When building email anonymization systems like Craigslist's dynamic aliases, you need Postfix to handle wildcard email addresses (e.g., user-*@example.com) and pipe them to processing scripts. Here's how to implement this properly:
First, ensure your main.cf contains these critical settings:
virtual_alias_maps = hash:/etc/postfix/virtual virtual_alias_domains = example.com default_transport = smtp
Edit /etc/postfix/virtual with the following pattern:
user-@example.com scriptuser
Then run:
postmap /etc/postfix/virtual postfix reload
Add to /etc/postfix/transport:
example.com script:
Then create /etc/postfix/master.cf entry:
script unix - n n - - pipe flags=F user=scriptuser argv=/path/to/script.sh ${sender} ${recipient}
Here's a basic Bash script (script.sh) to handle incoming emails:
#!/bin/bash sender="$1" recipient="$2" # Extract user ID from email address user_id=$(echo "$recipient" | sed 's/user-$[^@]*$@.*/\1/') # Process the email content while IFS= read -r line; do # Your processing logic here echo "$line" >> "/var/mail/processed/${user_id}.eml" done exit 0
For more complex routing, consider using regex tables in Postfix:
virtual_alias_maps = pcre:/etc/postfix/virtual_regexp
With /etc/postfix/virtual_regexp containing:
/^user-[0-9]+@example\.com$/ scriptuser
Always ensure:
- The script user has minimal privileges
- Email content is properly sanitized
- Script execution time is monitored
- Mailbox permissions are correctly set
Use these commands to verify your setup:
postmap -q "user-1234@example.com" hash:/etc/postfix/virtual postconf virtual_alias_maps tail -f /var/log/mail.log
When building systems that require dynamic email handling (like Craigslist-style anonymization), Postfix's pipe functionality becomes essential. The core challenge is intercepting all emails sent to a pattern like user-*@example.com and redirecting them to a processing script without traditional mailbox delivery.
The most reliable approach uses Postfix's virtual alias maps with regex support. First, enable regex in your main.cf:
# /etc/postfix/main.cf virtual_alias_maps = regexp:/etc/postfix/virtual_regexp
Then create the regex mapping file:
# /etc/postfix/virtual_regexp /^user\-[0-9]+@example\.com$/ scriptpipe
Define a custom transport in master.cf that pipes emails to your script:
# /etc/postfix/master.cf scriptpipe unix - n n - - pipe flags=FR user=scriptuser argv=/path/to/script.py ${sender} ${recipient}
The script (script.py in this example) should handle stdin for the email content and the passed arguments for metadata.
Here's a basic Python script template to process incoming emails:
#!/usr/bin/env python3 import sys import email from email import policy sender = sys.argv[1] recipient = sys.argv[2] msg = email.message_from_file(sys.stdin, policy=policy.default) subject = msg['subject'] body = msg.get_body(preferencelist=('plain',)).get_content() # Process the email (example: extract user ID from recipient) user_id = recipient.split('@')[0].split('-')[1] print(f"Processing email for user {user_id}", file=sys.stderr) # Your custom logic here...
Permission problems: Ensure your script is executable (chmod +x) and the Postfix user can access it. Test with:
sudo -u postfix /path/to/script.py test@example.com user-1234@example.com < test_email.txt
Regex not matching: Verify your pattern with postmap:
postmap -q "user-1234@example.com" regexp:/etc/postfix/virtual_regexp
Consider adding these to main.cf for production systems:
# Prevent mail bombs anvil_rate_time_unit = 60s smtpd_client_message_rate_limit = 100
For security, run your script under a dedicated user with minimal privileges, and sanitize all inputs.