So, you're a hobbyist or maybe even a user in a small-scale business capacity and you have some kind of headless Linux (or other *nix) box, maybe it's a VPS or a Raspberry Pi, and you want it to be able to email you with alerts (setting up monitoring is a separate subject!)
I went round in circles with this for a while, because it seemed like such a basic thing, I felt like there should be a one-click solution.
There kind of is, and it's called ssmtp
, or maybe a more recent fork called
msmtp
? Unfortunately this one seems to be too simple.
I was already familiar with Postfix from running mail server farms so I was shying away from that because it felt heavyweight. But then again, it's 2019, and even a Raspi has more RAM than the massive servers we used to run Postfix on back then. So it's not a big deal. Postfix does potentially have a huge feature list, but you can keep it simple.
My starting point for these notes was this great guide from Linode.
- Uninstall all other MTAs and install Postfix.
- Configure it to send everything out through a SASL-authenticated smarthost.
- Forward root mail to a user account.
- Use a personal
.forward
file to forward mail for that account to a "real" email address.
I'm going to speaking in Debianese, which will also apply to Ubuntu and Raspbian and many others. The only big difference if you're on CentOS or any other Linux is working out exactly which package names you need to install, and maybe the exact paths for files. But the main ideas should be the same.
This guide is based on the idea that your local MTA is going to forward everything except local mail to an external "relay host", aka a "smart host", for onward delivery, rather than trying to deliver things itself.
The cheapest and easiest option, if you have a GMail account, is to use Google's authenticated SMTP service. There's a note below about how to set up an app password.
If you have anything else you'd rather use, you'll need to have the credentials to hand. For example, I have an account with Mailgun and they provide a smart SMTP relay I can use. I can strongly recommend Mailgun as a hobbyist option if you have a domain you'd like to handle mail for. They have a free tier which can handle up to 10,000 emails per month and great online tools that make it very easy to set up your domain, as long as you're basically comfortable with editing DNS records on your domains. Obviously using a service like Mailgun is more work that just using GMail, but if you're already using Mailgun to handle your incoming mail, why not take advantage of the outbound service too?
I'll just throw in a note about running your own full MTA to handle incoming and outgoing mail. Postfix after all is a five-star, full-featured MTA. Mailgun probably use it internally. If you want to have a go, please do. It's great way to learn how email works at a low level. The reason I'm not going that route is (1) My main requirement is for my mail to be rock solid reliable with a minimum of intervention on my part. A trusted provider like Mailgun can just get on with it. (2) I've done it before, at scale, and now I'm happy to have someone else do it for me.
So if you're going to use GMail, you'll need an "app password", which is like a one-off password you can save on the server to avoid having your main account password sitting around in config files.
Pop over to your Google account App passwords page (or navigate there yourself if you don't trust my link) and create a new app password. For the app, select "Other", and call it "Postfix on Ulthar" or words to that effect. Copy the app password. Leave it up on screen untill you're ready to use it, just in case. It's not necessary or even wise to back it up anywhere else. If you lose it, you can always generate another.
Your system may have come with an MTA preinstalled, and it was probably Exim? so to be safe, let's start by getting our system up to date and getting rid of any MTAs that aren't Postfix:
sudo apt update -y && sudo apt upgrade -y
sudo apt remove exim4 sendmail ssmtp msmtp
Now we'll install the bits we need:
sudo apt install postfix libsasl2-modules mailutils alpine -y
This MIGHT open up the package configurator for Postfix, which will ask a bunch of questions. You can find the answers below.
Either way, you DO need to run the configurator (again, or for the first time). Running it by hand will ask you more questions than if it ran automatically.
sudo dpkg-reconfigure postfix
-
The server type is Internet with smarthost
-
System mail name is a FQDN including the name of this host. So if your server is called
ulthar
and your domain name isexample.com
, you putulthar.example.com
. If you don't have a domain name, then just leave this as the unqualified hostname (ulthar
). -
Relay host is
[smtp.gmail.com]:587
. This is important! the :587 forces it to use TLS, and needs to correspond to the SASL config we'll be doing in a minute. *If you're using a different relay service, put the MX name they tell you here, e.g.[smtp.eu.mailgun.org]:587
. -
"Root and postmaster mail recipient" should be the name of your normal local user, e.g.
mavis
. -
"Domains for which this machine id the final destination":
ulthar.example.com, localhost.example.com, localhost
-
"Force synchronous updates": No.
-
"Local networks" (the default should be fine):
127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
-
"Mailbox sixe limit": 0. This is maybe marginally dangerous?
-
"Local address extension character":
+
. -
"Internet protocols": All.
Phew!
You should have an app password (or other credentials if you aren't using GMail) ready to go.
Now lets create our SASL password file:
sudo vi /etc/postfix/sasl/sasl_passwd
This should have one line in it, like:
[smtp.gmail.com]:587 [email protected]:abcdefghijklmnop
Note the :587 corresponding to the smarthost name you configured before!
[email protected]
should be your Google account username, or the username
for your smart relay.
abcdefghijklmnop
should be the app password you made just before, or the
password for your smart relay.
Once you've saved this file you can close the app password in the browser.
Lastly, we need to "bake" this password file for Postfix, which we do by running
sudo postmap /etc/postfix/sasl/sasl_passwd
This creates a file called /etc/postfix/sasl/sasl_passwd.db
, which is a
high-speed format for Postfix.
If you ever change the sasl_passwd
file, you'l
need to re-run that postmap
command.
Now we'll set up Postfix to use the SASL passwd we just made.
vi /etc/postfix/main.cf
Add these lines to the end:
smtp_sasl_auth_enable = yes
smtp_use_tls = yes
smtp_sasl_security_options = noanonymous
smtp_sasl_password_maps = hash:/etc/postfix/sasl/sasl_passwd
smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt
Lastly (for this bit) we'll restart Postfix so that all takes effect:
sudo systemctl restart postfix.service
For this next bit we're not going to use sudo
! This is all normal-account
stuff.
vi ~/.forward
This file contains a space-separated list of places to forward your mail to, e.g.
mavis [email protected]
This config means that I keep a copy locally (mavis
) because it's not recursive!
And also a copy gets sent to my real email address.
Some forwarding agents will reject mail if the sender doesn't have a FQDN (Gandi and Pobox do this).
Some system mail, like the mails from unattended-upgrade
will have a bare username as the sender, so they will fail to get forwarded.
There are a few things you can do:
- You can configure
mail
andmailx
to append a domain to the username or even just use a hardcoded address, but that's fraught because if a process manually sets the sender this will be ignored.unattended-upgrade
does this and it was driving me potty that my mailutils config was being ignored. - You can configure
unattended-upgrade
to use a specific sender address - but that won't fix the general case (and it feels weird for the apt updater to know about actual email addresses.) - You can get Postfix to append the domain.
3. is not something you'd want to do on a real public mail server, because as the Postfix config says, "appending .domain is the MUA's job" (Postfix is an MTA). However in this situation it seems smart. It's a catch-all solution, and it keeps email-related info inside the email system.
To do this, edit etc/postfix/main.cf
and set:
append_dot_mydomain = yes
You absolutely do not want your email server being used by anyone outside the box it's on, so make sure to block port 25 at every level. First, tell postfix to only listen on loopback:
vi /etc/postfix/main.cf
Find the line that says inet_interfaces = all
and change it to:
inet_interfaces = loopback-only
Save and restart postfix.
You can check that's only listening local with
sudo netstat -tunlp|grep :25
Now check your ufw
firewall:
sudo ufw status
It's probably allowing 25.
sudo ufw delete allow 25
(You could sudo ufw deny 25
but ufw is default-deny so it's simpler and therefore better to just delete the allow rule.)
Lastly check your hosting provider and make sure you're not allowing port 25 through the hosting-level firewall.
A handy command to fire off an email to root
is:
date; date| mail root -s "$(date)"
I like this one because if you're doing a bit of debugging, each test message will have a clearly diffent subject and body, and you can see off the command line what the last one was.
If things don't go perfectly, you can check /var/log/mail.log
to see what
went wrong. I sometimes leave
sudo tail -f /var/log/mail.log
open in a tmux pane.
You can check your local mail with
alpine
This will help you confirm that mail is getting copied to local; or if remote delivery is the problem, you can confirm that mail is going through the system at all.
When I did this on Ubuntu 19.04, it completely ignored the "deliver root mail
to" option and didn't populate the /etc/aliases
so I had to go and do that by
hand.
We didn't touch on the /etc/aliases
file here because the Postfix configurator
should have set it up for us, and we are using a local .forward
file to
send email external.
/etc/aliases
is a sendmail-compatible (i.e. venerable unix tradition) file
which can be used to set up redirection for local mail. The way the configurator
left it, all the special local accounts like "postmaster" get forwarded to
root
, and root
gets forwarded to mavis
. This seems like a sensible,
system-level configuration. We then use mavis's .forward
to nominate a real
address to send everything to.
HOWEVER. You could use /etc/aliases
to do all the forwarding, or set up more
complex rules. If you have a look in there (using sudo vi /etc/aliases
) you'll
see the line root: mavis
. We COULD add another line, mavis: mavis [email protected]
. This would have exactly the same effect as giving mavis her
own .forward
but with the difference that she wouldn't be able to edit it with
out sudo
.
It's a subtle difference and honestly for a single-user hobbyist box there's not
much in it, but it feels nicer to me to use the .forward
.
General Postfix documentation.
I found the man page on local delivery very helpful.
If you want to use /etc/aliases
directly or need to fix it, you'll want the
man page on aliases.
By default, the mail
and mailx
commands will send as user@host
, e.g. root@celephais
. Some SMTP servers will (reasonably, I guess) reject that as not being a real email address. To fix this you need to get those commands to an actual domain:
/etc/mailutils.conf
program mail {
address {
# Set the current user email address (default is loginname@defaultdomain).
#email-addr [email protected];
# Set e-mail domain for unqualified user names (default is this host)
email-domain lumphammer.net;
};
}
program mailx {
address {
# Set the current user email address (default is loginname@defaultdomain).
#email-addr [email protected];
# Set e-mail domain for unqualified user names (default is this host)
email-domain celephais.lumphammer.net;
};
}
The secret is that mail
and mailx
both have to be configured!! For ages I only had the first one and it wasn't working for mailx
.
Some relay hosts will not relay email for domains that don't exist, like myraspberrypi.mydomain.net
. To fix this, you need to add the following to /etc/postfix/main.cf
:
masquerade_domain = mydomain.net
This domain needs to be the parent domain of your hostname.
The Postfix configurator asks you which user to deliver mail to. I found that on one occasion this wasn't being honoured. The solution is:
sudo vi /etc/aliases
Add:
root: ndc
And then run:
sudo newaliases
If you have unattended-upgrade
set up, it actually sets its own sender address so your mailutils work will have no effect. Worse, it's an undocumented config line, so you need to add
Unattended-Upgrade::Sender "[email protected]";
in /etc/apt/apt.conf.d/50unattended-upgrades
to make it work.