Setup Sieve mail filter with Postfix and Dovecot

A mailbox can get flooded with many emails, some are automatically generated, others are related to orders. Sorting through emails on a daily basis can be a tedious task. Email filters can help automate the most common tasks. One of those filtering mechanisms is called “Sieve“. Sieve allows to sort emails as they arrive on the server.

There are many ways to sort through emails. Many email clients support some sort of rules which can be applied to the mailbox. When using multiple clients to check the mailbox, the client with the rules needs to run in order to apply the rules. In short, the rules are only applied when the client runs. A nicer way to apply rules, without involving a client, are server side rules. With Sieve, incoming emails are sorted right before they are placed in the inbox of the account.

The project Pigeonhole adds Sieve support to Dovecot. To allow the Sieve filters to be applied by Dovecot, the MTA (in this setup postfix) must be instructed to pass the email to Dovecot for final delivery. Dovecot can then run the mail through the Sieve filter and deliver the email to its destination mailbox.

Dovecot LMTP Setup

Assuming you have a mailserver running already, in a setup like described in Setup Postfix with SMTP-AUTH and TLS on CentOS and Setup Dovecot with PAM authentication and SSL on CentOS, there are not too many changes to make.

Postfix should be configured at this point to deliver the emails locally. It is assumed the “mbox” format is used by Dovecot as described in the above articles. Now Dovecot’s “LMTP” (Local Mail Transfer Protocol) should take over the email for delivery. The Dovecot configuration files are split up in most distributions and located in a “conf.d/” subdirectory. The configuration for LMTP is distributed across multiple files which makes it necessary to edit multiple files to configure and activate it.

/etc/dovecot/dovecot.conf holds a list of enabled protocols. To enable LMTP, make sure the “lmtp” protocol is listed, along with any other protocols which should be enabled. In this example only imap and LMTP will be enabled.

# Protocols we want to be serving.
protocols = imap lmtp

/etc/dovecot/conf.d/10-master.conf contains the configuration for the LMTP service. The LMTP service is configured to provide a Unix socket for postfix to connect to. The permission and owner settings ensure that the postfix process can access the socket file. The path is chosen to be inside the postfix spooling directory. As “mbox” storage is used to store emails, LMTP requires “client_limit” to be set to “1”. This ensures only one client at a time will modify the mbox file. The same setting is required for the “imap” service as it is now also involved in the local email delivery.

service lmtp {
 unix_listener /var/spool/postfix/private/dovecot-lmtp {
   group = postfix
   mode = 0600
   user = postfix
  }
  client_limit = 1
}
service imap {
  client_limit = 1
  ...
}

For postfix to pass mails to Dovecot, the /etc/dovecot/conf.d/10-auth.conf file needs to be adjusted. The “auth_username_format” needs to adopted to ensure only the username part is used to authenticate via lmtp. The “%Ln” uses only the user part and converts it to lower case. In detail, “%n” removes the domain part if present and “%L”controls the conversion to lower case.

auth_username_format = %Ln

With Dovecot delivering the emails to their inbox, the “recipient_delimiter” must be set as it is in postfix to allow LMTP to properly extract the user part from the email address. Even though this setting is part of the sieve configuration file, it is also used by LMTP as the comment states. The /etc/dovecot/conf.d/90-sieve.conf contains the “recipient_delimiter” setting.

plugin {
  # The separator that is expected between the :user and :detail
  # address parts introduced by the subaddress extension. This may
  # also be a sequence of characters (e.g. '--'). The current
  # implementation looks for the separator from the left of the
  # localpart and uses the first one encountered. The :user part is
  # left of the separator and the :detail part is right. This setting
  # is also used by Dovecot's LMTP service.  
  recipient_delimiter = +
  ...
}

As a final step to setup LMTP, postfix needs to be instructed to send incoming mails for local delivery to Dovecot via LMTP. Depending on the configuration of Postfix, the “local_transport” or the ” virtual_transport” must be set accordingly.

The “virtual_transport” is the default for final delivery to domains listed with virtual_mailbox_domains.

The “local_transport” is the default for final delivery to domains listed with mydestination.

