Skip to main content

Zimbra Sieve Filters: An Introduction

Every mail filter in Zimbra - the rules users build under Preferences > Filters as well as the rules administrators apply to a whole domain - is a Sieve script. This article is the first in a series about Sieve on Zimbra. It explains what Sieve is, how Zimbra runs it, what a script looks like, where Zimbra keeps the scripts and how to set them up.

What is Sieve

Sieve is a small language for filtering email, standardized by the IETF in RFC 5228. The RFC defines it as a language "for filtering email messages at time of final delivery" - it runs when a message is about to be stored in a mailbox and decides what happens to it: which folder it goes to, whether it is forwarded, tagged or refused.

The language is deliberately limited. The base specification has no loops and no user-defined functions, so a script always runs once from top to bottom and can never hang the server. That makes it safe to run unattended for thousands of mailboxes, and simple enough for a graphical rule editor to generate.

Everything beyond the basics comes as an extension, each defined in its own RFC - for example variables, body tests or header editing. A script lists the extensions it uses at the top. IANA keeps the official list of Sieve extensions.

Sieve in Zimbra

Zimbra has no separate filter engine of its own. The filter editor in the web client is a graphical front end for Sieve: every rule a user creates is saved as Sieve script text.

A few facts that shape how Sieve behaves on Zimbra:

  • It runs in the mailbox server, at delivery. A message first passes through Postfix and the spam and virus checks, and only then reaches the mailbox server, where the Sieve scripts decide where it is stored.
  • The engine is Apache jSieve. Zimbra embeds Apache jSieve, a Java implementation of Sieve, and adds its own commands on top - for example tag and flag actions, and tests such as attachment or addressbook. Scripts that use them work only on Zimbra.
  • There are incoming and outgoing filters. Incoming filters handle mail delivered to the mailbox. Outgoing filters act on the sender's own saved copy of a sent message - for example to file sent mail into folders. They do not change what the recipients get.

Basic syntax

A Sieve script is a list of rules. Each rule is an if with a test that checks something about the message, and actions that run when the test matches:

require ["fileinto"];

# file invoices from our supplier into their own folder
if allof (address :domain :is "from" "supplier.example.com",
header :contains "subject" "invoice") {
fileinto "Invoices";
stop;
}

# everything from the old domain goes to the Archive folder
if address :domain :is "from" "old.example.com" {
fileinto "Archive";
}

The building blocks:

  • require - lists the extensions the script uses, such as fileinto. It comes first.
  • Tests - check the message, for example header (any header), address (sender or recipient addresses) and size.
  • Match types - how a test compares: :is for an exact match, :contains for a substring, :matches for wildcards like *@example.com.
  • allof and anyof - combine several tests: all of them must match, or at least one.
  • Actions - what happens to the message, for example fileinto (move to a folder), redirect (forward), discard (drop) or keep (deliver normally).
  • stop - ends the script, so no later rule sees the message.
  • Comments - start with #.

If no rule moves, forwards or drops a message, Sieve delivers it to the Inbox as usual - a script cannot lose mail just because nothing matched.

Where Zimbra stores Sieve scripts

Zimbra keeps each script as an attribute in its LDAP directory. There are three scripts for incoming mail and three for outgoing mail:

ScriptIncoming mailOutgoing mail
Admin script, runs before the user's filterszimbraAdminSieveScriptBeforezimbraAdminOutgoingSieveScriptBefore
The user's own filterszimbraMailSieveScriptzimbraMailOutgoingSieveScript
Admin script, runs after the user's filterszimbraAdminSieveScriptAfterzimbraAdminOutgoingSieveScriptAfter

For each message, Zimbra runs the admin "before" script, then the user's own filters, then the admin "after" script. Users never see the admin scripts and cannot change them, which makes them the place for rules that must apply to everyone.

The user's filters belong to the account. The admin scripts can be set on an account, a class of service (COS) or a domain. When more than one is set, Zimbra uses the account's own script first, then the COS script, and only then the domain script.

How to set up Sieve filters in Zimbra

In the web client - for users

Users manage their own filters under Preferences > Filters, on separate tabs for incoming and outgoing messages. Each rule is built from drop-down lists, without writing any Sieve. A filter can also be run on messages already in a folder, which is useful for trying a new rule.

The web client checks every rule when it is saved and refuses invalid ones.

In the admin console - for administrators

From Zimbra 9, the admin console can edit the admin scripts of a domain or a COS: open the domain or COS, go to Advanced and scroll to Sieve filter rules. On older versions, use the command line.

The Advanced page of the default class of service in the Zimbra admin console, with the Sieve filter rules section: the Sieve reject action and Edit header commands checkboxes, and text boxes for the Sieve rules applied before and after end user filters

On the command line

All commands run on the Zimbra server as the zimbra user (sudo su - zimbra).

Admin scripts are set with zmprov. Save the script to a file first, then:

# set the domain's "before" script from a file
zmprov md example.com zimbraAdminSieveScriptBefore "$(cat /tmp/filter.sieve)"

# show it
zmprov gd example.com zimbraAdminSieveScriptBefore

# remove it
zmprov md example.com zimbraAdminSieveScriptBefore ""

Use zmprov mc for a COS and zmprov ma for a single account in the same way.

zmprov stores the script without checking it, so a typo only shows up when mail arrives. Check the syntax before saving - for example on checksieve.com, which runs in the browser. It does not know Zimbra's own commands such as tag.

A user's own filter rules can be managed with zmmailbox, using the same building blocks as the web client instead of Sieve text:

# add a rule: file messages whose subject contains "invoice" into /Invoices
zmmailbox -z -m user@example.com addFilterRule "Invoices" active any \
header "subject" contains "invoice" fileinto "/Invoices" stop

# list the user's rules
zmmailbox -z -m user@example.com getFilterRules

Before you edit headers

Sieve can add and remove message headers with the editheader extension. On Zimbra it is switched off by default, and it works only in admin scripts, never in a user's own filters. To enable it for a COS:

zmprov mc default zimbraSieveEditHeaderEnabled TRUE

From Zimbra 9, you can also tick Edit header commands in the admin console, in the same Sieve filter rules section shown above.

Sieve and MSH Zimbra Rules

Sieve runs at the very end of the mail path, when a message is stored in a mailbox. That limits what it can do: it changes only the copy kept in the recipient's own mailbox, and outgoing filters change only the sender's saved copy. Nothing a Sieve script does reaches the recipients on other servers.

MSH Zimbra Rules works earlier, while Postfix passes the message on, so its changes are part of the message every recipient gets. That is what server-side email signatures and disclaimers need. It can also refuse a message during the SMTP session, before Zimbra accepts it.

The two work well together. A policy rule with the Add header action can mark a message, and a Sieve script can then file or tag it by that header.