The RasPi’s small size and low power consumption make it an ideal choice for use as a home email server. After trying a couple of different pieces of software, I finally found an excellent combination: Postfix with Dovecot and Squirrelmail, plus Spamasssassin and Sieve for spam filtering. There are many, many tutorials out there for the first trilogy of programs, but since the configuration is slightly different for each distribution I kept coming unstuck when setting mine up on the Pi. Having finally got mine configured properly, I’ve put together a set of 5 tutorials, which will take you from a vanilla Raspbian image to a fully functioning email server in no time. When writing the tutorial I made an effort to explain what each setting does instead of just dumping commands. With a bit of luck at the end of the process you’ll not only have a working server, you’ll understand how it works… without having to wade through reams of documentation like I did! If you follow the tutorials from start to finish, here’s what you’ll end up with:
- An email server that you can run 24/7/365 for under £5 of electricity per year
- Personalised email address like you@yourdomain.com (requires you to have registered a domain name with a registrar like namecheap.com - see my DNS basics tutorial)
- The ability to connect from anywhere, and read & send email, using a secure IMAP connection on your phone, tablet or computer
- Log in to webmail using any web browser on a secure HTTPS connection, read & send email
- Complete control over your personal communication. Your emails are stored on YOUR server, and nobody is scanning them to sell you adverts.
- Smart spam filtering with Spamassassin
- Customisable mail sorting with Sieve rules
Postfix, the Mail Transfer Agent
Postfix is the program that lets you send and receive email using Simple Mail Transfer Protocol (SMTP). Whilst you, the user, may connect to your email server using IMAP (on port 143 or 993), or POP (on port 110 or 995), email servers talk to each other using SMTP on port 25. So, this is the basic core of the server. Without it, you wouldn’t be able to send or receive any emails! I’ve covered the setup here: Raspberry Pi Email Server Part 1: Postfix
Dovecot, the POP/IMAP Server
Dovecot is used for two things:
- It provides you with IMAP functionality
- It checks that you are who you say you are using Simple Authentication and Security Layer (SASL) before you send or fetch mail
If you’re not interested in connecting with IMAP on your devices, you still need Dovecot. Not only is it doing SASL for you, but Squirrelmail connects using IMAP in order to provide you with webmail. I’ve covered Dovecot installation and configuration here: Raspberry Pi Email Server Part 2: Dovecot
Squirrelmail, for Webmail
Squirrelmail is handy because it allows you to check your email in any browser, from anywhere. Of the first three, it’s probably the easiest to configure. I’ve covered it here: Raspberry Pi Email Server Part 3: Squirrelmail
Spamassassin, for Marking Spam
Spamassassin is the program that we will use to audit incoming mail and decide whether or not it’s spam. Spamassassin doesn’t actually sort the mail into the spam folder, it only changes information in the headers based on the results of the scan. I’ve covered it here: Raspberry Pi Email Server Part 4: Spam Detection with Spamassassin.
LMTP & Sieve for Spam Sorting & Mailbox Organisation
After Spamassassin has checked incoming mail to see if it’s spam or not, we need another program to sort it into the right mail folder. This final step will be done with Dovecot’s Local Mail Transfer Protocol (LMTP) daemon and a Sieve plugin. Sieve is a simple programming language that allows users to define what to do with incoming email based on a predefined set of rules – think “if the header contains this flag, put it in the spam folder” kind of thing and you’ll get the gist. Aside from spam filtering, Sieve can be used to automatically sort & de-clutter your inbox. These steps are covered in the final tutorial: Raspberry Pi Email Server Part 5: Spam Sorting with LMTP & Sieve Enjoy! I’d love to hear how you get on, so leave a comment below :)
Comments
Thanks for the prompt
Thanks for the prompt response, Sam. I'll give it a go and revert.
John
Sam, I tried that but my
Sam, I tried that but my problems continue albeit with a slightly different error message.
Mail Delivery Subsystem
13:23 (2 hours ago)
to me
This is an automatically generated Delivery Status Notification
THIS IS A WARNING MESSAGE ONLY.
YOU DO NOT NEED TO RESEND YOUR MESSAGE.
Delivery to the following recipient has been delayed:
john@mydomain.com.au
Message will be retried for 2 more day(s)
Technical details of temporary failure:
Google tried to deliver your message, but it was rejected by the server for the recipient domain mydomain.com.au by mail.mydomain.com.au. [my IP].
The error that the other server returned was:
451 4.3.5 : Helo command rejected: Server configuration error
Your continued help is appreciated.
TIA
John
Sounds like there may be a
No errors on starting Postfix
No errors on starting Postfix, Sam.
Herewith the main.cf:
# See /usr/share/postfix/main.cf.dist for a commented, more complete version
# Debian specific: Specifying a file name will cause the first
# line of that file to be used as the name. The Debian default
# is /etc/mailname.
#myorigin = /etc/mailname
smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU)
biff = no
# appending .domain is the MUA's job.
append_dot_mydomain = no
# Uncomment the next line to generate "delayed mail" warnings
#delay_warning_time = 4h
readme_directory = no
# TLS parameters
smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
smtpd_use_tls=yes
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
# See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for
# information on enabling SSL in the smtp client.
myhostname = mail.mydomain.com.au
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
myorigin = /etc/mailname
mydestination = hedge.com.au, rpi, localhost.localdomain, localhost
relayhost =
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all
inet_protocols = ipv4
home_mailbox = Maildir/
mailbox_command =
smtpd_recipient_restrictions =
permit_sasl_authenticated,
permit_mynetworks,
reject_unauth_destination
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
check_helo_access hash:/etc/postfix/helo_access
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
smtpd_tls_auth_only = yes
Thanks,
John
Check helo access
I obviously missed a domain
I obviously missed a domain name :-) The output was:
hedge.com.au REJECT Get lost - you're lying about who you are
www.hedge.com.au REJECT Get lost - you're lying about who you are
John
Did you run the first command?
/etc/postfix/helo_access.db
, which is the database that is created by the postmap command - postfix reads this, not the text file/etc/postfix/helo_access
. If you've not run the command, or if you've changed the file since you last ran it, please run it again and restart postfix to see if that makes a difference. SamAh! Apologies, I ran the
Ah! Apologies, I ran the command and forgot to paste the output so I ran the command again and restarted. The output is:
-rw-r--r-- 1 root root 274 Jan 7 08:36 dynamicmaps.cf
-rw-r--r-- 1 root root 160 Jan 7 09:13 helo_access
-rw-r--r-- 1 root root 1826 Jan 10 11:29 main.cf
-rw-r--r-- 1 root root 1262 Jan 7 08:42 main.cf.BAK
-rw-r--r-- 1 root root 5595 Jan 7 12:17 master.cf
-rw-r--r-- 1 root root 5531 Jan 7 08:42 master.cf.BAK
-rw-r--r-- 1 root root 19707 Mar 13 2013 postfix-files
-rwxr-xr-x 1 root root 8729 Mar 13 2013 postfix-script
-rwxr-xr-x 1 root root 26498 Mar 13 2013 post-install
drwxr-xr-x 2 root root 4096 Mar 13 2013 sasl
No helo_access.db!
If you're willing to have a look I'm happy to let you ssh into it. <redacted>
Thanks.
postmap
/etc/postfix/helo_access.db
afterwards. Now restart postfix (sudo service postfix restart
) and send a test email from your freemail account again. I won't ssh into your server because I think you can do it yourself (and posting the UN/PW was a bit dodgy so I redacted it - remember this is a password that will let people authenticate and send mail from your account! If the user is in the "sudo" group it would be trivial for someone to pwn your server by logging on using the credentials in the comment). You might want to set up publickey authentication so that bots can't guess your password, or at least use fail2ban to crack down on bruteforce attacks. SamIt works! :-) SquirrelMail is
It works! :-) SquirrelMail is showing its received my last 2 test emails. Did I miss a step in the Postfix tutorial, Sam?
Thanks for keeping me secure. I'll check out your security ideas a bit later.
And thanks for all your help.
John
At the end
Aliases
Is any simple way to assign defined or all accounts to go for specify email address? I wish to assign admin@ webmaster@ or someuser@ for my pi mail account. Could you help?
Hi,
/etc/aliases
and then runsudo newaliases
, that's how webmaster, postmaster, root etc are mapped to my account on my server. SamCreating mail folders
In the instructions where it says to "Run the following commands to create the template files:" I get an error on each command:
sudo maildirmake.dovecot /etc/skel/Maildir
sudo: unable to resolve host myhostname
Before I go any further, is it required to set the hostname in /etc/hostname to the fully qualified hostname such as myhostname.com and reboot?
Or can the hostname in /etc/hostname be anything else?
I found that if I set /etc/hostname to myhostname.com then I don't get "unable to resolve host myhostname" message.
Should the unable to resolve message be ignored?
Haven't seen that one before!
/etc/hostname
and/etc/hosts
. The first holds the hostname (e.g. "raspberrypi"), which is the obvious bit. The stranger bit is that some software expects the hostname defined there to be resolvable to an IP address, which is what /etc/hosts is all about... so on most systems you'll see something like this... On the raspi, if you want to change your hostname you can useraspi-config
to change it in both places easily: I expect what you've done is changed/etc/hostname
without changing/etc/hosts
, right? Change them so they match and reboot, see if that solves your problem. Samhostname problem
sudo echo "foo" gives foo.
But, you are right. I only changed /etc/hostname without changing /etc/hosts. I've changed hostnames on pi's many times but forget this time. That solved that problem. Thanks!
Now, I'm into the "Initial Testing" section, read your suggestion to ssh into a second Konsole to look at log with (less +f /var/log/mail.log) and get this when doing the telnet localhost 25 command in the first ssh.
First, in main.cf I had relayhost = smtp.googlemail.com:465 and got the following:
Jan 22 19:16:43 mydomainname postfix/smtpd[2812]: connect from localhost[127.0.0.1]
Jan 22 19:18:04 mydomainname postfix/smtpd[2812]: CE95381511: client=localhost[127.0.0.1]
Jan 22 19:18:20 mydomainname postfix/cleanup[2847]: CE95381511: message-id=<20150123001804.CE95381511@mydomainname.com>
Jan 22 19:18:20 mydomainname postfix/qmgr[2398]: CE95381511: from=, size=331, nrcpt=1 (queue active)
Jan 22 19:18:21 mydomainname postfix/smtp[2848]: CLIENT wrappermode (port smtps/465) is unimplemented
Jan 22 19:18:21 mydomainname postfix/smtp[2848]: instead, send to (port submission/587) with STARTTLS
Jan 22 19:18:24 mydomainname postfix/smtpd[2812]: disconnect from localhost[127.0.0.1]
Looked up the "CLIENT wrappermode (port smtps/465) is unimplemented" and removed the :465 and got this:
Jan 22 19:26:11 mydomainname postfix/smtpd[3051]: connect from localhost[127.0.0.1]
Jan 22 19:26:45 mydomainname postfix/smtpd[3051]: 501C181516: client=localhost[127.0.0.1]
Jan 22 19:26:58 mydomainname postfix/cleanup[3055]: 501C181516: message-id=<20150123002645.501C181516@mydomainname.com>
Jan 22 19:26:58 mydomainname postfix/qmgr[3040]: 501C181516: from=, size=331, nrcpt=1 (queue active)
Jan 22 19:27:01 mydomainname postfix/smtpd[3051]: disconnect from localhost[127.0.0.1]
Jan 22 19:27:28 mydomainname postfix/smtp[3056]: connect to smtp.googlemail.com[64.233.176.16]:25: Connection timed out
Jan 22 19:27:28 mydomainname postfix/smtp[3056]: 501C181516: to=, relay=none, delay=55, delays=25/0.06/30/0, dsn=4.4.1, status=deferred (connect to smtp.googlemail.com[64.233.176.16]:25: Connection timed out)
It isn't sending email to myoutside@gmail.com.
I already had my pi successfully sending email messages when it reboots by setting up /etc/ssmtp/ssmtp.com with the following:
#
# Config file for sSMTP sendmail
#
# The person who gets all mail for userids < 1000
# Make this empty to disable rewriting.
root=postmaster
# The place where the mail goes. The actual machine name is required no
# MX records are consulted. Commonly mailhosts are named mail.domain.com
mailhub=mail
# Where will the mail seem to come from?
#rewriteDomain=
# The full hostname
hostname=myhostname
# Are users allowed to set their own From: address?
# YES - Allow the user to specify their own From: address
# NO - Use the system generated From: address
#FromLineOverride=YES
AuthUser=myoutside@gmail.com
AuthPass=mypw
FromLineOverride=YES
mailhub=smtp.gmail.com:587
UseSTARTTLS=YES
Is this maybe interfering? Any help would be appreciated. Thanks.
I'm afraid I don't know, I
ssmtp, email, etc.
Yeah, I probably do have a "mess". I have 12 (local and remote) raspberry pi's used for ownCloud (thanks to you), web cams, xbmc, weather station, heating system monitor and control, junk call blocking, backup pi, etc. When I "build" a new pi, I set a hostname and local static IP. I then run scripts that install common software (git, ssmtp, utilities, etc.) on the pi. So, all of the pi's are set up with common functions to send mail, run cron job scripts, back themselves up, notify me of power failures, etc. Then I "personalize" each pi based on its intended function.
So, I will create a "fresh" pi (I love raspberry - ha!), update, set a local static IP, NOT install any software, and THEN follow your tutorial.
As far as "I guess you don't have the option of a static IP address?". I get my tv, phone, and internet through AT&T which is on 24/7. So, technically, I don't have a static IP (at least I'm not paying for one). But, my external IP address has not changed in four years and I'm using it for my ownCloud. If my IP ever changes, my raspberry pi's will send me a text and email message almost immediately.
One important thing that I learned with 12 pi's is to provide UPS for each. I've had several power glitches that have corrupted many of them. Some just won't boot, and some "sort of" run. I also learned to re-build them from scratch rather than from a backup, because even the backups were corrupted (I unknowingly backed up "sort of functioning" pi's). Using git and cron jobs on each pi that backs each pi to another "backup pi" is a great time saver.
Thanks for you help!
Wow... and I thought I had lots of pi!
Port blocking
You are way beyond me in the networking stuff. I'm just plodding away and trying to learn.
When you say "static IP because they normally have no port blocking" are you talking about incoming or outgoing port blocking? I know that my uverse gateway does incoming port blocking because I have to open incoming ports to be able to access the pi's from the outside through ssh (each pi with a different ssh port set in /etc/ssh/sshd_config). I'm not sure about outbound port blocking or what device/software does this.
I'm not sure I understand the "relay issue"?
You say "I have a static ip and my backup has a dynamic IP, but still doesn't have outbound port blocking". I guess I have a static ip (in that it doesn't change, but I don't pay for one). But what do you mean that your "backup" has a dynamic IP but still doesn't have outbound port blocking? What is the "backup".
I just built a "fresh" pi and am following your tutorial.
ISP port blocking
ISP Port Blocking
When you say "I'm talking about your ISP's firewall, not the one you have control of on your router." Is this the firewall on the uverse gateway (in my home) that supplies my tv, phone, and internet service? Or is the ISP firewall further upstream at the ATT VRAD box in my neighborhood? Or even upstream from there?
When I log into my uverse gateway and go into Settings/Firewall/Advanced Configuration there is a section titled "Outbound Protocol Control" which says "Checking the box ALLOWS the associated traffic type through the firewall." and these are HTTP, HTTPS, FTP,
Telnet, SMTP, DNS, NetBIOS, POP3, IMAP, NNTP, IRC, H323, All Other Protocols. There's a sections on "Inbound Protocol Control" with NetBIOS" and an "Attack Detection" section with Excessive Session Detection, TCP/UDP Port Scan, Invalid Source/Destination IP address,
Packet Flood (SYN/UDP/ICMP/Other), Invalid TCP Flag Attacks (NULL/XMAS/Other), Invalid ICMP Detection, Miscellaneous.
So it looks like I CAN ALLOW SMTP traffic through the firewall in my gateway (I'm assuming that this means port 25). But that doesn't necessarily mean through a firewall upstream. I read http://www.ka9q.net/Uverse/port25.html which talks about ATT Unblocking Port 25 (but this is old). I also see under "Sending email via SMTP with Uverse... I send email smtp.gmail.com using SSL and port 465. Will this continue to work with Uverse? It should, since you're using SSL and port 465. If you were using port 25, then the answer would be 'no,' at least by default.".
So the only way to know for sure is to try it. I may be able to do that later today (I got sidetracked on something else).
So, if I can't send on 25, I may be able to call ATT and ask them to allow it (at least according to ka9q).
Why shouldn't I just pursue using SSL and port 465?
Thanks
Further upstream
SMTP Port 25
Found out that the blockage was on planet Zurg. So I put in a call to Buzz at ATT and said "I need port 25 outbound unblocked".
A minute later Woody said the port was open.
So I did:
telnet smtp.gmail.com 25
Trying 173.194.195.109...
Connected to gmail-smtp-msa.l.google.com.
First hurdle cleared. Now onto the next step.
I'm getting excited now. Thanks for your help!
hostname problem
Ok, I'm on a roll now.
I'm to the point "Set up Postfix to listen on port 465 for encrypted connections - Now try openssl". Your tutorial shows the following with samhobbs in three places.
openssl s_client -connect localhost:465 -quiet
depth=0 CN = samhobbs
verify error:num=18:self signed certificate
verify return:1
depth=0 CN = samhobbs
verify return:1
220 samhobbs.co.uk ESMTP Postfix (Debian/GNU)
quit
221 2.0.0 Bye
Mine shows:
openssl s_client -connect localhost:465 -quiet
depth=0 CN = emailserver
verify error:num=18:self signed certificate
verify return:1
depth=0 CN = emailserver
verify return:1
220 mydomainname.com ESMTP Postfix (Debian/GNU)
quit
221 2.0.0 Bye
The first two entries show emailserver which was the pi hostname before I changed it with raspi-config to mydomainname.com.
How do I get the test to show mydomainname in place of emailserver? Or does it matter?
Snakeoil cert
CAcert
Ok, I followed your tutorial on ownCloud and got a certificate. My pi ownCloud has been working great for a while.
So if I follow the CAcert tutorial again, can I just use my ownCloud CAcert certificate on my pi email server ALSO?
For the email server, I opened up IMAP Server ports in my uverse gateway. When I looked at the status, I found that ports 143, 220, 585, and 993 were opened. Do I need all four of these, or should I close some?
ports
CAcert
I'm to the point in the pi email server tutorial where I have my CAcert certificate in.
I see that ssl_cert and ssl_key already exist uncommented in /etc/dovecot/conf.d/10-ssl.conf:
ssl_cert =
Incomplete message
Somehow the above message got cut off. Reposting the complete message:
I see that ssl_cert and ssl_key already exist uncommented in /etc/dovecot/conf.d/10-ssl.conf as:
# certificate, just make sure to update the domains in dovecot-openssl.cnf
ssl_cert = </etc/dovecot/dovecot.pem
ssl_key = </etc/dovecot/private/dovecot.pem
Do I add the following two lines and comment out the above two?
ssl_cert = </etc/ssl/certs/myownkey.crt
ssl_key = </etc/ssl/private/myownkey.key
(edited to repair formatting)
Add new comment