In the described setup, the “local_transport” setting needs to be used for the delivery to lmtp. The Postfix transport setting delivers emails received by postfix to Dovecot’s lmtp unix socket.

# deliver mail for users to Dovecot's LMTP socket
local_transport = lmtp:unix:private/dovecot-lmtp

To activate the changes, restart Dovecot and Postfix. Test the setup before continuing. If emails are not delivered via lmtp, the next step, where we include sieve in the delivery of the email, will not have any effect.

Setup Sieve with Dovcecot

Sieve is an email filtering language specified in RFC5228 and also described on sieve.info. The sieve filter allows you to create rules on the server which are applied when the email is delivered. Emails can be matched against rules, and the related action can mark emails or just deliver them to a different destination folder of the user’s IMAP folder structure.

The rules are written in the sieve language and stored in the email user’s home directory. This is where the sieve implementation, “dovecot-pigeonhole”, will read the filter configuration from. To install dovecot-pigeonhole, the sieve plugin for Dovecot, the following package needs to be installed.

$ yum install dovecot-pigeonhole

The additional configuration files for sieve/pigeonhole can then be found in the Dovecot configuration directory. The /etc/dovecot/conf.d/90-sieve.conf file contains the “sieve” setting which controls which file should contain the user’s rules.

plugin {
  # location of users' sieve file / their "active" sieve script
  sieve = ~/.dovecot.sieve
  ...
}

The second configuration file, /etc/dovecot/conf.d/20-lmtp.conf, enables the sieve plugin for the lmtp protocol. These settings configure the sieve filter into the delivery process so that the rules can be applied.

protocol lmtp {
  mail_fsync = optimized
  mail_plugins = $mail_plugins sieve
}

To load the changes in the configuration files and to activate the installed sieve plugin, dovecot needs to be restarted.

Testing Sieve Setup

When the above configuration is active, it is time to test the setup. I suggest creating a first Sieve filter. The filter should be written in a way to be able to test it by sending an email to yourself.

Example filters can be found at Pigeonhole Sieve examples. This page contains a number of very usefull examples showing many features and use-cases.

To test the basic functionality of the configured sieve filter, I suggest a simple filter. The following filter uses the “envelope” and the “imap4flags” extensions. The if-statement will match only when the received email is sent “from” the mentioned email address and contains the mentioned string in the “subject”.

require ["envelope", "imap4flags"];

if allof (address :is "from" "mailuser@example.com", header :contains "subject" "Test Message") {
  setflag "\\seen";
  setflag "\\Flagged";
  stop;
}

When the if-conditions match, three actions will be executed. First, the flag “\\seen” is set which marks the email as read. “\\Flagged” sets the flagged state for the email. The flagged status of a message is not shown in the same way by all mail clients. Some might not even show it at all.

Adjust the if-condition to match the email address used to test the setup and send an email. The message should arrive in the inbox already marked as read and with the flagged status.

Troubleshoot Sieve and LMTP

When a sieve filter does not behave as expected, additional logging can be enabled in the /etc/dovecot/config.d/10-logging.conf configuration file. The setting to enable more logging is called “mail_debug”.

# Enable mail process debugging. This can help you figure out why Dovecot
# isn't finding your mails.
mail_debug = yes

