Local mail relay with Postfix

Postfix it's powerful fast and easy mail server that can be configured as local mail relay service to provide guaranteed mail delivery.

For this example I will use Postfix 2.6.6 that running on CentOS 6.8 but I had also tested it on Postfix 2.11.8. However I sure that the configuration that show below will working fine with any Postfix 2.x.x on any Linux distro.

Installation

The installation process is pretty simple

yum install epel-release  
yum install postfix  

Configuration

For the start lets make base relay configuration. In this example I will expect that my relay was accept only local connections.

cat << EOF > /etc/postfix/main.cf  
smtpd_banner = $myhostname ESMTP $mail_name  
biff = no  
append_dot_mydomain = no  
mynetworks = /etc/postfix/mynetworks  
recipient_delimiter = +  
inet_interfaces = 127.0.0.1  
mail_owner = postfix  
queue_directory = /var/spool/postfix  
data_directory = /var/lib/postfix  
bounce_queue_lifetime = 12h  
smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination  
smtpd_relay_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination  
EOF  

As you can see we are turn of local biff service because we configure relay and does not wish to send any notifications.

Then we need to configure our trusted networks.

As I write above -- I will accept inbound mails only from my localhost, so I need to define loopback network.

cat << EOF > /etc/postfix/mynetworks  
127.0.0.0/8  
EOF  

The next step is configure our master file and define basic transports.

cat << EOF > /etc/postfix/master.cf  
smtp      inet  n       -       n       -       -       smtpd  
pickup    fifo  n       -       n       60      1       pickup  
cleanup   unix  n       -       n       -       0       cleanup  
qmgr      fifo  n       -       n       300     1       qmgr  
tlsmgr    unix  -       -       n       1000?   1       tlsmgr  
rewrite   unix  -       -       n       -       -       trivial-rewrite  
bounce    unix  -       -       n       -       0       bounce  
defer     unix  -       -       n       -       0       bounce  
trace     unix  -       -       n       -       0       bounce  
verify    unix  -       -       n       -       1       verify  
flush     unix  n       -       n       1000?   0       flush  
proxymap  unix  -       -       n       -       -       proxymap  
proxywrite unix -       -       n       -       1       proxymap  
smtp      unix  -       -       n       -       -       smtp  
relay     unix  -       -       n       -       -       smtp  
        -o smtp_fallback_relay=
showq     unix  n       -       n       -       -       showq  
error     unix  -       -       n       -       -       error  
retry     unix  -       -       n       -       -       error  
discard   unix  -       -       n       -       -       discard  
local     unix  -       n       n       -       -       local  
virtual   unix  -       n       n       -       -       virtual  
lmtp      unix  -       -       n       -       -       lmtp  
anvil     unix  -       -       n       -       1       anvil  
scache    unix  -       -       n       -       1       scache  
EOF  

That is all. With this configuration you will got local mail relay service but with few restrictions:

  • yours relay service will unsecured -- all messages will transport as plant text.
  • yours relay service will send outbound messages from first valid public IP address (interface).

That's not cool! Let's try to fix it!

Enable SSL support

cat << EOF >> /etc/postfix/main.cf  
smtpd_tls_auth_only = yes  
smtp_use_tls = yes  
smtpd_use_tls = yes  
smtp_tls_note_starttls_offer = yes  
smtpd_tls_key_file = /etc/postfix/ssl/smtpd.key  
smtpd_tls_cert_file = /etc/postfix/ssl/smtpd.crt  
smtpd_tls_CAfile = /etc/postfix/ssl/cacert.pem  
smtpd_tls_CApath = /etc/pki/tls/certs  
smtpd_tls_loglevel = 1 # be more verbose  
smtpd_tls_received_header = yes  
smtpd_tls_session_cache_timeout = 3600s  
EOF  

Do not forget to got valid key-cert files in right locations!

Add custom transport

Supposing my server have two different interfaces with public IP addresses:

  • eth0: inet 81.140.82.100/24
  • eth1: inet 92.130.195.200/24

I need to send outbound messages from second interface with IP 92.130.195.200 so lets configure some additional transport for that in master.cf file.

cat << EOF >> /etc/postfix/master.cf  
out_default       unix -       -       n       -       -       smtp  
-o smtp_bind_address=92.130.195.200
-o smtp_helo_name=relay.zombig.name
-o syslog_name=relay-zombig-name
EOF  
service postfix restart  

Besides that you need to define default transport.

