Setting up Postfix as SMTP Client for Outgoing Automatic Mail Notifications

Say you want to get an e-mail notification when something goes wrong, or when some task finishes.

The alert category should actually be covered by some monitoring system like Prometheus or LibreNMS. But even then, the monitoring system itself needs to send e-mail notifications.

You may be tempted to use a simple tool like S-nail to send automated e-mails over an SMTP server. The trouble is, if the Internet connection goes down, the computer temporarily loses network connectivity, or the operating system decides to update itself and reboot, your notification e-mails can get lost. Some software may possibly retry, but the majority won't, or will not retry long enough.

The proper solution is to install a Mail Transfer Agent (MTA) that queues outgoing e-mails on disk and keeps retrying for a long time. Then any software can send mail with a local command-line tool like 'GNU mail', a POSIX 'mailx' utility, 'sendmail', or even a fully-featured application like 'Mutt'. Sending with a local tool is in fact rather common on Linux/Unix and does not actually require an SMTP server.

You would normally choose a small, simple server/daemon for this task. Examples are:


 * nullmailer
 * OpenSMTPD
 * msmtp together with some msmtpqueue add-on.

Unfortunately, I had no joy with them. If you actually succeeded with an alternative, please drop me a line.

So in the end, I turned to Postfix, which is a monster that has its own small service controller to orchestrate a number of subservices.

Your Linux distribution probably packages Postfix, so it is normally easy to install. The difficult part is to understand how it works, and to configure it.

This guide has been written for Ubuntu 20.04/Debian, but it should be easy to adapt to other Linux distributions.

On Ubuntu/Debian, you will be prompted for configuration after installing the 'postfix' package. If you missed it, you can always retrigger the configuration with command:

sudo dpkg-reconfigure postfix

The closest configuration to our needs is called:

Satellite system All mail is sent to another machine, called a 'smarthost', for delivery.

And now is when the fun begins.

The first thing to do is to locate the Postfix log, which tends to be at /var/log/mail.log. You want to keep watching the log with a command like this:

tail -f /var/log/mail.log

Any problems, including configuration warnings, will be output to that log.

Mail server folks consider themselves very important and unique, so that is why they named the main service/daemon "master". More humble individuals would have named it "postfix-small-systemd-clone", or something actually useful like "postfix-services-controller".

Mail server folks also believe that they know better, so Postfix automatically installs an SMTP service on your system. If you scan for listening sockets, you will see something like this:

$ sudo ss --listening --processes -A 'all,!unix,!netlink' tcp LISTEN  0  100  127.0.0.1:smtp  0.0.0.0:*  users:(("master",pid=1234,fd=13)) tcp LISTEN  0  100      [::1]:smtp     [::]:*  users:(("master",pid=1234,fd=14))

In the lines above, 'smtp' stands for TCP port 25, and 'master' is Postfix.

SMTP servers are relatively hard to secure, and completely useless in our scenario, so let's disable it. Edit configuration file /etc/postfix/master.cf and comment out a line like this:

smtp inet  n   -  y  -  -  smtpd

Then reload the configuration with a command like this:

sudo systemctl reload postfix

The listening sockets should be gone by now.

Mail server folks are fond of past times, so Postfix automatically installs a local mail service which nobody uses nowadays. In order to prevent services like 'cron' from filling up the disk with unread local mail notifications, it is best to disable it.

Edit configuration file /etc/postfix/main.cf and clear setting "mydestination", so that it looks like this:

mydestination =

After reloading the configuration, local mail delivery will stop. If you want, you can check that the local mailbox directory, usually at /var/mail, is empty or only has empty user mailbox files (0 bytes long).

Now it is time to configure the Postfix STMP client to relay all e-mails through an existing account on your ISP. This should get you going:

relayhost = [your-isp-smtp-server.example.com]:465 smtp_sasl_auth_enable = yes smtp_sasl_password_maps = static:some-existing-account-for-sending@example.com:your-password-here smtp_sasl_tls_security_options = noanonymous smtp_sender_dependent_authentication = no smtp_tls_wrappermode = yes smtp_tls_security_level = encrypt
 * 1) Required when using SMTPS wrappermode (TCP port 465):

The exact settings will depend on the kind of SMTP authentication that your ISP requires. Check out the full configuration file example below for more information on each configuration setting.

Do not forget to reload the Postfix configuration:

sudo systemctl reload postfix

Now you can test sending an e-mail:

echo "Test 1 body" | mail --subject="Test 1" your-email-address@example.com

There is one security risk with this setup: anybody who can read file /etc/postfix/main.cf has access to the password for that SMTP account. On many systems, this tends to be anybody with a local account on the computer. Furthermore, depending on the mail provider, you may be able to impersonate anybody xxx@example.com when sending through any one yyy@example.com SMTP account. If you are worried about this, create a separate password file with tighter access permissions. Configuration setting smtp_sasl_password_maps will then look like this: smtp_sasl_password_maps = hash:/some/file You will have to use tool postmap. There are plenty of guides about it on the Internet.

The last step is to set a proper sender address for such mails, in case they bounce, or your ISP's spam filter requires it:

sender_canonical_classes = envelope_sender, header_sender sender_canonical_maps = static:{ no-reply@example.com }

If you want to restrict the local user accounts who can submit mails, see configuration option 'authorized_submit_users'.

That's it. This is a full example of configuration file main.cf with more information on each configuration setting:

