This is the fifth and final 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 how to automatically sort spam emails into the spam folder using Dovecot’s Local Mail Transfer Protocol (LMTP) and Sieve rules.
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
Intro
If you followed the previous tutorial, you currently have an email server that automatically scans incoming emails using Spamassassin. However, in its current state, Spam and Ham alike are delivered to the inbox, which is annoying. Since Spamassassin only marks emails based on their spam score, we need to use an external program to handle sorting & delivery. The best tool for the job is Sieve: a set of rules defined by each user to determine how incoming emails are filtered. Sieve rules can sort emails based on a myriad of things: headers, the body of the email, various tags added by external programs, sender address… the list goes on. In this case, we are going to use Sieve rules to send emails that have been marked by Spamassassin with spam flags like this (“X-Spam-Flag: YES“) in the headers straight into the Spam folder. At present, emails are delivered to the inbox by Postfix. However, since Sieve is a Dovecot plugin, the final step of the delivery must be handled by Dovecot. This gives us two choices:
- Use Dovecot’s Local Delivery Agent (LDA)
- Use Dovecot’s Local Mail Transfer Protocol (LMTP)
For our setup, LDA is not ideal because it doesn’t run as root and therefore can’t access the individual inboxes of each user due to permissions. There are some other differences too…from the Dovecot Wiki:
The main difference is that the LDA is a short-running process, started as a binary from command line, while LMTP is a long-running process started by Dovecot’s master process.
In other words, with LDA a new process is started each time an email needs to be delivered, whereas with LMTP a process is always running and it handles a queue of emails. From what I have read on mailing lists etc. it seems that LMTP is more efficient. So… LMTP it is!
Install & Configure Dovecot LMTP
First, install dovecot-lmtpd:
sudo apt-get update sudo apt-get install dovecot-lmtpd
This will create a new config file at /etc/dovecot/conf.d/20-lmtp.conf
. Now to change the config in a few files:
/etc/dovecot/dovecot.conf
Append this to enable lmtp:
protocols = imap lmtp
/etc/dovecot/conf.d/20-lmtp.conf
Add this line to enable address extensions:
lmtp_save_to_detail_mailbox = yes
This means that if you send an email to you+folder@yourdomain.com it should be automatically placed in the “folder” folder. Cool, eh? You can use this for loads of things, but here’s a typical student example from a recent graduate ;) … Change your email address for Pizza takeaway companies to you+pizza@yourdomain.com and create a folder called “pizza”. Now all your emails about pizza go into a separate folder, instead of cluttering your inbox. Awesome :) Note: folder names are case sensitive, and the folder must be top level (not a folder within your inbox). Now change the lmtp protocol block to look like this:
protocol lmtp { mail_plugins = $mail_plugins sieve postmaster_address = postmaster@yourdomain.com }
/etc/dovecot/conf.d/10-master.conf
Now find the service lmtp {…
block and then change the line unix_listener lmtp {…
to look like this. This will allow postfix to access Dovecot’s LMTP from within its chroot:
service lmtp { unix_listener /var/spool/postfix/private/dovecot-lmtp { mode = 0666 } }
/etc/dovecot/conf.d/10-auth.conf
By default, Dovecot will try to look up “you@yourdomain.com” in your user database, when it should be looking up just the first bit (“you”). This setting instructs Dovecot to strip the domain name before doing the lookup, and convert the username to all lowercase letters:
auth_username_format = %Ln
(the L
is the lowercase part and the n
drops the domain name).
/etc/dovecot/conf.d/10-director.conf
I’m not sure if this bit is necessary, but I commented out the “protocol lmtp {…
” block completely.
/etc/postfix/main.cf
We still need to instruct Postfix to hand over control to Dovecot’s LMTP for the final stage of delivery. Comment out:
mailbox_command=
…and add:
mailbox_transport = lmtp:unix:private/dovecot-lmtp
Sieve Rules
Dovecot's sieve is already installed, you can check by running:
sudo apt-get install dovecot-sieve
Now we need to change one more parameter in /etc/dovecot/conf.d/90-sieve.conf
: Uncomment this setting:
recipient_delimiter = +
We still need to reload/restart Postfix and Dovecot to make that all the changes are loaded:
sudo service postfix reload sudo service dovecot reload
The default place to put the sieve script is in the user's home folder: ~/.dovecot.sieve
. Create it like this:
sudo nano /home/user/.dovecot.sieve
and add this:
require ["fileinto"]; # Move spam to spam folder if header :contains "X-Spam-Flag" "YES" { fileinto "Spam"; # Stop here - if there are other rules, ignore them for spam messages stop; }
Or, if you want spam messages to be marked as read as well as moved:
require ["fileinto","imap4flags"]; if header :contains "X-Spam-Flag" "YES" { addflag "\\Seen"; fileinto "Spam"; stop; }
Now chown
the file to the owner of the mailbox, e.g.:
sudo chown sam:sam /home/user/.dovecot.sieve
When Spamassassin marks emails as Spam it adds X-Spam-Flag: YES
to the headers. This rule checks the headers and sends mail to the spam folder if that flag exists.
Testing: GTUBE SPAM email
Here's how to send an email to your server using Telnet that will definitely be marked as spam. There's a neat trigger called GTUBE (Generic Trigger for Unsolicited Bulk Email) that is implemented in spamassassin. All we need to do is send a message that contains this line in the body:
XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X
We can use Telnet to send this email like we did when testing in parts 1 and 2:
feathers-mcgraw@Hobbs-T440s:~$ telnet yourdomain.com 25 Trying 192.168.1.174... Connected to yourdomain.com. Escape character is '^]'. 220 yourdomain.com ESMTP Postfix (Debian/GNU) ehlo randomdomain.com 250-yourdomain.com 250-PIPELINING 250-SIZE 10240000 250-VRFY 250-ETRN 250-STARTTLS 250-ENHANCEDSTATUSCODES 250-8BITMIME 250 DSN mail from: test@randomdomain.com 250 2.1.0 Ok rcpt to: pi 250 2.1.5 Ok data 354 End data with. Subject: test spam email This should set it off... XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X . 250 2.0.0 Ok: queued as DDFDEDA77 quit 221 2.0.0 Bye Connection closed by foreign host.
That email should land in your Spam folder. Note that if you're using Squirrelmail you won't be automatically subscribed to the Spam folder, you have to add it yourself. Thanks to Jens for finding this test!
Optional: Managesieve
Managesieve is a service that will allow you to log in remotely with a compatible email client and manage your sieve scripts. First, we need to install the necessary package:
sudo apt-get update sudo apt-get install dovecot-managesieved
You will notice that this creates a new configuration file: /etc/dovecot/conf.d/20-managesieve.conf
, which you can leave as it is. One more configuration change to make: open /etc/dovecot/dovecot.conf
and add sieve to the protocols line:
protocols = imap lmtp sieve
and restart Dovecot:
sudo service dovecot restart
The managesieve service uses port 4190, so log in to your router's admin page and forward this port to your Pi. You can now test if the service is running with telnet:
sam@samhobbs:/etc/dovecot$ telnet localhost 4190 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. "IMPLEMENTATION" "Dovecot (Ubuntu) Pigeonhole" "SIEVE" "fileinto reject envelope encoded-character vacation subaddress comparator-i;ascii-numeric relational regex imap4flags copy include variables body enotify environment mailbox date ihave" "NOTIFY" "mailto" "SASL" "PLAIN LOGIN" "STARTTLS" "VERSION" "1.0" OK "Dovecot (Ubuntu) ready."
If it's up and running, then you can try connecting with a compatible email client, like Kmail, the KDE email client that ships with distributions like Kubuntu. There is also a free software sieve plugin for Thunderbird that you might like to try if that's your client of choice. To enable sieve in Kmail, go to: Settings --> configure Kmail --> accounts --> Modify --> Filtering
Check "Server supports Sieve" and "Reuse host and login configuration". Now you can select Settings --> "Manage Sieve Scripts"
and edit your scripts using Kmail's editor, complete with syntax highlighting. If you write multiple scripts, they will be stored in ~/sieve
and the active one will be symlinked from ~/.dovecot.sieve
. If you had a script at ~/.dovecot.sieve before you set up managesieve, it will be saved as dovecot.orig when you create a new one. Thanks to the members of Kubuntuforums, without whom I would never have even heard of sieve rules! Please leave a comment, I'd love to hear how you're getting on!
Comments
Incoming mail does not get filtered by sieve
Hi Sam,
this is a great guide. I followed it to set up a RPi to accept mail from the local network so I have a central place where all system mail from my various linux devices can go. I followed the guide very closely and only skipped the spamassassin part -- there won't be any spam from within my local network.
Sadly, sieve filtering does not work for me. It's only the filtering part that does not work. Maintining the sieve rules via managesieved works great. And I know that the rules are fine, I checked this with "sieve-filter".
Incoming mail, however, does not get filtered. From '/var/log/mail.log' I can read that the mail gets put into 'INBOX', sieve is never mentioned. Do you have any advice on debugging this? I would really appreciate any help.
Btw, you could have tested your sieve rule for spam easily. It's enoug to add a line 'X-Spam-Flag: YES' when 'composing' a message via telnet.
meekstone
Is your mail being passed to LMTP?
/etc/postfix/main.cf
has this parameter in it? That line is what tells postfix to pass email to Dovecot's LMTP for the final stage of delivery, and LMTP is the bit that uses sieve. Additionally, can you check if your/var/log/mail.log
mentions delivering with LMTP? SamSieve filtering is working now
Hello Sam,
thanks for the fast reply. In '/var/log/mail.log' I can indeed see that the mail is passed to dovecot-lmtp. And I checked once again that lmtp in turn is configured to use sieve. It is.
The error was in fact not in the postfix or dovecot configuration. I just noticed in your screenshots above that you ticked the checkbox next to 'dovecot.orig' in the screenshot showing sieve configuration with KMail. So I went back to that dialogue, ticked the checkbox and voila. I'm a bit embarrassed now. But anyway, it's working now, thanks to your guide.
meekstone
Thanks for letting me know it's working
Hi,
Hi,
you've createt a very good tutorial here ! It was because of your work i was able to setup an email server on my Pi B+.
There is just something i wanted to point out.
In "/etc/dovecot/conf.d/90-sieve.conf" is an option "sieve_before". Why do you not use that to have a global handling of spam for all users so one does not have to manually create and set ownership for the ".dovecot.sieve" you provided?
So one could create a ".sieve"-file i.e. "/etc/dovecot/global-sieve/spam.sieve"
with
require ["fileinto"];
# Move spam to spam folder
if header :contains "X-Spam-Flag" "YES" {
fileinto "Spam";
# Stop here so that we do not reply on spams
stop;
}
to sort spam into the right folder and still be able to have and manage user specific sieves right?
If so do i need to chmod "/etc/dovecot/global-sieve/spam.sieve" to rwxrw-r-- ?
Very interesting
chmod 755 /path/to/script
Thanks again for the interesting comment! Samlmtp rejecting unknown user
/etc/dovecot/conf.d/10-auth.conf
By default, Dovecot will try to look up “you@yourdomain.com” in your user database, when it should be looking up just the first bit (“you”). This setting instructs Dovecot to strip the domain name before doing the loookup:
auth_username_format = %Ln
This did not work for me "unknown user" but when I altered it to = %n it worked fine?
Upper case letters in your usernames
%Ln
not only strips the domain name, it converts the username to all lower case letters. Do you have any system usernames called things like "Alf" instead of "alf"? That would explain it! SamSpamfilter-Testing
Hi Sam,
really great tutorial you wrote here. I set up a small PasPi Mailserver according to your tut... It's not completed yet, but it looks good allready. I have a small hint regarding your "To-Do" point 1: When you write a Testmail with any subject and this mail content "XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X" (without quotes) the mail will be marked as SPAM with a spam score from about 1000... This is a similiar to the eicar test virus.
Thank you, that's pretty cool
Send email to folder delimiter
Hi and hello
I have a quick question about that pizza send to mailbox thing. I would like to know how to change to delimiter to something nicer like a - or a .? Thank in advance
recipient_delimiter
/etc/dovecot/conf.d/90-sieve.conf
: And in/etc/postfix/main.cf
, set: SamHi
Hi
After some time on the internet and you're right on the postfix thing but you can also change it in /etc/dovecot/conf.d/15-lda.conf
Anyway thanks for the tut! I am lovin my new email!
Very Grateful
Hi Sam, just wanted to thank you so much for this series of tutorials. I setup all of this (barring spamassassin and webmail) a long time ago on my Raspberry Pi Model B. Since that is better off just running XBMC I have bought the new Model B+ to use as my 'everything' server and your tutorial saved me hours and hours of searching around to try to remember how I got the old one working.
The instructions are clear and I love that you explain the steps so that you can get an understanding of what you are doing instead of just copy/pasting commands. Excellent job, thanks again!
You're welcome :)
Problem executing Part5 of the guide
Good day. I'm having issues regarding running the lmtp part.
The socket /var/spool/postfix/private/dovecot-lmtp is missing, even though I've installed dovecot-lmtp. Could you help me out? Thanks
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp { #missing
#mode = 0666
mode = 0666
}
}
I'm assuming you mean the
/etc/dovecot/dovecot.conf
with this line: ... then restart dovecot and see if that solves your problem. Sam[ Error writing /home/user/.dovecot.sieve: No such file or...
What am I doing wrong? :(
Everything else seems to be working fine...
The command I am calling is
sudo nano /home/user/.dovecot.sieve
Many thanks.
I'm loving the whole explain and do it approach.
user in command
Just as a thought....
One thing I havent seen in here, which may prove to be useful to me (it's complicated, please don't ask - I move around a lot and still try to run a mail server out of the back of my car at times)
I need to pick up all my mail through a pop3 service and drop it into the mailserver at my end and have it processed at this point.
Do you know of a solution for this?
Fetchmail
Unfortunately fetchmail with
Unfortunately fetchmail with this setup doesn't work. I followed the tutorial to install the whole package (except Horde instead of Squirrel), and while sieve will move mail received by postfix, it will not process mail retrieved by fetchmail.
Thank you for everything!
This might be going to your Spam folder, ironically, because my free domain does not allow me to add an SPF record. Oh well. Anyway, I really appreciate all your hard work on this, and your other, tutorial(s). Because of that hard work I have successfully been able to configure my email server on my Raspberry Pi, along with the Owncloud server I've had running for more than a month now. Now all I need are some solar panels, an electric car, a farm, some well water, and I'm on my way to being completely off the grid!
Cheers and Best Regards,
Justin Wingate
You're very welcome, thanks
sieve doesn't store into folder spam or any other
Hi,
first of all thank you, i couldn't have come this far without your guide!
Unfortunatley i cannot solve this problem:
Sieve doesnt file the marked mails into Spam, nor the mails coming to me+something@mydomain.de into the something folder.
in the .dovecote.sieve.log is nothing; mail.log says that for the spam mail:
(i changed server names and ips)
Jun 2 18:54:55 raspberrypi postfix/smtpd[4147]: connect from mail-blubb.net[IP-blubb]
Jun 2 18:54:55 raspberrypi postfix/smtpd[4147]: A30EF42228: client=mail-blubb.net[IP-blubb]
Jun 2 18:54:55 raspberrypi postfix/cleanup[4153]: A30EF42228: message-id=<556DDFDB.9000306@blubb.de>
Jun 2 18:54:55 raspberrypi postfix/qmgr[4140]: A30EF42228: from=, size=9924, nrcpt=1 (queue active)
Jun 2 18:54:55 raspberrypi spamd[2949]: spamd: connection from localhost [127.0.0.1] at port 60165
Jun 2 18:54:55 raspberrypi postfix/smtpd[4147]: disconnect from mail-blubb.net[IPblubb]
Jun 2 18:54:55 raspberrypi spamd[2949]: spamd: setuid to debian-spamd succeeded
Jun 2 18:54:55 raspberrypi spamd[2949]: spamd: processing message <556DDFDB.9000306@blubb.de> for debian-spamd:113
Jun 2 18:54:57 raspberrypi spamd[2949]: spamd: identified spam (1000.0/2.0) for debian-spamd:113 in 1.3 seconds, 9648 bytes.
Jun 2 18:54:57 raspberrypi spamd[2949]: spamd: result: Y 1000 - FREEMAIL_FROM,GTUBE,HTML_MESSAGE,RCVD_IN_DNSWL_NONE,T_DKIM_INVALID,T_TO_NO_BRKTS_FREEMAIL scantime=1.3,size=9648,user=debian-spamd,uid=113,required_score=2.0,rhost=localhost,raddr=127.0.0.1,rport=60165,mid=<556DDFDB.9000306@blubb.de>,autolearn=no
Jun 2 18:54:57 raspberrypi postfix/pickup[4139]: 2F25442470: uid=113 from=
Jun 2 18:54:57 raspberrypi postfix/cleanup[4153]: 2F25442470: message-id=<556DDFDB.9000306@blubb.de>
Jun 2 18:54:57 raspberrypi postfix/pipe[4154]: A30EF42228: to=, relay=spamassassin, delay=1.6, delays=0.11/0.02/0/1.4, dsn=2.0.0, status=sent (delivered via spamassassin service)
Jun 2 18:54:57 raspberrypi postfix/qmgr[4140]: A30EF42228: removed
Jun 2 18:54:57 raspberrypi postfix/qmgr[4140]: 2F25442470: from=, size=10952, nrcpt=1 (queue active)
Jun 2 18:54:57 raspberrypi dovecot: lmtp(4160): Connect from local
Jun 2 18:54:57 raspberrypi dovecot: lmtp(4160, email): BrfBEOHfbVVAEAAAKv1cSg: sieve: msgid=<556DDFDB.9000306@blubb.de>: stored mail into mailbox 'INBOX'
Jun 2 18:54:57 raspberrypi postfix/lmtp[4159]: 2F25442470: to=, relay=blubbls.de[private/dovecot-lmtp], delay=0.17, delays=0.04/0.02/0.05/0.06, dsn=2.0.0, status=sent (250 2.0.0 BrfBEOHfbVVAEAAAKv1cSg Saved)
Jun 2 18:54:57 raspberrypi dovecot: lmtp(4160): Disconnect from local: Client quit (in reset)
Jun 2 18:54:57 raspberrypi postfix/qmgr[4140]: 2F25442470: removed
Jun 2 18:54:57 raspberrypi spamd[2755]: prefork: child states: II
and that for the something mail:
more or less the same in mail.log
.dovecot.sieve.log says "error: msgid=<1851654fddbaa71eee914d50d631662c@www.something.com>: failed to store into mailbox 'something': Internal error occurred. Refer to server log for more information. [2015-06-02 18:53:40]."
i unfortunately have no idea where to finde server log information?!
the .dovecot.sieve file "-rwxr-xr-x user:user" rights. and contains:
require ["fileinto"];
if header :contains "SPAM" "YES" {
fileinto "Spam";
stop;
}
note that by default it just added "***SPAM***" and i change it to "***SPAM***YES***" in /etc/spamassassin/local.cf
Header vs subject
I found the mistake for
I found the mistake for fileinto Spam. I thought header is the same as subject, so i searched for "**SPAM**" for example, which gets written into the subject. I changed that to " the normal check "X-Spam-Flag" "YES" and now it works.
Sorry for the posting of that :)
But the pizza thing still doesn't quite work. Or maybe it supposed to work like that.
If there is no folder the mail from "me+something@domain.de" goes into normal inbox. if i created the folder and added a check to my .dovecot.sieve file like this:
if address :contains "to" "something" {
fileinto "something";
stop;
}
Is this the right way? I thought the +pizza thing is supposed to work automaticaly when the folders exists without the check i wrote?!
Sorry for the long post, and thank you again for this great tutorial, and at least for reading this, if not helping :)
Case sensitive, top level folder
you+Spam@yourdomain.com
- it should go into the Spam.ah it was the case
ah it was the case sensitivity! yes it was a toplevel folder. now everything works!
Thank you so much for your help and blazing fast responses!
bingo :)
Add new comment