Slow down central mail relay server but with domain exceptions

Written by - 0 comments

Published on - Listed in Mail Linux Internet


I recently picked up a task to create a new central mail relay server in order to replace an existing relay system running on Ironport appliances. I decided to go with a setup of two Ubuntu 16.04 Xenial servers, using a VRRP-VIP for high availability and run Postfix as mail daemon.

Fun fact: That's kind of the opposite of what I had to do back in August 2011 (see Spam comparison: Ironport vs. Open Source solution), but that was for incoming and not for outgoing mails.

As this central mail relay sends a lot of mails for all internal servers, it's important that it does not get on a black list. And if it does, I need to be informed immediately and I need to keep the numbers of sent spam mails as low as possible.

In order to achieve that, I  decided to use throttling/rate limiting to send outgoing mails in a "controlled" way, so Postfix wouldn't just flush thousands of mails in a hurry.
This is what I added into /etc/postfix/main.cf:

# Throttling/Rate limiting
smtp_destination_concurrency_limit = 2
smtp_destination_rate_delay = 1s
smtp_extra_recipient_limit = 10

smtp_destination_concurrency_limit: As per the Postfix documentation: "The maximal number of parallel deliveries to the same destination via the smtp message delivery transport." Example: If your mail server sends mails to several gmail.com recipients, Postfix will only deliver two mails at the same time. The default is 20. This could also be set with default_destination_concurrency_limit.
This setting is particularly helpful in case a spammer bombards a certain domain. Often the recipient mail server then refuses the sent mails (your real mails as well) with a 421, 450 or 451 SMTP response that you're sending too many mails too quickly.

smtp_destination_rate_delay: Postfix doc says "The default amount of delay that is inserted between individual deliveries over the same message delivery transport, regardless of destination". In the setting above, I added a "wait time" of 1 second before the next e-mail should be delivered. The default is "0s" which means no delay between sending mails.
This setting slows down the sending a lot, although 1 second doesn't seem like a high value.

smtp_extra_recipient_limit: Again the doc: "This extra recipient space is reserved for the cases when the Postfix queue manager's scheduler preempts one message with another and suddenly needs some extra recipients slots for the chosen message in order to avoid performance degradation.". Understood? No, because for once the documentation doesn't describe it in plain English. A better explanation is this phrase: "Limit the number of recipients of each message. If a message had 20 recipients on the same domain, postfix will break it out to two different email messages instead of one." which comes from http://steam.io/2013/04/01/postfix-rate-limiting/.

This worked pretty well but once the system went live, I realized that too many mails queued up. As I mentioned before, this mail relay server is a central system for a lot of internal servers. Hence most of the e-mails are actually destined for internal employees (reports, statistics, infos, cronjobs, etc). Instead of piling these mails up in the queue, they can and should be delivered asap/without going through the throttling.

I decided to use transport maps to solve this. In /etc/postfix/main.cf I added the transport_maps parameter and defined where to find the (hashed) map:

# Use transport maps for special domain settings
transport_maps = hash:/etc/postfix/transport

In the transport file (/etc/postfix/transport) I defined the destination domains:

# cat /etc/postfix/transport
mycompany.ch fast:[external.relay.server]
internal.ch  fast:[external.relay.server]

Which means that every mail with a recipient address @mycompany.ch or @internal.ch will be sent through the "fast" Postfix service to the external relay server (external.relay.server). 

In order to create the hashed transport map, it needs to be created with postmap:

postmap /etc/postfix/transport

The "fast" service doesn't exist yet, so this needs to be created in /etc/postfix/master.cf:

# ==========================================================================
# service type  private unpriv  chroot  wakeup  maxproc command + args
#               (yes)   (yes)   (no)    (never) (100)
# ==========================================================================
[...]
# Special fast mail delivery for certain domains (specified in transport map)
fast      unix  -       -       n       -       -       smtp
        -o smtp_fallback_relay=

This tells Postfix to create a new service called fast. Additionally I added smtp_fallback_relay without a value. If the defined mail relay (external.relay.server) is unavailable, Postfix will attempt to send the mails directly via its own Internet connection.

In order to tell Postfix to use different throttling settings for this "fast" service, the following additional parameters were defined in /etc/postfix/main.cf:

# Faster rates for internal domains (specified in transport map)
fast_destination_concurrency_limit = 50
fast_destination_rate_delay = 0s
fast_extra_recipient_limit = 100

The fast_ prefix means that these are parameters for the "fast" transport service (compared to the smtp transport, which exists by default). As you can see, the values are much higher, letting through a lot of mails at the same time.

At the end to activate the config changes, a restart (not reload, because of the change in master.cf) of Postfix is required:

service postfix restart

Within a couple of minutes the mail queue went down from ~700 mails to 0, due to the amount of mails destined for internal domains/employees.

To sum it up: All e-mails which are sent to external domains (like hotmail.com, gmail.com, etc) are going through the slow throttling of this relay system. Yet when the destination is one of the defined internal domains, the mails are sent immediately and with a much higher rate.


Add a comment

Show form to leave a comment

Comments (newest first)

No comments yet.

RSS feed

Blog Tags:

  AWS   Android   Ansible   Apache   Apple   Atlassian   BSD   Backup   Bash   Bluecoat   CMS   Chef   Cloud   Coding   Consul   Containers   CouchDB   DB   DNS   Database   Databases   Docker   ELK   Elasticsearch   Filebeat   FreeBSD   Galera   Git   GlusterFS   Grafana   Graphics   HAProxy   HTML   Hacks   Hardware   Icinga   Influx   Internet   Java   KVM   Kibana   Kodi   Kubernetes   LVM   LXC   Linux   Logstash   Mac   Macintosh   Mail   MariaDB   Minio   MongoDB   Monitoring   Multimedia   MySQL   NFS   Nagios   Network   Nginx   OSSEC   OTRS   Office   OpenSearch   PGSQL   PHP   Perl   Personal   PostgreSQL   Postgres   PowerDNS   Proxmox   Proxy   Python   Rancher   Rant   Redis   Roundcube   SSL   Samba   Seafile   Security   Shell   SmartOS   Solaris   Surveillance   Systemd   TLS   Tomcat   Ubuntu   Unix   VMWare   VMware   Varnish   Virtualization   Windows   Wireless   Wordpress   Wyse   ZFS   Zoneminder