After the above setting is changed, dovecot needs a restart to activate the changes. With the debug setting activated, log entries similar to the ones below can be found in the mail log.

 dovecot: lmtp(28422): Debug: none: root=, index=, control=, inbox=
 dovecot: lmtp(28422): Connect from local
 dovecot: lmtp(28422): Debug: Loading modules from directory: /usr/lib64/dovecot
 dovecot: lmtp(28422): Debug: Module loaded: /usr/lib64/dovecot/lib90_sieve_plugin.so
 dovecot: lmtp(28422): Debug: auth input: mailuser system_groups_user=mailuser uid=500 gid=502 home=/home/mailuser
 dovecot: lmtp(28422): Debug: changed username to mailuser
 dovecot: lmtp(28422, mailuser): Debug: Effective uid=500, gid=502, home=/home/mailuser
 dovecot: lmtp(28422, mailuser): Debug: fs: root=/home/mailuser/mail, index=, control=, inbox=/var/mail/mailuser
 dovecot: lmtp(28422, mailuser): Debug: kCqdNP+n4VsGbwAAzku34w: sieve: using sieve path for user's script: /home/mailuser/.dovecot.sieve
 dovecot: lmtp(28422, mailuser): Debug: kCqdNP+n4VsGbwAAzku34w: sieve: opening script /home/mailuser/.dovecot.sieve
 dovecot: lmtp(28422, mailuser): Debug: kCqdNP+n4VsGbwAAzku34w: sieve: script binary /home/mailuser/.dovecot.svbin is not up-to-date
 dovecot: lmtp(28422, mailuser): Debug: kCqdNP+n4VsGbwAAzku34w: sieve: script /home/mailuser/.dovecot.sieve successfully compiled
 dovecot: lmtp(28422, mailuser): Debug: kCqdNP+n4VsGbwAAzku34w: sieve: executing script from /home/mailuser/.dovecot.sieve
 dovecot: lmtp(28422, mailuser): kCqdNP+n4VsGbwAAzku34w: sieve: msgid=<50c2ff17-7986-3638-9745-1c39b372a0c7@gmail.com>: stored mail into mailbox 'Trash'
 postfix/lmtp[28079]: A5BC2C0EA1: to=<mailuser@example.com>, relay=mail.example.com[private/dovecot-lmtp], delay=0.36, delays=0.14/0/0.07/0.15, dsn=2.0.0, status=sent (250 2.0.0 <mailuser@example.com> kCqdNP+n4VsGbwAAzku34w Saved)

Manage rules with ManageSieve

Writing and managing the rule file on the server might not be very convenient. The ManageSieve extension tries to provide a way to write rules within an email client.

The ManageSieve protocol is specified in RFC 5804. There is a Thunderbird Sieve extension implementing the ManageSieve protocol allowing you to manage the rules from the mail client.

The managesieve protocol must be enabled and configured. In the /etc/dovecot/conf.d/20-managesieve.conf managesieve can be enabled with its port set to 4190 (port 2000 is the old manage sieve port, 4190 is the new one).

# Uncomment to enable managesieve protocol:
protocols = $protocols sieve

service managesieve-login {
  inet_listener sieve {
    port = 4190
  }

  # Number of connections to handle before starting a new process. Typically
  # the only useful values are 0 (unlimited) or 1. 1 is more secure, but 0
  # is faster. <doc/wiki/LoginProcess.txt>
  service_count = 1
}

After the protocol is enabled, it needs to be configured. The following setting in /etc/dovecot/conf.d/10-auth.conf ensures that password authentication is only available via TLS as transport encryption.

# Disable LOGIN command and all other plaintext authentications unless
# SSL/TLS is used (LOGINDISABLED capability). Note that if the remote IP
# matches the local IP (ie. you're connecting from the same computer), the
# connection is considered secure and plaintext authentication is allowed.
disable_plaintext_auth = yes

Restart dovecot to activate managesieve. Verify that the managesieve service was activated successfully by checking dovecot’s listening ports.

$ lsof -i :4190 -P
COMMAND  PID USER   FD   TYPE    DEVICE SIZE/OFF NODE NAME
dovecot 7798 root   15u  IPv4 421830835      0t0  TCP *:4190 (LISTEN)
dovecot 7798 root   16u  IPv6 421830836      0t0  TCP *:4190 (LISTEN)

The “-i :4190” will only limit the report to only network port “4190”.
The “-P” shows port numbers instead of translating them to names.

If you have a firewall running, make sure the port 4190 can be accessed from your managesieve/email-client.

Installing the Thunderbird Sieve extension allows you to create and manage your Sieve filter script from within Thunderbird.

Sieve extensions

Sieve has a lot of different extensions to use. The Dovecot website Pigeonhole Sieve Interpreter has a list of extensions with links to their description.

In the test rule, the envelope was used to match the sender address and the subject. imap4flags was used to set the flagged and seen flags on the email.

There are many more extensions, such as the fileinto extension which allows to deliver the incoming email to an IMAP folder instead of the inbox or the vacation extension providing autoreply messages.


Read more of my posts on my blog at https://blog.tinned-software.net/.

This entry was posted in Mailserver and tagged , , , , . Bookmark the permalink.