How to Configure Postfix as a Mail Proxy with Domain-Based SMTP Routing


2 views

When building mail processing systems, we often need to route incoming emails differently based on recipient addresses. A common scenario involves having Postfix handle general mail delivery while forwarding specific domains/subdomains to specialized processors like Lamson (Python mail server). Here's how to implement this properly.

Internet → Postfix (port 25) → 
    ├──→ Lamson (port 10025) for special@domain.com
    └──→ Local delivery for others

Edit /etc/postfix/main.cf:

# Enable transport maps
transport_maps = hash:/etc/postfix/transport

# Lamson relay configuration
lamson_destination = localhost:10025

# Other standard Postfix settings
mydestination = $myhostname, localhost.$mydomain, localhost
relayhost =
inet_interfaces = all

Create /etc/postfix/transport:

# Format: pattern transport:destination
specialdomain.com  smtp:[127.0.0.1]:10025
.subdomain.org     smtp:[127.0.0.1]:10025
*                  :

Then compile the map:

postmap /etc/postfix/transport

Verify with Postfix's built-in checker:

postfix check
postmap -q "test@specialdomain.com" hash:/etc/postfix/transport

Basic Lamson server setup (server.py):

import lamson.server

class BasicReceiver(lamson.handlers.Base):
    def handle(self, message):
        print("Received message to:", message['to'])

if __name__ == "__main__":
    lamson.server.run(
        receiver=BasicReceiver(),
        host='localhost',
        port=10025
    )

For more complex routing, use pcre transport maps:

# In main.cf
transport_maps = pcre:/etc/postfix/transport_pcre

Sample PCRE map:

/^user-\d+@special\.com$/  smtp:[127.0.0.1]:10025
/^.*@marketing\.com$/      smtp:[192.168.1.100]:25

For high-volume systems:

# In main.cf
default_process_limit = 100
smtpd_client_connection_count_limit = 20
smtpd_client_connection_rate_limit = 30

Use these commands to monitor mail flow:

tail -f /var/log/mail.log
postqueue -p  # View mail queue
postsuper -d ALL  # Flush queue in emergencies

Essential security settings for the proxy:

smtpd_delay_reject = yes
smtpd_helo_required = yes
smtpd_sender_restrictions = reject_unknown_sender_domain
smtpd_recipient_restrictions = permit_mynetworks, reject_unauth_destination

When building mail processing systems, we often need to route incoming emails to different handlers based on destination addresses. In this case, we want to:

  • Use Postfix as the primary MTA listening on port 25
  • Proxy specific emails to Lamson (listening on port 10025)
  • Process remaining emails normally through Postfix

The solution involves using Postfix's transport_maps feature to create routing rules. Here's the step-by-step approach:

# /etc/postfix/main.cf
transport_maps = hash:/etc/postfix/transport
local_recipient_maps =

Define which domains or addresses should be proxied to Lamson:

# /etc/postfix/transport
lamson.example.com   smtp:[127.0.0.1]:10025
.example.com         smtp:[127.0.0.1]:10025
*                    :

Ensure Postfix can communicate with Lamson by adding this to your master.cf:

127.0.0.1:10025 inet n  -       n       -       -      smtpd
  -o smtpd_authorized_xforward_hosts=127.0.0.0/8
  -o smtpd_client_restrictions=
  -o smtpd_recipient_restrictions=permit_mynetworks,reject

After making changes, remember to:

postmap /etc/postfix/transport
postfix reload

Test the routing by sending emails to both Lamson-handled addresses and regular addresses while monitoring mail logs.

For more complex routing, consider using check_recipient_access with regular expressions:

smtpd_recipient_restrictions =
    check_recipient_access regexp:/etc/postfix/recipient_access
    ...other restrictions...

# /etc/postfix/recipient_access
/^user-.*@lamson\.example$/ FILTER smtp:[127.0.0.1]:10025

Implement proper error handling for cases when Lamson is unavailable:

# /etc/postfix/main.cf
lamson_destination_recipient_limit = 1
lamson_transport_retry_time = 60s