Skip to main content

MSH Zimbra Rules vs Sieve: Conditions and Actions Compared

Both can read a header. Both can change a subject. Both can refuse a message. So the question comes up constantly: when there are two ways to do something on a Zimbra server, which one is right? The answer almost always follows from where each one runs, so that is where this comparison starts, before the tables.

Part of the series on Everyday Uses for Sieve Mail Filters in Zimbra.

They run at opposite ends of the mail path

MSH Zimbra Rules is a Postfix milter. It sees a message while Postfix is still receiving it over SMTP, before the message is queued and before anyone has accepted it. Sieve runs inside the mailbox server at final delivery, after Postfix, the spam filter and the virus scanner have all finished.

Sending mail server
|
| SMTP, port 25
v
Postfix (smtpd) <-- MSH Zimbra Rules runs here, during the SMTP session
|
| message accepted and queued
v
Amavis <-- spam and virus checks, adds the X-Spam-* headers
|
v
Postfix delivers over LMTP
|
v
Mailbox server <-- Sieve runs here, once per recipient mailbox
| admin "before" -> user's filters -> admin "after"
v
A folder in that recipient's mailbox

Three consequences fall out of that diagram, and between them they settle most decisions.

What the milter changes, everybody gets. It edits the message before it is delivered anywhere, so a subject marker, a header or a disclaimer is part of the message every recipient receives, on your server or someone else's. What Sieve changes exists only in the one mailbox it was delivered to. Nothing Sieve does reaches an external recipient.

Only the milter can refuse a message cleanly. It can answer 5xx during the SMTP session, so the sending server generates the bounce and nothing is ever accepted. Sieve reject runs after acceptance, which means Zimbra has to create and send the bounce itself. With a forged sender that bounce goes to an innocent third party, which is backscatter.

Only Sieve can see the spam verdict. Amavis runs after the milter, so X-Spam-Flag, X-Spam-Score and X-Spam-Level do not exist yet when a milter rule reads the message. Any rule that depends on the spam score has to be Sieve.

Conditions

MSH Zimbra Rules uses one shared set of conditions across policy, signature, disclaimer and autoresponder rules.

MSH Zimbra RulesClosest Sieve equivalent
All messagestrue
Message directionNothing built in. Compare envelope :domain "from" against your own domains
Message typeNothing built in. exists "In-Reply-To" is a rough proxy for a reply
Message senderaddress "from", or envelope "from" for the real origin
Message recipientaddress ["to","cc"], envelope "to", or me :in "to,cc"
Message recipients countaddress :count with the relational extension
Message count based on senderNone. Sieve has no memory between messages
Message count based on recipientNone, for the same reason
Message headerheader, or mime_header for the headers of MIME parts
Message sizesize :over and size :under
Message subject or body containsheader "subject" plus body :contains (Zimbra supports only :contains on body)
Attachment namemime_header on Content-Disposition or Content-Type
Attachment typemime_header on Content-Type, or bare attachment for any attachment at all
Attachment sizeNone. size measures the whole message, not one part
Attachments countNone
Schedulercurrent_time and current_day_of_week

Matching

Every MSH Zimbra Rules condition offers exact match, wildcards and regular expressions. Sieve on Zimbra has :is, :contains and :matches with * and ? wildcards, and no regular expressions at all - the regex extension is not in Zimbra's keyword registry. Anything that genuinely needs a regex has to be a milter rule.

The one Sieve cannot approximate

The two counting conditions are worth calling out, because no amount of clever Sieve gets near them. Sieve evaluates one message in isolation and remembers nothing afterwards, so "this sender has sent 200 messages in the last hour" is not expressible. That makes Message count based on sender the natural place for throttling and for catching a compromised account that has started sending in volume.

Actions

MSH Zimbra Rules policy rule actions against Sieve actions:

MSH Zimbra RulesClosest Sieve equivalent
Block messagereject or ereject, but only after acceptance
Modify subjectreplaceheader :newvalue on Subject
Rewrite subjectNone. It is regex-based and Sieve has no regex
Add recipientNone. redirect sends a copy elsewhere, it does not add a recipient to the message
Remove recipientNone
Move all recipients to BCCNone
Add attachmentNone
Remove attachments by name / type / sizeNone. Sieve can refuse the whole message, not strip a part from it
Compress attachmentsNone
Save attachmentsNone
Strip attachmentsNone
Add headeraddheader
Modify headerreplaceheader
Remove headersdeleteheader
Forward messageredirect, or redirect :copy to keep delivering as well
New messagenotify, which is far more limited
Run executableNone

Note what the three header rows have in common. Sieve's addheader, replaceheader and deleteheader come from the editheader extension, which Zimbra ships disabled (zimbraSieveEditHeaderEnabled) and documents as a feature of admin scripts. They also fail silently when it is off, which is the single most common Sieve support question. The equivalent milter actions need no such switch.

What only Sieve can do

The comparison runs the other way too. These have no milter equivalent, because they are all about one person's mailbox rather than about the message:

SieveWhat it does
fileintoPut the message in a named folder
tag, flagApply a Zimbra tag, or mark read / flagged / high priority
discardDelete it silently, with no bounce and no trace
keep, stopDeliver normally; end the script
replyAuto-reply to the sender
meMatch the account's own addresses, aliases included
addressbook, contact_rankingIs the sender in the user's contacts, or someone they have written to
conversationA thread the user started or has replied to
list, bulkMailing list traffic, bulk mail
inviteCalendar invitations, optionally by method
importance, flaggedPriority headers, and flags set earlier in the same script
X-Spam-* headersThe spam verdict, which does not exist yet at milter time

And one structural difference: users can write their own Sieve filters, in Preferences > Filters, without an administrator. Milter rules are always administered centrally. For anything that is a matter of personal taste, that alone settles it.

Choosing between them

Reach for MSH Zimbra Rules when:

  • the change must be in the message every recipient gets, including external ones - signatures, disclaimers, subject markers on outbound mail;
  • the message should be refused during the SMTP session rather than bounced afterwards;
  • the rule involves attachments as parts - stripping, compressing, saving, blocking by real content type;
  • the rule needs a regular expression, or counts messages over time;
  • the policy belongs to the organization and users must not be able to change it.

Reach for Sieve when:

  • the outcome is where a message lands in one mailbox - a folder, a tag, a flag;
  • the rule depends on the spam score or anything else amavis adds;
  • the rule is about the recipient rather than the message - their contacts, their threads, whether they were in To or only Cc;
  • the user should own the rule themselves.

Using both together

The strongest pattern uses each for what it is good at. The milter marks the message while it still can, and Sieve acts on the mark after delivery.

An Add header action stamps messages from the accounting system:

X-MSH-Category: invoice

A Sieve script then files them, and this half needs no special configuration, because reading a header has never required editheader:

require ["fileinto"];

if header :is "X-MSH-Category" "invoice" {
fileinto "Invoices";
stop;
}

This is worth knowing as a general escape hatch. Any condition the milter can express and Sieve cannot - a regular expression, a per-attachment test, a rate limit - can be reduced to a header, and Sieve can then match on that header trivially.

One direction to keep in mind: mail that Sieve sends, such as a redirect or a reply, goes back out through Postfix and therefore through the milter again. Outgoing signature and disclaimer rules will apply to auto-replies unless you add an exception, for instance with the Message header condition on Auto-Submitted.