cat << EOF > /etc/postfix/transport_maps  
* out_default:
EOF  
postmap hash:/etc/postfix/transport_maps  
cat << EOF >> /etc/postfix/main.cf  
transport_maps = hash:/etc/postfix/transport_maps  
EOF  
service postfix restart  

Now all yours emails will be outgoing via out_default transport with public address 92.130.195.200.

Sender depended transports

In some cases you will need to use different public IPs per senders domain.

Create transport map.

cat << EOF > /etc/postfix/sender_dependet_transpors  
@zombig.name zombig_name
EOF  
postmap hash:/etc/postfix/sender_dependet_transpors  
cat << EOF >> /etc/postfix/main.cf  
sender_dependent_default_transport_maps = hash:/etc/postfix/sender_transport_maps  
EOF  

And define it into main.cf file.

cat << EOF >> /etc/postfix/master.cf  
zombig_name       unix -       -       n       -       -       smtp  
-o smtp_bind_address=81.140.82.100
-o smtp_helo_name=relay.zombig.name
-o syslog_name=relay-zombig-name
EOF  
service postfix restart  

Enable rate limiting

Also you can specify some rate limits per destination.

First step is specify transport for this destination. In my example I will enable rate limits for qq.com.

cat << EOF >> /etc/postfix/master.cf  
qq_com_limit       unix -       -       n       -       -       smtp  
EOF  

Then create transport map for this domain.

cat << EOF >> /etc/postfix/transport_maps  
qq.com qq_com_limit:  
EOF  
postmap hash:/etc/postfix/transport_maps  

And enable limits for this transport.

cat << EOF >> /etc/postfix/main.cf  
qq_com_limit_destination_concurrency_limit = 2  
qq_com_limit_destination_rate_delay = 10s  
qq_com_limit_destination_recipient_limit = 3  
EOF  
service postfix restart  

However you can specify default rate limits that will be using for all destinations except named (e.g. qq.com).

cat << EOF >> /etc/postfix/main.cf  
default_destination_concurrency_limit = 20  
default_destination_rate_delay = 1  
default_extra_recipient_limit = 50  
initial_destination_concurrency = 3  
EOF  
service postfix restart  

Enable header checks

In some cases, you might need to rewrite some information in message headers (e.g. to hide some critical IPs).

Supposing we have some SSO login service named sso-api-01.zombig.name, that send password recovery messages but we want to hide it IP address.

So we need create header checks file with follow rules.

cat << EOF > /etc/postfix/header_checks  
# Our clients must specify realy FQDN names. Ignore if not!
/.*localhost.*/ IGNORE
# Hide our SSO real IP address
/^(Received: from) sso-api-[\d\.\w]+ \([\w\-\.\d]+ \[[\d\.]+\]\)(.*)$/ REPLACE ${1} login.zombig.name (unknown [unknown]) ${2}
EOF  
cat << EOF >> /etc/postfix/main.cf  
header_checks = pcre:/etc/postfix/header_checks  
EOF  
service postfix restart  

Enable selective debugging

Selective debugging can help to troubleshot some problems with delivery via some destinations (domains).

Create target peers list and set debug level for it.

cat << EOF > /etc/postfix/debug_peer_list  
qq.com  
EOF  
cat << EOF >> /etc/postfix/main.cf  
debug_peer_level = 2  
debug_peer_list = /etc/postfix/debug_peer_list  
EOF  
service postfix restart  

Tests

You can test how relay works with mail utility. Install it and try to send some mail.

yum install mailx  
echo "This is test mail. Please ignore it. If you got this message then you relay server works fine!" | mail -s 'Relay Service Test message' -r testing@zombig.name  

Additional

  • view messages in que: mailq -bp
  • delete all deferred messages: postsuper -d ALL deferred
  • delete specified messages:
    • mailq -bp | grep 'Connection refused' -B1 | grep -E '^[0-9A-Z]' | cut -d' ' -f1 | postsuper -d -
    • mailq -bp | grep 'Connection timed out' -B1 | grep -E '^[0-9A-Z]' | cut -d' ' -f1 | postsuper -d -

Statistics and analysis

To got some statistic you can use Postfix Perl Scripts package.

yum install postfix-perl-scripts  
pflogsumm /var/log/maillog  

Enable remote asscess

If you wish to provide remote access to your relay server you will need to add remote server into mynetworks file and enable listener on some public interface.

[ ! ] Note: that addition new ip address to mynetworks can lead to security risks!


See more