There are a bunch of things on Linux that send emails by default (for example, the output of Cron jobs). Being a Linux noob I wanted to ensure I received these emails (what if something goes bad because of my noobness?) and also wanted to ensure my Raspberry Pi can send emails to me from scripts if required in the future.

There are a lot of tutorials online about how to do this most of which require hard-coding your email account password on your Pi. I’m not ready for this sort of commitment (even if it’s an App-Specific password) and knowing a little about SMTP I was fairly sure it wasn’t required if I was only deliverying mail to one place.

So, the things we need to do are:

  1. Set up all mail to be passed on to the same local account (in my case danny)
  2. Set up that accounts mail to forward to an external address (a real email address, mine being hosted by Google)
  3. Install and configure an MTA that can actually connect to the external SMTP server and deliver the email

All of these seemed pretty straight forward, until I actually came to try… It turns out that if you’re deliverying email to Google and your ISP supports IPv6 (mine does) and you don’t want to disable IPv6 (I do not) then you will find yourself receiving errors like this:

Our system has detected that this message does not meet IPv6 sending guidelines regarding PTR records and authentication. Please review https://support.google.com/mail/?p=ipv6_authentication_error for more information.

For some reason Google have added some extra restrictions on being able to talk to their SMTP servers over IPv6, some of which you likely can’t solve (because the IP address is owned by your ISP and not you). It’s not just me that thinks this sucks.

So, we have an additional requirement:

  • Our MTA must be able to deliver only over IPv4, despite IPv6 being set up and configured

I set about testing a whole bunch of MTAs and I failed at gtting almost all of them working (mostly because of this IPv6 issue). Possibly this is because of lack of experience for Linux but whatever the reason, I needed something I could make work! Eventually I got PostFix working (or at least, I thought I did… keep reading!).

The first thing I do when setting up a new Raspberry Pi is ensure everything is up-to-date. If your Raspbian image is quite old there might be many updates for you to install. This might take a little while:

# Update the package list, update all packages and remove any packages that are no longer required
sudo apt-get update -y && sudo apt-get dist-upgrade -y && sudo apt-get autoremove -y

Next we need to install and configure Postfix. When you install this it will automatically open a config utility (I don’t think it should, because of -y but it does…). Just select No Config and OK since we’re going to write the entire config file ourselves.

sudo apt-get install postfix -y

Now to write the Postfix config file. We need to set a couple of things; descriptions are inline in comments:

sudo tee /etc/postfix/main.cf > /dev/null <<EOF

# Where to read account aliases, used to map all emails onto one account
# and then on to a real email address
alias_maps = hash:/etc/aliases

# This sets the hostname, which will be used for outgoing email
myhostname = pi.dantup.com

# This is the mailserver to connect to deliver email
# NOTE: This must be the MX server for the account you wish to deliver email to
# or an open relay (but you hopefully won't find one of them). In my case, this
# is Google's first MX server (which can be found by doing an MX lookup on my domain).
relayhost = aspmx.l.google.com

# Which interfaces to listen on. We don't want anyone connected to our Pi to send email,
# so we set this to the local loopback interface only.
inet_interfaces = loopback-only

# This one is important for the reasons mentioned above. This means only IPv4 will be used,
# avoiding the IPv6 restrictions Google have in place.
inet_protocols = ipv4

EOF

Now we need to create the aliases file referenced above. We simply map root mail on to our main user (danny) and then that user on to the required email address.

# Set the aliases
echo "root: danny" | sudo tee -a /etc/aliases
echo "danny: danny+pi@notreallymydomain.com" | sudo tee -a /etc/aliases

# Rebuild alias db and restart Postfix
sudo newaliases
sudo /etc/init.d/postfix start

And that’s that. Simples! Next we need to send a test email to ensure everything is working. We send this to a local account (not a full email address) to ensure we’re testing the whole thing.

echo -e "FROM: root\nTO: root\nSubject: Test email from the Raspberry Pi\n\nThis is a test email sent from your Raspberry Pi" | sendmail -t
echo -e "\e[33mTest email sent. Make sure it turns up :)\e[0m"

If you’ve done everything right and Google (or your mailhost) don’t suspect you of being a spammer (which is possible if you’re connecting from a domestic IP address, but so far I’ve had no issues) you should have an email in your mailbox. For extra profit, add the sender to your address book and add a nice profile picture :)

Email from Raspberry Pi

For extra points (and to reduce the chance of being labelled a spammer), you probably want to set up SPF records for your home IP address. If this changes a lot, you could use a dynamic DNS service. For example, my SPF record looks like this:

v=spf1 include:_spf.google.com a:home.dantup.com ~all

This will allow Google and the IP that home.dantup.com resolves to to send mail and it be considered an SPF pass.

Not so fast…

At this point I thought everything was dandy… Until I rebooted! If you’re using Raspbian Jessie (but not Raspbian Jessie Lite) you’ll find that after a reboot that your email is broken. This reason for this is that Raspbian Jessie defaults to a Fast Boot mode where it does not wait for the network during booting. Postfixes creates a chroot jail and copies /etc/resolv.conf into it at startup, but in fast boot mode this is too early and it ends up blank. This means Postfix is unable to resolve DNS and no emails get sent!

It took me several days to track down what was happening here but the fix is as simple as running sudo raspi-config and selecting Slow Boot, or running the following command:

sudo raspi-config nonint do_wait_for_network Slow

This will create a script that runs at startup which blocks until DHCP completes before allowing other services (like Postfix) to start up. I posted my frustration with this default on GitHub and was informed that neither way was great, because Slow Boot would wait for a DHCP timeout (which could be quite long) if a Pi booted and wasn’t connected to the network.

It’s worth noting that in Raspbian Jessie Lite the defaut is the Slow Boot (yay!) and therefore you don’t have to worry about this step.

Hope this is helpful. If you have any problems, leave a comment. Bear in mind I’m a Linux noob and what’s written above might not be the best way to achieve this and I take no responsibility if anything breaks :)