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
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:
/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
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
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
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
ehlocommand to tell the server who you are, and it will tell you its capabilities
- use the
mail fromcommand 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 firstname.lastname@example.org)
- use the
rcpt tocommand to tell the server where to send the email
- Use the
datacommand to tell the server that you’re about to start giving it the message you want to send
Subject: YOUR SUBJECTthen enter to set a subject
- Type the body of your email. Once you’re done, press
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: email@example.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
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
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
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
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: firstname.lastname@example.org 554 5.7.1 <email@example.com>: Relay access denied quit 221 2.0.0 Bye Connection closed by foreign host.
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
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
ehlocommands I mentioned earlier.
- Line 2 starts the list of restrictions.
- Line 3 accepts any old rubbish in the
ehloif 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
helohostname 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.
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!
Use Gnus mainly. Running under Emacs 24. Using Trisquel distro. Also tried configuring using Evolution.
Found this in /var/log/mail.warn
"Mar 31 11:11:06 raspberrypi postfix/smtps/smtpd: warning: TLS library problem: error:1408F10B:SSL routines:ssl3_get_record:wrong version number:../ssl/record/ssl3_record.c:252:
Mar 31 11:30:57 raspberrypi dovecot: master: Warning: SIGHUP received - reloading configuration
Mar 31 13:15:36 raspberrypi dovecot: master: Warning: SIGHUP received - reloading configuration
Mar 31 15:41:46 raspberrypi dovecot: master: Warning: Killed with signal 15 (by pid=19671 uid=0 code=kill)
Mar 31 15:41:47 raspberrypi dovecot: log: Warning: Killed with signal 15 (by pid=1 uid=0 code=kill)
Mar 31 15:42:14 raspberrypi dovecot: master: Warning: Killed with signal 15 (by pid=19832 uid=0 code=kill)
Mar 31 15:42:14 raspberrypi dovecot: log: Warning: Killed with signal 15 (by pid=1 uid=0 code=kill)
Mar 31 15:53:35 raspberrypi dovecot: master: Warning: Killed with signal 15 (by pid=20089 uid=0 code=kill)
Mar 31 15:54:15 raspberrypi dovecot: master: Warning: Killed with signal 15 (by pid=20479 uid=0 code=kill)
Mar 31 15:56:09 raspberrypi dovecot: master: Warning: SIGHUP received - reloading configuration"
Appears to me to be something to do with ssl3? :/
You've got a great tutorial here, however I am getting stuck at the 'Initial Testing' phase.
When entering the commands, and getting to the 'data' command, I'm getting an error.
421 4.3.0 collect: Cannot write ./dfw4EFc18K028870 (bfcommit, uid=0, gid=126): No such file or directory
Connection closed by foreign host.
I'm not sure where this directory might be; do you have any idea?
sudo netstat -tulpnSam
I have been using Mercury/32 as an email relay for several years, but some of the new security features ISP mail uses are starting to block some of my email. I'm a Raspbian novice, but can follow directions :) My client has 16 of those big, free-standing, coin-op ice machines. They will send email when they have a hardware fault. Unfortunately, they were programmed a lot of years ago and they are not really good at sending email the way ISPs want to see it. They send out what looks like a Telnet email: mail from: rcpt to: data: SUBJECT: two line error message and end. I have them sending to an address where Mercury/32 is running. Mercury is not as picky about how well-formed the email is. Mercury/32 forwards the email to a paid email service (SENDGRID) . Trouble is, Google and vtext.com are starting to reject the emails. SO basically, I don't need any local mailboxes at all. I need PostFix to accept a barely formed (unchangeable format, will not log in to the email server) email, block any incoming email that does NOT one of three wildcard extension (like *.wilburcabinets.com, *.rcblock.com or *.rc-block.com [these are not real domains, I only use them to show WHICH machine the message is coming from, i.e. they will not pass testing] ) and send a well-formed email to SENDGRID for forwarding to the recipient. If it is not too much trouble, could you tell me how to configure Postfix such a way?
Hi Sam -
Great tutorial. I really appreciate all the work you put into it.
I have an issue with receiving mail from external domains. I have followed along both parts 1/2 and I believe I have everything configured properly. I can send mail no problem, but I cannot receive mail. I can send/receive mail internally using 'telnet localhost 25'. There is nothing in the logs or in the error logs to indicate a problem. I do NOT have a static IP so I think my ISP may be blocking? I cannot telnet to your domain over port 25. But I didn't think I was using port 25 to receive mail (I thought we used 993)? Do you have any ideas on how I could troubleshoot?
I tried a couple things you recommended:
1. I called my ISP and they said they are NOT blocking port 25 (incoming or outgoing). However they do not have an SMTP relay so I am using a third party (sendGrid).
2. Just for giggles, i reformatted my pi and went through the tutorial again to make sure i didn't miss anything. I'm still at the same spot :(
3. All my ports are forwarded correctly: 25,465,993. I know it works because i also forward 22 for SSH and i am able to SSH into my pi through the internet. So I guess i am assuming the other ports are working correctly.
4. I believe I have my A record and MX record set up correctly (my domain is: ex3.host)
So I guess the only things I can't do: I can't telnet to your domain (telnet samhobbs.co.uk 25) and I still can't receive email from an external domain, although I can get it when I send from my own domain - ex3.host.
You provide instructions for setting up Maildir format. What do you do if this is not your preference?
I've been running a Eudora Mail Server on a really old Mac for about 15 years or so. It doesn't support encryption, which is my motivation to set up a new server. It wasn't a problem when all of my POP queries were from behind my router, but with a new dual-WAN, most of my queries are going out the 1G network, and then coming back to the fixed IP from the outside. Bummer.
My other concern is that the old server supports about a half-dozen domains, with a bunch of cross-domain redirects. I figure I'll finish the tutorial, and then assess whether I can adapt the approach to my situation, or use a different tutorial, as you suggest. I expect to go through this exercise a few times, as you did.
I had some concern about the behavior when permit_mynetworks was commented out. I was probably doing something wrong, but the server didn't reject me, the way you described.
Thank you for making these posts available.
Tutorial one I have completed and it works so far. Thanks.
This tutorial has been amazing so far! Been a while since I went through one this clean! Good job.
I did find one thing abnormal that I was hoping someone could help me with below.
postmap: warning: /etc/postfix/main.cf, line 46: overriding earlier entry: inet_protocols=all
Line above is received after entering --> sudo postmap /etc/postfix/helo_access
If I go into main.cf and comment out inet_protocals=all then "sudo postmap /etc/postfix/helo_access" gives no warning.
Thanks in advance.
inet_protocolsin master.cf that gets overwritten or something like that. I wouldn't worry about it. Sam
I have had a blast working through your tutorial and although the tutorial has been written in 2014 I was hoping that I could seek here for a bit of help. My problem is that I have a webapp on a different server that has an email notification system. I can't get to seem that part working and I guess that is because in the written tutorial, external servers are unauthorized if I am not mistaken. How could I make it so the other server could auth as well and can send e-mails through my homeserver?
It's an app called Sonarr and it uses login. So I first thought it would be sufficient to only fill in the user login I use for mailing but indeed, I didn't change anything under main.conf. I now changed it to what was there already and added a comma followed by the remote IP (which is fixed and even has an own domain name. Would that be enough or am I filling in the mynetworks at a faulty way?
Not just for the comment but you seem like a real top notch guy. Have a great weekend!
I Sam. Thanks for those explanations that's worked wall 6 months ago. But the SD card of my raspery crashed so I resarted a whole installation with a hard drive instead of a SD card. Now i Can send emails but I'm not able to receive emails. My mailserver adress is thomasfamily.freeboxos.fr. Can you help?
Thanks in advance,
I sorted it out: there was a mix in main.cf between smtpd_recipient_restriction and smtpd_helo_restriction
thanks again for your terrific tutorial;-)
Hi Sam and many thanks for the tutorials on setting up email server on Raspberry Pi.
I've followed your instructions up to the point where I try to send a test email using telnet.. Unfortunately at that point it seems that the email is not sent.. My ISP is "Sky"
See below for the last few lines of the "mail.log".. I'm really not any good at reading these !!!, so would be grateful if you could advise if this is showing what may be the problem ??
Jan 29 23:37:24 raspberrypi postfix/trivial-rewrite: warning: /etc/postfix/main.cf, line 46: overriding earlier entry: inet_protocols=all
Jan 29 23:37:51 raspberrypi postfix/cleanup: warning: /etc/postfix/main.cf, line 46: overriding earlier entry: inet_protocols=all
Jan 29 23:37:51 raspberrypi postfix/smtpd: DE49A44B2F: client=localhost[127.0.0.1]
Jan 29 23:38:39 raspberrypi postfix/cleanup: DE49A44B2F: message-id=<20190129233751.DE49A44B2F@nealm.co.uk>
Jan 29 23:38:39 raspberrypi postfix/qmgr: DE49A44B2F: from=, size=352, nrcpt=1 (queue active)
Jan 29 23:38:39 raspberrypi postfix/local: warning: /etc/postfix/main.cf, line 46: overriding earlier entry: inet_protocols=all
Jan 29 23:38:39 raspberrypi postfix/local: DE49A44B2F: to=, relay=local, delay=74, delays=74/0.04/0/0.01, dsn=2.0.0, status=sent (delivered to maildir)
Jan 29 23:38:39 raspberrypi postfix/qmgr: DE49A44B2F: removed
Jan 29 23:38:55 raspberrypi postfix/smtpd: disconnect from localhost[127.0.0.1] ehlo=1 mail=1 rcpt=1 data=1 quit=1 commands=5
Many thanks for any advice you can give.
So far so good
First of all many thanks for this great guide -- clearer and better than anything else I have found
I was going along swimmingly until I came to the Test IMAP section, when "b select inbox" returned the following error:
b NO [SERVERBUG] Internal error occurred. Refer to server log for more information. [[and then the date and time]]
Any idea where I might have gone wrong?
Just wanted to say a great many thanks for your email tutorial, it is so easy to follow and it really helps when you explain each bit.
I recently got a Raspberry Pi 4 and decided to re-build my email server from scratch in Raspian Buster.
I followed you guide as I did a few years back and had everything up and running very quickly. The guide still works perfectly (though I don't need webmail so I didn't install squirrel mail.
Once again, many thanks for the countless hours it must have taken you to write the guide.
Have returned to your excellent tutorial on setting up an email server for a Raspberry Pi once again. I used it initially to setup my own mail server on a Pi that is still doing its stuff beneath our TV! Thought I'd try and use the tutorial to setup a mail server for a national campaign group I volunteer for. However it's a little more complicated than my simple Pi install was. They have 2 servers, one which has their domain pointing to it, the other being used as the mail server with a subdomain of the server 1 domain. Everything installs and tests out fine but when I eventually come to send an email to a registered address (say postmaster@domain) it returns the mail as undeliverable with the message "The mail system : host mail.domain[XX.80.XX.164] said: 554 5.7.1 : Relay access denied (in reply to RCPT TO command)".
My /var/log/mail.log file returns the following:-
"Aug 7 19:09:17 blue postfix/smtpd: connect from xxx.me.uk[xx.69.xx.139]
Aug 7 19:09:17 blue postfix/smtpd: NOQUEUE: reject: RCPT from xxx.me.uk[xx.69.xx.139]: 554 5.7.1 : Relay access denied; from= to= proto=ESMTP helo=
Aug 7 19:09:17 blue postfix/smtpd: disconnect from xxx.me.uk[xx.69.xx.139] ehlo=1 mail=1 rcpt=0/1 data=0/1 rset=1 quit=1 commands=4/6"
Any advice really would be appreciated.