Summary

  • RFC 5231 added ordered :value comparisons and :count tests to Sieve’s existing address, envelope and header tests. The number produced by :count depends on which test parses the message.
  • Address counts are mailbox elements, envelope counts are transport addresses, and header counts are field instances—not the addresses inside those fields. An envelope to test intentionally sees only the current user.

“How many recipients?” was not one question

Look at an email’s To: line and a count seems straightforward. If it lists two mailboxes, there are two recipients. But a mail filter does not operate on the social impression of a line. It sees a message header, an SMTP envelope and parsed address structures, each with different meaning and authority.

RFC 5231, published in January 2008, gave Sieve’s existing address, envelope and header tests a relational vocabulary. Instead of asking only whether a value matched, a script could ask whether it was greater than, less than, equal to or different from a test value. The extension introduced two match types: :value, which compares strings under a comparator with sorting information, and :count, which counts selected entities before comparing the number.

The new operators were gt, ge, lt, le, eq and ne. For :value, a parsed value from the message is the left side of the relation; a value in the script’s key list is the right side. Where either side contains several values, any pair that satisfies the relation makes the test true. Sorting was not a universal natural-language operation: the selected comparator mattered. RFC 5231 required support for i;ascii-numeric, including at least 32-bit unsigned numbers; that comparator does not represent negative values.

The more revealing change was :count. Consider a message with two mailbox entries in To: and one in Cc:. An address :count test over to and cc counts three mailbox elements. Group labels do not add to the total, though mailboxes inside a group do. Ask instead for a header :count over to and cc, and the test counts header-field instances. In an ordinary RFC 2822-compliant message with one To: field and one Cc: field, that result is two—not three people.

The envelope :count test counts yet another thing: addresses in the selected transport-envelope parts. The envelope’s to always contains one address—the user for whom that Sieve script is running. The specification requires that this test not reveal whether the message was delivered to somebody else. Its envelope from count is zero for an empty SMTP MAIL FROM and one otherwise. So “count the recipients” can mean mailboxes visible in a header, an envelope address available to this script, or header lines. The test name alone does not choose among them.

That distinction also changes how conditions compose. A single address count over to and cc adds the two mailbox counts together. If the rule is “at least three in To, or at least three in Cc,” the script needs two comparisons inside anyof; a combined count would answer the different question “at least three across both fields.” The RFC’s worked example shows the combined test returning true for a two-address To plus one-address Cc, while the two separate threshold tests return false.

RFC 5231 did not invent relational Sieve from scratch. It obsoleted RFC 3431, which had already introduced the relational extension and both match types in 2002. The successor updated the comparator reference from ACAP to the Internet Application Protocol Collation Registry in RFC 4790, corrected examples, clarified which RFC 2822 elements COUNT counts, and removed a whitespace-trimming rule after a broader requirement was added to the Sieve base specification. The relational capability was recorded in the IANA Sieve Extensions registry.

And the extension stopped at testing. It did not alter implicit KEEP or any explicit action such as fileinto, redirect or reject. A predicate can determine which branch a script takes; it cannot by itself prove what a server parsed, whether it executed the branch correctly, or where the message was ultimately delivered. That separation is the practical boundary: a precise comparison language is useful only when its unit, comparator and implementation surface are all known.

Sources