Sieve: An Email Filtering Language
Extracted elements (31)
Extensions must be declared with 'require' before use, and if a required extension is unavailable the entire script must not execute. This design, borrowed from LISP and Tcl experience, ensures scripts are not silently altered by extensions the author was unaware of.
Sieve implements an 'implicit keep': if a script completes without any action that cancels the implicit keep (fileinto, keep, redirect, or discard), the message is automatically filed to the user's default mailbox. This prevents message loss from scripts that miss certain cases.
Sieve is intentionally not Turing-complete: it has no loop control structure and no functions. This makes it impossible for users to do anything more complex than simple mail filters, enabling safe server-side execution where arbitrary program execution is not permitted.
The 'else if' sequence used in C is prohibited; 'elsif' is a separate command following 'if'. This is intentional because the 'else if' construct produces a shift-reduce conflict in the grammar.
Capability strings are case-sensitive: 'foo' and 'FOO' are different capabilities. Extensions that share a common prefix MUST register that prefix ending in '-' (e.g., 'comparator-') and the prefix MUST NOT overlap any existing registrations.
Header name comparisons are always done with 'i;ascii-casemap' (case-insensitive), as defined by the message specification. The user cannot override this with a :comparator argument; comparator selection only applies to header value comparisons.
All implementations MUST support the 'i;octet' comparator (compares octets) and the 'i;ascii-casemap' comparator (treats uppercase and lowercase US-ASCII characters as equal). The default comparator when unspecified is 'i;ascii-casemap'.
Any extension to Sieve MUST define a capability string that uniquely identifies that extension. Capability strings are case-sensitive. If a new version of an extension changes functionality, it MUST use a different name.
Implementations MUST support fifteen levels of nested blocks and fifteen levels of nested test lists.
Implementations MUST support integer values in the inclusive range zero to 2,147,483,647 (2^31 - 1), but MAY support larger values. Only non-negative integers are permitted.
Implementations MUST support tests: address, allof, anyof, exists, false, header, not, size, and true. Implementations SHOULD support the 'envelope' test.
Implementations MUST support the 'keep', 'discard', and 'redirect' actions. Implementations SHOULD support 'fileinto'. Implementations MUST allow at least one keep or one fileinto.
Implementations SHOULD convert header field text from all charsets to Unicode (UTF-8) for comparisons, and MUST be capable of converting US-ASCII, ISO-8859-1, the US-ASCII subset of ISO-8859-*, and UTF-8. If conversion fails, text MAY be treated as plain US-ASCII.
The 'discard' action MUST be silent: it MUST NOT return a non-delivery notification of any kind (DSN, MDN, or otherwise).
The 'redirect' action MUST preserve existing Received headers, and the count of Received headers in the outgoing message MUST be larger than in the received message. If the incoming message has an empty envelope sender, the outgoing message MUST also have an empty envelope sender to prevent DSN loops.
The 'require' command, if present, MUST be used before anything other than another 'require'. An error occurs if 'require' appears after any other command type. Implementations MUST NOT execute any test or command after a 'require' if one of the required extensions is unavailable.
When an error occurs, implementations MUST notify the user that an error occurred and which actions (if any) were taken, and perform an implicit keep. All processing stops when an error occurs.
Address-part arguments :localpart, :domain, and :all specify which portion of an email address to compare against. The default is ':all'. If an address is syntactically invalid, it will not be matched by :localpart or :domain tests.
Match types :is (exact), :contains (substring), and :matches (wildcard with '*' and '?') control string comparison behavior. Commands default to ':is' if no match type is supplied. It is an error to use ':contains' or ':matches' with a comparator that does not support substring matching.
Tagged arguments begin with ':' followed by a tag name (e.g., ':contains'). They must appear before positional arguments but may appear in any order relative to other tagged arguments. They SHOULD NOT take other tagged arguments as their own arguments.
The 'envelope' test matches against the SMTP envelope (MAIL FROM for 'from', RCPT TO for 'to'). The null reverse-path matches as the empty string. All envelope tests MUST drop source routes. The capability string is 'envelope'.
The 'fileinto' action delivers the message to a specified mailbox string. If the implementation uses a different encoding than UTF-8 for mailbox names, it SHOULD reencode from UTF-8. The capability string is 'fileinto'.
This document creates and updates the IANA Sieve Extensions registry. Vendor-controlled names beginning with 'vnd.' may be registered first-come, first-served. Names not beginning with 'vnd.' require a standards-track or IESG-approved experimental RFC. Initial registrations: encoded-character, fileinto, envelope, comparator-* (prefix).
This document registers the MIME media type 'application/sieve' for Sieve scripts. File extensions are '.siv' and '.sieve'. Encoding: most scripts are UTF-8 text; quoted-printable is appropriate for 7-bit transport.
Implementations MUST implement facilities to detect and break message loops (per SMTP section 6.2), MUST provide means for administrators to limit redirect use (including limiting the number of redirects per script, with a SHOULD of 1 if no multi-destination use case exists), and MUST log redirect use to facilitate abuse tracking.
Sieve scripts MUST be protected from unauthorized modification to preserve mail system integrity. An attacker who can modify a script can cause mail to be discarded, rejected, or forwarded to an unauthorized recipient. Scripts SHOULD also be protected from unauthorized retrieval as they may expose private information such as mailbox names.
Sieve evaluation proceeds through commands in order; the implicit keep state starts as active. Executing fileinto, keep, redirect, or discard cancels the implicit keep. If no such action fires before the script ends (or 'stop' is reached), the implicit keep is taken, delivering to the default mailbox.
Multi-line strings start with the token 'text:' followed by CRLF and end with CRLF, '.', CRLF. Lines within are dot-stuffed: an extra '.' is added before any line beginning with '.', and the server removes these extra dots. The CRLF before the final period is part of the value.
Numbers are decimal integers optionally suffixed with 'K' (×1024), 'M' (×1,048,576), or 'G' (×1,073,741,824) as power-of-two multipliers. The grammar rule is: number = 1*DIGIT [ QUANTIFIER ], where QUANTIFIER = 'K' / 'M' / 'G'.
Quoted strings are delimited by double-quote characters (US-ASCII 34). Inside, '\"' represents a double-quote and '\\' represents a backslash. Scripts SHOULD NOT escape other characters with a backslash; undefined escape sequences like '\a' are interpreted as just 'a'.
The encoded-character capability enables two escape syntaxes in strings: '${hex:HH...}' embeds arbitrary octets by hex pairs, and '${unicode:HHHH...}' embeds UTF-8 encoded Unicode characters by code point. Unicode values outside 0–D7FF and E000–10FFFF are errors.