This is the first part of a five part tutorial that will show you how to install a full featured email server on your Raspberry Pi. This tutorial covers Postfix, the Mail Transfer Agent.
The parts are:
The Introduction & Contents Page (read first)
Raspberry Pi Email Server Part 1: Postfix
Raspberry Pi Email Server Part 2: Dovecot
Raspberry Pi Email Server Part 3: Squirrelmail
Raspberry Pi Email Server Part 4: Spam Detection with Spamassassin
Raspberry Pi Email Server Part 5: Spam Sorting with LMTP & Sieve
Installing Postfix
Note: While you are setting up the mail server on the Pi, it’s a good idea to turn off port forwarding rules for email to the Pi in your router’s firewall. If you don’t have any port forwarding rules now, that’s great, don’t worry – I’ll prompt you to set them up later. First, log into your Pi with a SSH session and install postfix:
sudo apt-get update sudo apt-get install postfix
You will see a menu with some choices. Select “Internet Site” and then set the mail name to your domain name, not including www. (e.g. samhobbs.co.uk). The setup script will then do some automatic configuration for you. The output will look something like this:
Selecting previously unselected package postfix. (Reading database ... 67653 files and directories currently installed.) Unpacking postfix (from .../postfix_2.9.6-2_armhf.deb) ... Processing triggers for man-db ... Setting up postfix (2.9.6-2) ... Adding group `postfix' (GID XXX) ... Done. Adding system user `postfix' (UID XXX) ... Adding new user `postfix' (UID XXX) with group `postfix' ... Not creating home directory `/var/spool/postfix'. Creating /etc/postfix/dynamicmaps.cf Adding tcp map entry to /etc/postfix/dynamicmaps.cf Adding sqlite map entry to /etc/postfix/dynamicmaps.cf Adding group `postdrop' (GID XXX) ... Done. setting myhostname: samhobbs setting alias maps setting alias database changing /etc/mailname to samhobbs.co.uk setting myorigin setting destinations: samhobbs.co.uk, samhobbs, localhost.localdomain, localhost setting relayhost: setting mynetworks: 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 setting mailbox_size_limit: 0 setting recipient_delimiter: + setting inet_interfaces: all /etc/aliases does not exist, creating it. WARNING: /etc/aliases exists, but does not have a root alias.
You can edit all of this later. You may also get some warnings like this:
postmulti: warning: inet_protocols: disabling IPv6 name/address support: Address family not supported by protocol
IPv6 is a new type of IP address that was introduced because we’re running out of the “old” IPv4 addresses. Not many ISPs support IPv6 yet, so you probably don’t need it. Unless you fix the warning, you’ll see it every time. Change directory into the postfix configuration folder:
cd /etc/postfix/
Edit /etc/postfix/main.cf
with your favourite command line text editor (e.g. sudo nano main.cf
) and add inet_protocols = ipv4
to the end of the file. Now is also a good time to check that your hostname is specified properly in /etc/postfix/main.cf
. The setup script takes the hostname of the server and uses that, but it may not be in the right format, i.e. “samhobbs” instead of “samhobbs.co.uk”. Find the line that begins myhostname =
and make sure it is your fully qualified domain name. This is important because your server will use this to talk to other mail servers, and some will reject your emails if you don’t use a fully qualified domain name to say hi! This is covered in more detail in the helo access restrictions later. Restart postfix and you shouldn’t see the warnings any more:
sudo service postfix restart
Testing and Configuration
Before you start, it’s probably worth backing up the configuration files in their current state. This way, you’ll have something to compare to if you’re ever trying to work out which bits were defaults and which bits you changed yourself:
cd /etc/postfix sudo cp main.cf main.cf.BAK sudo cp master.cf master.cf.BAK
Mailbox Setup
There are a couple of different types of mailbox you can use, I’ve chosen to use a “Maildir” rather than “mbox” configuration. For users with “real” UNIX accounts on the system (like the one you’re using to log in), Maildir creates a folder in the user’s home directory and places emails inside it, one file for each email. I prefer this to the alternatives, because it’s easier to see and understand: you can rummage around in your home folder and see all your emails as individual files. To tell Postfix to use the Maildir format, add the following lines to /etc/postfix/main.cf
:
home_mailbox = Maildir/ mailbox_command =
If there's already a line with mailbox_command
, comment it out by adding a #
at the start of the line. We also need to create the mail directory and its subfolders for existing users, and add some things to /etc/skel
(the template for new users) so that if you create a new account this will be done automatically. These commands are part of Dovecot, so first we need to install it:
sudo apt-get update sudo apt-get install dovecot-common dovecot-imapd
You will get a lot of output: some other dovecot packages will automatically be installed and the config files will be created. You will also see some errors – don’t worry about those for now, I’ll explain how to deal with them in part 2, later. Now we can create those mail folders. Run the following commands to create the template files:
sudo maildirmake.dovecot /etc/skel/Maildir sudo maildirmake.dovecot /etc/skel/Maildir/.Drafts sudo maildirmake.dovecot /etc/skel/Maildir/.Sent sudo maildirmake.dovecot /etc/skel/Maildir/.Spam sudo maildirmake.dovecot /etc/skel/Maildir/.Trash sudo maildirmake.dovecot /etc/skel/Maildir/.Templates
Next, copy the files over to existing users’ home directories, and change the ownership and permissions for privacy (replace USER with the username you are doing this for, and repeat for all existing usernames):
sudo cp -r /etc/skel/Maildir /home/USER/ sudo chown -R USER:USER /home/USER/Maildir sudo chmod -R 700 /home/USER/Maildir
Initial Testing
Now, the best way to test Postfix during configuration is to use Telnet, because it is such a simple way of communicating between programs and there’s less to go wrong and get confused about. First, install telnet:
sudo apt-get install telnet
Now, still inside the SSH session to your pi, type this command. It will connect you to port 25 on the Pi:
telnet localhost 25
You can now test sending an email using SMTP. Here are the steps:
- send an
ehlo
command to tell the server who you are, and it will tell you its capabilities - use the
mail from
command to say who the email is from. If you are sending it from an address that exists on the server, you needn’t include the domain name (i.e. user instead of user@yourdomain.com) - use the
rcpt to
command to tell the server where to send the email - Use the
data
command to tell the server that you’re about to start giving it the message you want to send - Type
Subject: YOUR SUBJECT
then enter to set a subject - Type the body of your email. Once you’re done, press
ENTER
, then.
, thenENTER
again. - Type
quit
to exit
Here’s an example:
telnet localhost 25 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. 220 samhobbs.co.uk ESMTP Postfix (Debian/GNU) ehlo foobar 250-samhobbs.co.uk 250-PIPELINING 250-SIZE 10240000 250-VRFY 250-ETRN 250-STARTTLS 250-ENHANCEDSTATUSCODES 250-8BITMIME 250 DSN mail from: me 250 2.1.0 Ok rcpt to: me@outsideemail.com 250 2.1.5 Ok data 354 End data with <CR><LF>.<CR><LF> Subject: test This is a test email . 250 2.0.0 Ok: queued as A639C3EE6D quit 221 2.0.0 Bye
Some Access Restrictions
Add the following to /etc/postfix/main.cf
to restrict who can send emails to external mail servers:
smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination
Reload postfix:
sudo service postfix reload
- Line 1 begins the list of restrictions.
- Line 2 permits users who have authenticated with Simple Authentication and Security Layer (SASL) to send email to any destination (this is part of the Dovecot config in Part 2, later).
- Line 3 will let users send emails to any destination if they have connected from an IP address defined in mynetworks.
- Line 4 will reject the email if none of the above conditions have been met unless the “rcpt to” address is one of the addresses that your server is accepting email to (as defined in
main.cf
with themydestination
parameter).
In its present state, the email server will allow you to send external emails because the connection is originating from the Pi itself (you are logged in via SSH) and not an unknown computer. Addresses of “trusted” computers are listed under the mynetworks setting in main.cf
, e.g.
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
Try sending an external email again, using telnet as before. You should be able to do so without any issues. Now we want to see what kind of response someone would get if they were connecting from outside of the IP range defined in mynetworks
, to make sure Pi won’t allow everyone to send outgoing emails from your server. To simulate this we can comment out permit_mynetworks
under smtpd_recipient_restrictions
:
smtpd_recipient_restrictions = permit_sasl_authenticated, # permit_mynetworks, reject_unauth_destination
Now reload the postfix configuration:
sudo service postfix reload
This will let you see what kind of response you would get if you weren’t sending the email from mynetworks. Try sending again, and you should receive an error “554: Relay access denied“:
admin@samhobbs /etc/postfix $ telnet localhost 25 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. 220 samhobbs.co.uk ESMTP Postfix (Debian/GNU) ehlo samhobbs.co.uk 250-samhobbs 250-PIPELINING 250-SIZE 10240000 250-VRFY 250-ETRN 250-STARTTLS 250-ENHANCEDSTATUSCODES 250-8BITMIME 250 DSN mail from: USER 250 2.1.0 Ok rcpt to: me@externalemail.com 554 5.7.1 <me@externalemail.com>: Relay access denied quit 221 2.0.0 Bye Connection closed by foreign host.
Perfect. Leave permit_mynetworks
commented out in your smtpd_recipient_restrictions
(you'll see why in part 2).
Helo access restrictions
Helo access restrictions can be a very useful way of blocking spam. Note that we’re not talking about unauthorised people being able to send email outside your network any more (that’s taken care of with the smtpd_recipient_restrictions
); we’re now talking about stopping spammers from sending incoming mail to your email address. Spammers try to conceal their identity so that they don’t end up on block lists, so they rarely use helo hostnames that could identify them – these hostnames are written to the mail log files. As a result, they often make up a random string or use an IP address instead of a domain name. Luckily, these are easily taken care of. Add the following to /etc/postfix/main.cf
:
smtpd_helo_required = yes smtpd_helo_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_invalid_helo_hostname, reject_non_fqdn_helo_hostname, reject_unknown_helo_hostname
- Line 1 requires people and programs to identify themselves when they send email, using the
helo
orehlo
commands I mentioned earlier. - Line 2 starts the list of restrictions.
- Line 3 accepts any old rubbish in the
ehlo
if it comes from an IP address defined in mynetworks. If the connection isn’t connecting from an IP address in mynetworks, then the helo hostname is checked against the rest of the list. - Line 4 accepts any
helo
hostname if the client is authenticated with SASL (I added this to the tutorial recently after troubleshooting problems some people had in the comments – it allows you to connect from any network and still send messages through your Pi. Mobiles will usually work without this because most providers pass mail through their own proxies, so your Pi receives a connection from the proxy – which has a valid hostname – and not from the mobile, which may be called something like “android-b627cfe2efea7e67″). - Line 5 rejects connection attempts when the HELO hostname syntax is invalid.
- Line 6 rejects non-fully qualified domain names (for example, foobar instead of foobar.com). This will also block those random strings, e.g. “kjhrsbvks”.
- Line 7 rejects the helo hostname if it that domain doesn’t have a valid DNS A or MX record. For example, someone spamming you could make up a domain like theflyingspaghettimonster.com. If that domain doesn’t actually exist and have the right records, then your server won’t accept it as a hostname, and the email will be rejected.
If the helo hostname gets past line 7 and hasn’t been denied, it is accepted. You’d be surprised how much spam these helo access restrictions will block on their own (looking through my log files, I can see numerous spam scripts that have attempted to ehlo with my IP address), but there’s an extra step we can add in here to help:
Blocking people claiming to be your domain name
Many spammers try to send email to you after helo
’ing with your own domain name. Since postfix doesn’t check whether or not they’re lying about their helo hostname, this will usually work. But, since we’ve put permit_mynetworks
at the top of the list, anyone actually sending an email from your domain will be accepted already. Anyone using your hostname who isn’t in mynetworks is an imposter. So, add one more line to the end of the restrictions list:
smtpd_helo_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_invalid_helo_hostname, reject_non_fqdn_helo_hostname, reject_unknown_helo_hostname, check_helo_access hash:/etc/postfix/helo_access
That last line checks a file for custom rules you’ve built in. Create the file:
sudo nano /etc/postfix/helo_access
Add the following lines, edited for your domain:
samhobbs.co.uk REJECT Get lost - you're lying about who you are mail.samhobbs.co.uk REJECT Get lost - you're lying about who you are
Now tell postfix to map the file, and restart postfix:
sudo postmap /etc/postfix/helo_access sudo service postfix restart
Now anyone who tries to ehlo
with one of the hostnames you defined in that file gets rejected, and sees the “get lost” message. Your legitimate servers won’t have that problem, because they will already have been accepted higher up the list. Neat, right? I found that little nugget of wisdom at unixwiz.net.
Moving on…
We’re almost done with Postfix now, athough there are a few bits of configuration that we’ll want to do once we’ve set up SASL with Dovecot, which I’ve chosen to lump in with the Dovecot tutorial. In Raspberry Pi Email Server Part 2: Dovecot, we’ll set up Dovecot to provide SASL authentication and IMAP capability. Please leave a comment if you’re having trouble with anything in this tutorial, and I’ll try and help you out!
Comments
What's your IP address/domain name?
Thanks for caring Sam, I
Thanks for caring Sam, I really appreciate it. Let me know if you´re in Iceland and I will buy you a beer/tea :-P
85.220.30.129
rostur.org
I can connect to you
I'm home now... wasn't fail2ban
No, but I´m sure I can
No, but I´m sure I can emulate that somehow. My Pi is behaving weird right now (
Read from socket failed: Connection reset by peer
. I´m going to setup Raspbian again from scratch and run through your tut again :-)Excellent tutorials! One quick question
Hello Sam,
Thank you very much for all your great info; I highly appreciate that you took the time to write this thorough tutorial out! I've got everything working all the way up to part 4 of the tutorial, that's where I'm up to.
My question is regarding this part of the tutorial however, specifically the storage path of emails. In your listed configuration, every user would have their Maildir in /home/USER which is defined by /etc/skel/ and that's fine. But what if we were to take it one step further and change the Maildir path from the RPi's SD card to some USB drive like /dev/sdX or /media/loldrivehere/? The reason being a relatively limited disk space on the SD card compared to, say, a 1TB HDD. Could it be done?
Looking forward to hearing your response and once again, thank you for your thorough tutorials!
-Mr. Cloud
Easier to move the whole of /home
/home
. Best to take the SD card out of the pi and do this from a linux workstation:/home
from the SD card to your external drive/etc/fstab
(on the SD card, not your laptop!) mounting the drive on/home
at boot (use UUID to identify drive/partition)/home
from the SD cardEasier to move the whole of /home
Actually I just moved the home directories to the external media drive and created symlinks to them in /home.
Then a whole lot of services will store and retrieve from the external drive without needing any additional config. Some system users are staying on the sd card though so that they go wherever the card goes.
Excellent.
Thank you for the prompt reply, Sam. I decided to move the whole partition to external drive (HDD, 100gig+) following your link and everything is working as expected. The only thing I had to redo after doing this change was to sudo chown -R 777 /media/* because they were being mounted in /etc/fstab by root, so my pi account didn't have write access to them. But after that, so far so good!
Cheers,
Mr. Cloud
PS- Mr. Cloud, that's my name; that name again is Mr. Cloud! <3
Gotta love that song!
Error 221 2.7.0
Hi Sam,
First of all, thanks so much for your great tutorial - it's so well written and easy to understand even for a newbie like me.
I followed it step by step last night, and when I got to the testing part, it told me that everything went alright (even though I didn't receive any email at the tested recipient address, but that's another issue).
After that, I went to bed and this morning I wanted to continue looking into why I didn't receive the test mails. I logged in just as I did yesterday, started telnet and sent an ehlo command. I received the following error message:
221 2.7.0 Error: I can break rules, too. Goodbye.
Connection closed by foreign host.
I tried undoing all the changes to /etc/postfix/main.cf that I made during the tutorial, to no avail. Even a complete purge of postfix and dovecot off my system and clean reinstall didn't solve the problem. I keep getting kicked out right after the ehlo command.
Have you had this before or do you have any idea where I could have gone wrong?
Best,
Jakob
SMTP commands in the wrong order/invalid
Re: SMTO commands in the wrong order/invalid
Sam,
I'm almost too embarrassed to write back - I did use the wrong syntax. I had a colon (:) after the ehlo command. Everything works now, including receiving the test mail at the recipient address. Thanks so much again!
Best,
Jakob
Glad you sorted it
Re: Glad you sorted it
Oh, I thank you for this awesome tutorial. I was actually wondering if you have a paypal account where I could send a virtual pint as a little token of my appreciation?
You're too kind! Thank you,
Not working: telnet localhost 25
Hi Sam.
Thanks for a super guide until now, but I have run into a problem.
I can not get telnet to work, I get this error no matter which port I tried:
root@raspberrypi:~# telnet localhost 25
Trying 127.0.0.1...
Trying ::1...
telnet: Unable to connect to remote host: Address family not supported by protocol
It works fine out of the house, but not on localhost. I have searched through google, but can not find a solution. Can you help?
Br
Steen
Have you changed your /etc/hosts file
Raspberry Pi Email Server Part 1: Postfix
Thanks Sam. I may do some more experimenting but for now I did get things working with an SMTP provider. Oh, and a clarification on my first post. My ISP is CableOne and they use GMail for their email server. Sorry for the confusion :-).
Yes, it look more or less
Yes, it look more or less like yours
root@raspberrypi:~# cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
127.0.1.1 raspberrypi
Br
Steen
Curious
No errors.
No errors.
[ ok ] Stopping Postfix Mail Transport Agent: postfix.
[ ok ] Starting Postfix Mail Transport Agent: postfix.
Yes, it's very weird
I wonder if postfix is only
inet_protocols
parameter is set to please? Also, try: Just to check... SamSame issue with 127.0.0.1
Same issue with 127.0.0.1
inet_interfaces = all
inet_protocols = ipv4
home_mailbox = Maildir/
mailbox_command =
Steen
Sorry, I'm out of ideas!
That's ok. Thanks for trying
That's ok. Thanks for trying
Steen
Me again.
Me again.
Telnet is now working, had to reinstall raspbian since I got stock.
But now a new problem has occurred. I'm not able to make "Testing SASL" working.
#Method No.1-2-3
echo -ne '\000testmail\000test1234' | openssl base64 are working fine, but when i'm trying to make it work with Telnet it doesn't show
AUTH PLAIN AHRlc3RtYWlsAHRlc3QxMjM0, it stops at 250 DSN.
Kind of like missing:
AUTH PLAIN AHRlc3RtYWlsAHRlc3QxMjM0
235 2.7.0 Authentication successful
Du you have any ideas how to solve it
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 brizarr.com ESMTP Postfix (Debian/GNU)
ehlo facebook.com
250-brizarr.com
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-STARTTLS
250-AUTH PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
That bit is something you type
Argh.....sorry :-)
Argh.....sorry :-)
When I do the rcpt to command
When I do the
rcpt to
command, I get the following response:554 5.7.1 : Relay access denied
Does anyone know what this is, why I'm getting it and how to solve it?
Thanks,
Eric
Add new comment