The IMAP server Dovecot can be used to filter mail. The functionality is called Sieve, a script language for mail filtering. For Sieve to work, not Postfix but Dovecot needs to be used to deliver mail to the mailbox or the mail directory as a local delivery agent (LDA) or via local mail transfer protocol (LMTP). If you do not know, whether you should use LDA or LMTP the rule of thumb is: if you have a small mail server (preferably one user) use LDA; if you have to serve many mails, users use LMTP. This means you have to configure your mail transfer agent (MTA), Postfix for example, to use Dovecot to deliver mails and not itself.
There are at least two cons in terms of dovecot-lda in comparison to LMTP.
reject_unverified_recipient
with pipe
and LDA.A remark: even though some configuration of LDA is done in a section protocol lda
, LDA is not a protocol. Thus protocols = imap lda
throws an error. While protocols = imap lmtp
does not.
In case you are looking for a replacement of Thunderbird filters, you have to know that Dovecot Sieve filter rules are only active when new mail arrives and can not be applied to sort the INBOX
for already received mails.
After it is clear whether to use LDA or LMTP, the MTA needs to be configured to actually use Dovecot. In case of Postfix, one needs to know if only local domains or also the virtual domains need to be configured.
The installation of Sieve is straightforward.
aptitude install dovecot-sieve
This will create:
/etc/dovecot/conf.d/90-sieve.conf
/etc/dovecot/conf.d/90-sieve-extprograms.conf
After installation this basically includes:
plugin {
sieve = file:~/sieve;active=~/.dovecot.sieve
}
After installation this basically is:
plugin {
}
If you are not using LMTP, this is the way to install and use LDA. For LDA no additional package has to be installed.
For Postfix, local domains are configured usually in main.cf
, while virtual domains need configuration in main.cf
and master.cf
:
main.cf:
mailbox_command = /usr/lib/dovecot/dovecot-lda -f "$SENDER" -a "$RECIPIENT"
virtual_transport = dovecot
master.cf:
dovecot unix - n n - - pipe
flags=DRhu user=vmail:vmail argv=/usr/lib/dovecot/dovecot-lda -f ${sender}\
-d ${recipient}
(See Dovcot Wiki for details.)
On the mail server install in addition to dovecot-sieve
also dovecot-lmtpd
. The package dovecot-lmtpd
basically contains 2 major files: lmtp
and 20-lmtp.conf
.
apt-file list dovecot-lmtpd
dovecot-lmtpd: /usr/lib/dovecot/lmtp
dovecot-lmtpd: /usr/share/bug/dovecot-lmtpd
dovecot-lmtpd: /usr/share/doc/dovecot-lmtpd/changelog.Debian.gz
dovecot-lmtpd: /usr/share/doc/dovecot-lmtpd/changelog.gz
dovecot-lmtpd: /usr/share/doc/dovecot-lmtpd/copyright
dovecot-lmtpd: /usr/share/dovecot/conf.d/20-lmtp.conf
The installation is just:
aptitude install dovecot-lmtpd
This will create the file /etc/dovecot/conf.d/20-lmtp.conf
with an empty protocol configuration. You have to add the Sieve module to it. Best done in /etc/dovecot/local.conf
, like so.
protocol lmtp {
mail_plugins = $mail_plugins sieve
}
There should be a service defined, so that Postfix can find it in its change root environment.
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
group = postfix
mode = 0660
user = postfix
}
}
On systems other than Debian we might need to tell Dovecot to manage lmtp
like the configuration below. On Debian however this is done by the package, that adds a file in /usr/share/dovecot/protocols.d/
with the name lmtpd.protocol
. So the following entry is not needed on Debian.
protocols = $protocols lmtp
The transfer protocol is easier to configure in Postfix. Usually master.cf
already contains the lmtp
configuration line like:
lmtp unix - - y - - lmtp
Then in main.cf
only the transport via a local Unix socket needs to be defined in mailbox_transport
. If virtual domains are used then additionally in virtual_transport
.
mailbox_transport = lmtp:unix:private/dovecot-lmtp # for non virtual
virtual_transport = lmtp:unix:private/dovecot-lmtp # in case of virtual user
This is probably better than lmtp:inet:localhost
over the network.
The configuration of Sieve depends how and by whom Sieve should be used. If it is just one user, the admin for example, additions like managesieved
are not needed. Managed-sieve is a concept that allows Sieve clients to add and change filter rules on the server. This adds of course complexity and needs to be configured properly to lower risks. For now this guide will not explain how to install and configure the package dovecot-managesieved
.
The next thing to consider is, if the manage sieve daemon is not used, how many mail users the mail server has. If it has only one user, then a global Sieve file is OK. If it has more than one user, who wants to filter mails, an individual file is appropriate. If there are more than one user or even many, then managesieve
would be better. An individual Sieve script and a global script with the directive sieve_global
is mutual exclusive. However, there are ways to add global scripts before or after individual script execution. This is not discussed here.
For the sake of simplicity we will use the individual configuration for one user. As we do not want filtering for system users, like root, postmaster, abuse.
One major aspect of configuration is the storage location of the individual Sieve script. For this it is important to understand that the mail directory and the home directory of a user can be identical, but also can be different. For some mail storage format, like mbox
, which is just a file it might be advantageous to store this into the home directory. In this case the mail directory and home directory are identical and in addition to the mail directory, we have a file. Here of course the Sieve script will be saved into the mail directory and the home directory do not need to be defined. On Maildir
storage’s the Maildir
directory is a directory by it self. And since some files can be stored in the home directory via the OS (like from /etc/skel
), the OS might interfere with mail directory content, if the mail directory and the home directory are identical. On this systems it is advised to have different locations. However it is quite common to store the Maildir
directory inside the home directory. For this configuration we assume the last case. The /etc/dovecot/local.conf
should define:
# Linux User Home Directory (aka $HOME): _home directory_
mail_home = /home/%n
# Dovecot Maildir directory, called 'Maildir': _mail directory_
mail_location = maildir:/home/%n/Maildir
Be aware that the location of %n
is taken from the IMAP
password file. For this the value of the 6th column need to be correct. Postfix ignores this column. Therefore the value of the home directory is configured in Postfix and Dovecot separately and should match.
The location of a Sieve directory or Sieve script is defined on Debian in /etc/dovecot/conf.d/90-sieve.conf
as:
sieve = file:~/sieve;active=~/.dovecot.sieve
This means, that Dovecot lmtp
will look first in the $HOME/sieve
directory or if the directory do not exist it will use $HOME/.dovecot.sieve
as a script. If the file $HOME/.dovecot.svbin
exists, it will use the pre-compiled version. If the binary version is missing it will create a binary version. To create the binary file yourself use sievec
.
cd $HOME
sievec .dovecot.sieve
However the idea behind a visible Sieve directory in the home directory is that dovecot-manage-sieved
will manage this directory by adding scripts and creating one symlink from .dovecot.sieve
to the active script inside ~/sieve
. For example like ln -s /home/user/sieve/last.sieve /home/user/.dovecot.sieve
. So there can be only one active Sieve script.
This is an example Sieve script that might be used for testing.
require ["fileinto"];
if header :matches "Subject" ["*SIEVE*"] {
fileinto "Trash";
}
An e-mail, send from an external host, with the subject that includes “SIEVE” should be moved to the Trash
directory in the IMAP
INBOX
. Be aware that the value of fileinto
might depend on the INBOX
structure of your mail setup.
Successful execution looks like this in the Dovecot log file on Debian 10 (Buster) [some strings have been removed, like date, PID, ‘Debug: sieve:’]:
lmtp(u@dom.tld): Pigeonhole version 0.5.4 () initializing
lmtp(u@dom.tld): include: sieve_global is not set; it is currently not possible
to include `:global' scripts.
lmtp(u@dom.tld): file storage: Storage path `/home/u//sieve' not found
lmtp(u@dom.tld): file storage: Sieve storage path `/home/u//sieve' not
found, but the active script `/home/u//.dovecot.sieve' is a regular file, so
this is used for backwards compatibility.
lmtp(u@dom.tld): file storage: Using Sieve script path:
/home/u/.dovecot.sieve
lmtp(u@dom.tld): file script: Opened script `.dovecot' from
`/home/u/.dovecot.sieve'
lmtp(u@dom.tld): Using the following location for user's Sieve script:
/home/u/.dovecot.sieve
lmtp(u@dom.tld): Opening script 1 of 1 from `/home/u/.dovecot.sieve'
lmtp(u@dom.tld): Loading script /home/u/.dovecot.sieve
lmtp(u@dom.tld): Script binary /home/u/.dovecot.svbin successfully
loaded
lmtp(u@dom.tld): binary save: not saving binary /home/u/.dovecot.svbin,
because it is already stored
lmtp(u@dom.tld): Executing script from `/home/u/.dovecot.svbin'
lmtp(u@dom.tld): Debug: Mailbox Trash: Mailbox opened because: lib-lda delivery
syslog
log files (add verbosity where needed) Are there errors?sieve-test
) Is the script okay?lmtp
executed (see log files, usually Dovecot). Are there any errors? See above for an example without errors.lmtp
was executed. Was it executed without error? If not have a look in the Sieve log (See below .dovecot.sieve.log
).postconf
to check the Postfix configurationdoveconf
to check the Dovecot configurationTo enable debug logging, add mail_debug = yes
to /etc/dovecot/local.conf
and to change the locations, add the following:
mail_debug = yes
log_path = /var/log/dovecot.log
# If not set, use the value from log_path
info_log_path = /var/log/dovecot-info.log
# If not set, use the value from info_log_path
debug_log_path = /var/log/dovecot-debug.log
Restart Dovecot.
After sending a mail that should trigger the Sieve filter, do a grep on the command line for that mail in your mail storage, so that the file name of the mail can be understood.
Example Test 018:
cd $HOME
grep -r 'test 018' Maildir
Binary file Maildir/.Trash/dovecot.index.cache matches
Maildir/.Trash/cur/1673444162.M431092P29340.smtp,S=2668,W=2726:2,:Subject:\
test 018 SIEVE
Maildir/.Trash/cur/1673444162.M431092P29340.smtp,S=2668,W=2726:2,:test 018
The file is Maildir/.Trash/cur/1673444162.M431092P29340.smtp,S=2668,W=2726:2,
and since it is in .Trash
we understand that the Sieve script worked.
Example Test 016:
This mail was send before Sieve was active.
grep -r 'test 016' Maildir
Binary file Maildir/dovecot.index.cache matches
Maildir/cur/1673443420.M696259P28433.smtp,S=2710,W=2768:2,S:Subject: test 016\
SIEVE
Maildir/cur/1673443420.M696259P28433.smtp,S=2710,W=2768:2,S:test 016
The mail for test 016 is in the INBOX
and was delivered when lmtp
was not configured or the Sieve script was not found at that time. We can test if it would have been correctly delivered if the Dovecot configuration was perfect. We execute it as user root and tell that we would like to do it on behalf of user u
.
sieve-test -u u .dovecot.sieve
Maildir/cur/1673443420.M696259P28433.smtp,S=2710,W=2768:2,S
sieve-test(u)<1118><>: Debug: auth USER input: u@dom.tld local_port=0 uid=1000
gid=1000 home=/home/u/
sieve-test(u)<1118><>: Debug: changed username to u@dom.tld
sieve-test(u)<1118><>: Debug: Added userdb setting: plugin/local_port=0
sieve-test(root): Debug: Effective uid=1000, gid=1000, home=/home/u/
sieve-test(root): Debug: Namespace inbox: type=private, prefix=, sep=,
inbox=yes, hidden=no, list=yes, subscriptions=yes
location=maildir:/home/u/Maildir
sieve-test(root): Debug: maildir++: root=/home/u/Maildir, index=, indexpvt=,
control=, inbox=/home/u/Maildir, alt=
Performed actions:
* store message in folder: Trash
Implicit keep:
(none)
sieve-test(root): Info: final result: success
This will test only and not move.
If you can see that the lmtp
is executed, but an error is indicated, look into $HOME/.dovecot.sieve.log
for the error message.
Is Pigeonhole the same as Sieve? No, pigeonhole is the project and Sieve is the mail filter language. The Pigeonhole project develops dovecot-sieve and dovecot-managesieved
. It is possible to just use dovecot-sieve alone. In this case the user needs to create and edit a Sieve script on the mail server. With dovecot-managesieved,
it is possible that the user supply a script remotely (via telnet or Thunderbird plugin).
There are many ways to filter e-mails. One way is to filter mail on the mail server with the IMAP server Dovecot by using the tools of the pigeonhole project. The project implements the mail filter language called Sieve (RFC5228 and updates RFC5229, RFC5429, RFC6785, RFC9042 ) so that Dovecot can filter mail: for example move a mail from the IMAP INBOX folder to a different folder.
rfc3028 (is obsolete, now RFC5228) Obsoleted by: 5228, 5429
Sieve scripts are easy to understand. See Wikipedia for example. With manageesieve
and the Thunderbird extension this scripts can be managed on the client.
require "fileinto";
if header :contains "X-Spam-Flag" "YES" {
fileinto "Junk";
}
dovecot-lmtpd
: Locale mail transfer protocol daemondovecot-managesieved
: Dovecot ManageSieve serverdovecot-sieve
: Sieve filters support for DovecotVersion | Date | Notes |
---|---|---|
0.1.2 | 2024-05-31 | Initial release for Quick Guide |
0.1.1 | 2023-01-11 | Install Dovecot Sieve + lmtpd with Postfix |
0.1.0 | 2020-11-21 | Initial release |