When configuring Postfix with virtual aliases, many administrators encounter a situation where the catch-all address (@example.com
) unexpectedly captures all incoming emails instead of just handling undefined addresses. This happens despite having properly defined specific virtual aliases like info@example.com
or sales@example.com
.
Here's a typical setup that might cause this issue:
# /etc/postfix/main.cf
virtual_alias_domains = example.com
virtual_alias_maps = hash:/etc/postfix/virtual
# /etc/postfix/virtual
postmaster@example.com account1
info@example.com account1
sales@example.com account2
@example.com catchall
The problem stems from Postfix's matching order for virtual aliases. The catch-all pattern (@domain.com
) is actually matching all addresses, including those that should be handled by specific mappings. This occurs because:
- Postfix processes virtual aliases in the order they appear in the map
- The catch-all is matching before specific addresses are checked
- The domain might be listed in both
virtual_alias_domains
andmydestination
To fix this, we need to:
- Ensure the domain is only in
virtual_alias_domains
- Structure the virtual aliases file correctly
- Use proper mapping syntax
Here's the corrected configuration:
# /etc/postfix/main.cf
virtual_alias_domains = example.com, myotherdomain.com
virtual_alias_maps = hash:/etc/postfix/virtual
mydestination = $myhostname, localhost.$mydomain, localhost
# /etc/postfix/virtual
postmaster@example.com account1
info@example.com account1
sales@example.com account2
# Catch-all comes LAST after all specific addresses
@example.com catchall
The crucial aspect is the ordering in the virtual aliases file. Postfix processes entries from top to bottom, and the first match wins. Therefore:
- Specific addresses must appear before catch-all
- More specific patterns should come before less specific ones
- The catch-all should always be the last entry
After making these changes, test with:
postmap /etc/postfix/virtual
postfix reload
postmap -q info@example.com hash:/etc/postfix/virtual
For complex setups, consider separating specific aliases and catch-all:
# main.cf
virtual_alias_maps = hash:/etc/postfix/virtual, regexp:/etc/postfix/virtual_catchall
# /etc/postfix/virtual (specific aliases)
postmaster@example.com account1
info@example.com account1
# /etc/postfix/virtual_catchall (regex catch-all)
/^.*@example\.com$/ catchall
- Duplicate domain entries in
virtual_alias_domains
andmydestination
- Missing
postmap
command after changing virtual files - Incorrect file permissions on virtual aliases files
- Not restarting/reloading Postfix after changes
When troubleshooting, check:
postconf -n # Verify active configuration
postmap -q address mapfile # Test specific address mapping
tail -f /var/log/mail.log # Monitor delivery attempts
When implementing virtual aliases in Postfix 2.10.2 for multi-domain mail routing, a common pitfall occurs where catch-all mappings (@domain.com) unexpectedly override all other defined aliases. This behavior contradicts the expected precedence where specific addresses should take priority over wildcards.
Here's the problematic configuration example:
virtual_alias_domains = example.com
virtual_alias_maps = hash:/etc/postfix/virtual
# /etc/postfix/virtual contents:
postmaster@example.com account1
info@example.com account1
sales@example.com account2
@example.com catchall
The root cause lies in Postfix's mapping evaluation order. While the documentation suggests this pattern, it doesn't explicitly warn about the precedence behavior.
Solution 1: Proper Domain Declaration
First, ensure your domain isn't listed in both virtual_alias_domains and mydestination:
# Correct main.cf settings:
virtual_alias_domains = example.com, myotherdomain.com
mydestination = $myhostname, localhost.$mydomain, localhost
Solution 2: Reordered Virtual Maps
Postfix processes virtual maps sequentially. Place catch-alls after specific mappings:
# /etc/postfix/virtual should be:
postmaster@example.com account1
info@example.com account1
sales@example.com account2
# Catch-all comes LAST
@example.com catchall
Solution 3: Recipient Verification
Add verification to prevent catch-all from grabbing valid addresses:
smtpd_recipient_restrictions =
...
reject_unverified_recipient
permit_mynetworks
permit_sasl_authenticated
reject_unauth_destination
For complex setups, consider using separate map files with proper lookup order:
virtual_alias_maps =
hash:/etc/postfix/specific_aliases,
hash:/etc/postfix/catchall
Where specific_aliases contains all defined addresses and catchall contains only the wildcard mapping. This ensures proper evaluation precedence.
Use these commands to verify your configuration:
postmap /etc/postfix/virtual
postfix check
postconf -n
postmap -q "test@example.com" hash:/etc/postfix/virtual
Check mail logs for mapping evaluation:
tail -f /var/log/mail.log | grep virtual