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
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:
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
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.