How to Route Wildcard Emails to a Script in Postfix for Dynamic Alias Handling


4 views

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.