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 Rules | Closest Sieve equivalent |
|---|---|
| All messages | true |
| Message direction | Nothing built in. Compare envelope :domain "from" against your own domains |
| Message type | Nothing built in. exists "In-Reply-To" is a rough proxy for a reply |
| Message sender | address "from", or envelope "from" for the real origin |
| Message recipient | address ["to","cc"], envelope "to", or me :in "to,cc" |
| Message recipients count | address :count with the relational extension |
| Message count based on sender | None. Sieve has no memory between messages |
| Message count based on recipient | None, for the same reason |
| Message header | header, or mime_header for the headers of MIME parts |
| Message size | size :over and size :under |
| Message subject or body contains | header "subject" plus body :contains (Zimbra supports only :contains on body) |
| Attachment name | mime_header on Content-Disposition or Content-Type |
| Attachment type | mime_header on Content-Type, or bare attachment for any attachment at all |
| Attachment size | None. size measures the whole message, not one part |
| Attachments count | None |
| Scheduler | current_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 Rules | Closest Sieve equivalent |
|---|---|
| Block message | reject or ereject, but only after acceptance |
| Modify subject | replaceheader :newvalue on Subject |
| Rewrite subject | None. It is regex-based and Sieve has no regex |
| Add recipient | None. redirect sends a copy elsewhere, it does not add a recipient to the message |
| Remove recipient | None |
| Move all recipients to BCC | None |
| Add attachment | None |
| Remove attachments by name / type / size | None. Sieve can refuse the whole message, not strip a part from it |
| Compress attachments | None |
| Save attachments | None |
| Strip attachments | None |
| Add header | addheader |
| Modify header | replaceheader |
| Remove headers | deleteheader |
| Forward message | redirect, or redirect :copy to keep delivering as well |
| New message | notify, which is far more limited |
| Run executable | None |
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:
| Sieve | What it does |
|---|---|
fileinto | Put the message in a named folder |
tag, flag | Apply a Zimbra tag, or mark read / flagged / high priority |
discard | Delete it silently, with no bounce and no trace |
keep, stop | Deliver normally; end the script |
reply | Auto-reply to the sender |
me | Match the account's own addresses, aliases included |
addressbook, contact_ranking | Is the sender in the user's contacts, or someone they have written to |
conversation | A thread the user started or has replied to |
list, bulk | Mailing list traffic, bulk mail |
invite | Calendar invitations, optionally by method |
importance, flagged | Priority headers, and flags set earlier in the same script |
X-Spam-* headers | The 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.
Related reading
- Sieve Actions in Zimbra and Sieve Conditions in Zimbra - the full Sieve vocabulary
- Conditions and exceptions and policy rule actions - the full MSH Zimbra Rules vocabulary
- Create your first rule - the
[EXTERNAL]subject marker built as a policy rule, and Tag External Mail in Zimbra - the same idea in Sieve - Rules tester - simulate a message against your rules without sending mail