Handling Spam with Postfix, SpamAssassin, Dovecot and Sieve.

Categories: Linux

(Back to the main article)


I’ve got a personal email server running Postfix, Dovecot and SpamAssassin. Email comes in to Postfix, is passed through SpamAssassin which sets a header with the “spam score” of the email, and is then passed to the Dovecot LMTP server for delivery to the local user.

I would now like to:

  • automatically delete any email with a very high spam-score, and
  • deliver emails with middle-rated spam scores into a “spam folder” rather than the main inbox of the target account.

Sieve is the tool that can do this, and this article describes how I added Sieve to the overall setup.

Actually, Sieve is a specification of a language for writing filters in. Each mail delivery agent which supports Sieve needs to provide a suitable implemenation of the language; the Sieve implementation for Dovecot’s delivery agent is pigeonhole.

Installing Sieve for Dovecot

On Ubuntu 16.04, installation is simple:

  • apt install dovecot-sieve

Configuring Sieve for Dovecot

Sieve needs to be enabled in Dovecot for LMTP delivery, so edit /etc/dovecot/conf.d/20-lmtpd.conf:

   mail_plugins = $mail_plugins sieve

I want the spam-handling script to be applied to all mailboxes, so need to define the location of a global sieve script in /etc/dovecot/conf.d/90-sieve.conf:

   sieve_default = /etc/dovecot/sieve/default.sieve

The other defaults for Sieve are fine; the conf-file documents the options well and there is also online documentation.

The defaults also allow per-user sieve scripts in the “mail user home directory” (which is not necessarily the same as a native unix account home directory); see later for some comments on user-specific scripts.

The Spam-filtering Script

Define the global filtering script:

echo > /etc/dovecot/sieve/default.sieve << EOF
mkdir /etc/dovecot/sieve
require ["fileinto", "mailbox"];
if header :contains "X-Spam-Flag" "YES" {
    fileinto :create "Junk";

The option :create will create the target mailbox if it does not exists. Option require mailbox is needed to make this option available.

Sieve is a compiled language. Filters can be compiled “on demand”, and this is sufficient for per-user scripts (which are stored in per-user directories). However this global script is in a directory which is only writable by root, so it must be precompiled. This also allows syntax-errors to be detected early. Compilation is simple:

  • sievec /etc/dovecot/sieve/default.sieve

Configuring Dovecot Mailboxes

The Sieve script above will cause Dovecot to create the new mailbox and write the incoming email into it. However it won’t automatically be shown to client applications; for that to happen it needs to be added to the user’s “subscribed mailboxes” list. Most IMAP email clients have an option to search for existing mailboxes which are not “subscribed to”; marking them as subscribed will cause the mailbox to appear in the client UI.

To have this happen automatically, either:

  • define that specific mailbox (eg “Junk”) in /etc/dovecot/conf.d/15-mailboxes.conf and mark it as auto=subscribe, or
  • edit /etc/dovecot/conf.d/15-lda.conf to set lda_mailbox_autosubscribe=yes (this works also for LMTP delivery)


To test: send an email with special body as documented here. Unfortunately, with my (recommended) setup, spamassassin doesn’t get run on emails delivered from a user on the same domain, so the test email must be generated from some external email system.

The spamfiltering can be checked with grep "identified spam" mail.log which shows all matched emails, and their rating. Values over 10 should be discarded, values between 5 and 10 should land in the “Junk” box.

User Sieve Scripts

One use of sieve-scripts is to forward some specific emails to another account. Forwarding all emails for an account could be done via a sieve script, but is more efficiently achieved by defining the target address in /etc/postfix/virtual. On the other hand, forwarding via sieve does allow custom processing such as the above spam-filtering to be applied first.

There is a standard API for client/server communication for reading and writing sieve scripts. This allows an email-client app to submit per-user scripts to the server, allowing users to configure things like “on holiday” auto-respond messages, and auto-sorting of incoming email into subfolders. Of course most client apps will not expose a “sieve script edit window” to users, but instead a simpler interface. Various email clients have support for this protocol, including claws-mail and roundcube. These per-user scripts get saved into the user’s “mailserver home directory” which is not the same as the directory into which mail is saved, and does not require the user to have a native account on the server (though it can be configured that way).

Ubuntu packages related to user-specific sieve scripts:

  • dovecot-managesieved - also part of Pigeonhole project
  • roundcube-plugins-extra