This site is now 100% read-only, and retired.

XML logo

Sieve filters for Exim4 virtual domains
Posted by lee on Fri 29 Apr 2011 at 19:03
Tags: ,

Client-side email filtering seems useless to anyone using multiple clients for reading email - especially if they're using iPhone, iPad, and the like.

For sites deploying "virtual email" IMAP accounts, the standard solution would be to support the upload of Sieve filter files using the managesieve protocol.

If you then want to use these filters at delivery time using Exim4, you have two choices:

  • Pass off the mail delivery to a local delivery agent (that supports Sieve) using a pipe transport (e.g. Dovecot LDA)
  • Write a router/transport that uses Exim's built-in filter support

Should you want to use Exim's Sieve support there are three main caveats:

  • Sieve files accessed from redirect routers need to be readable by the uid of the process that handles the SMTP connection, (e.g. Debian-exim)
  • While the Sieve RFC specifies that files use CRLF as linebreaks, Exim filters usually require the use of LF only.
  • Exim requires that sieve filter files identify themselves with "# Sieve filter" which is not part of the Sieve spec.

The first issue can easily be solved by adding the Debian-exim user to a group that can read the Sieve files. To work around the other issues you can use "data" (rather than "file") to munge the files to be usable.

The following configuration assumes a split config, maildir directories, and an active Sieve file (or likely symlink) is available from the sieve manager (if not, it should carry on to the next router for delivery e.g. standard maildir deivery)

ACTIVE_SIEVE = /var/lib/sieve/${domain}/${local_part}/active
VACATION_DIR = /var/lib/sieve/${domain}/${local_part}/vacation
VDOM_MAILDIR = /var/vmail/${domain}/${local_part}

The following router is installed to /etc/exim4/conf.d/router/350_local_sieve

   debug_print = "R: vdom_sieve for $local_part@$domain"
   driver = redirect
   domains = +local_domains
   require_files = ACTIVE_SIEVE
   allow_filter = true
   local_part_suffix = +* : -*
   data = "#Sieve filter\n${sg{${readfile{ACTIVE_SIEVE}}}{\r}{}}"
   sieve_useraddress = "$local_part"
   sieve_subaddress = "${sg{$local_part_suffix}{^.}{}}"
   sieve_vacation_directory = VACATION_DIR
   pipe_transport = address_pipe
   reply_transport = address_reply
   file_transport = vdom_sieve_file 

Note, the redirect router allows either "+" or "-" as a suffix, which may need to be tweaked depending on site requirements.


    debug_print = "T: vdom_sieve_file for $local_part@$domain ($address_file)"
    driver = appendfile
    directory = VDOM_MAILDIR/${sg {.${sg {$address_file}{/}{.}}/} \
      {^.(INBOX|inbox)/} {}}
    maildir_format = true
    user = vmail
    group = vmail

Note: The directory line might need a little fixing to fully support Maildir, but currently it replaces "/" characters with dots and assumes "inbox" as the user maildir root.