I stopped copying to try to work out the a structure in which to understand this foolish language. The order in which Ed's document explains things doesn't quite make sense. The official spec for Sieve rfc3028 isn't much better on this point. My difficulty is that there are two special tests: anyof and allof. These two require a test list. These, however, are the only two which act that way and I therefore believe they should be handled separately and after the regular tests have been discussed.
NOTE : it appears that the CMU sieve implementation is CASE SENSITIVE with respect to the names of the tests... or at least sieveshell is. Something rejected my script when I made the tests upper-cased (as they appear below).
This hierarchy is more representative of the way I order these tests. At the top, we have the simplest useful tests. We proceed through the more specialized versions. Next comes the one odd attribute test, size. After that we have the two token constants and then finally, the operators which are implemented as tests. Operators come last because they are of no use until you have mastered the more basic tests.
One of the things that I would like to see for my own understanding is a claim that a bunch of these things are equivalent. My first reaction was that ENVELOPE and ADDRESS were identical. Further reading has convinced me that ENVELOPE is special in that it deals with the values given to the SMTP server rather than what appears in the header. Moving up the chain, ADDRESS is just a specialized version of HEADER. It is specialized to look at email addresses. I believe a nearly equivalent test could be performed by each. For example: looking for a domain could use the domain flag to the ADDRESS or you could just write "@domain" in the match string used for HEADER. Beyond this, it appears from the RFC that EXISTS may be simulated by using HEADER and checking to to see if the specified header will substring match against a zero length string (HEADER :contains ["X-Caffeine"] [""]).
:is | The ":is" match type describes an absolute match; This is the default type of matching. If the contents of the first string are absolutely the same as the contents of the second string, they match. Only the string "frobnitzm" is the string "frobnitzm". The null key ":is" and only ":is" the null value. (default) |
:contains | The ":contains" match type describes a substring match. If the value argument contains the key argument as a substring, the match is true. For instance, the string "frobnitzm" contains "frob" and "nit", but not "fbm". The null key ("") is contained in all values. |
:matches | The ":matches" version specifies a wildcard match using the characters "*" and "?". "*" matches zero or more characters, and "?" matches a single character. "?" and "*" may be escaped as "\\?" and "\\*" in strings to match against themselves. The first backslash escapes the second backslash; together, they escape the "*". This is awkward, but it is commonplace in several programming languages that use globs and regular expressions. |
:all | Match against the complete email address. (default) |
:localpart | Match against the recipient or userid part of the email address. This is the part before the at (@) sign. |
:domain | Match against just the domain of the email address. This is the part after the at (@) sign. |
:comparator "i;ascii-casemap" | Perform case insensitive, ASCII based comparison. (default) |
:comparator "i;octet" | Perform a direct octet (binary) comparison without any form of conversion. |
To do : commands. Note that commands end with semi-colons.
NOTE : every line MUST end with CRLF. No other line ending is acceptable. sieveshell appears to be quite cranky and unwilling to help on this point (say by fixing up a script it doesn't like or giving you an option to force fix).
Actions specify how the message is handled. Each action statement is terminated by a semi-colon.
There are two special actions : "keep" and "discard". When processing start, the keep flag is automatically set. This is known as "implicit keep" in the sieve RFC. The discard action turns off the implicit keep action. However, if any other action (reject, redirect, or fileinto) is taken then the value of the keep flag is ignored / over-ridden. In practice this means that if a message is given a discard action, but a later rule in the script causes the message to be filed into a folder, then the message is filed rather than discarded! The work around for this is to use and if-else block for the discard and non-discard rules and actions.
string list = [<string>, <string>, ...] string = "<chars>" test list = (<test> , <test> , ...) invert = not <test> if test { block } else { block } if test { block } elsif test { block } else { block } Match Type -- Control used in header, address, and envelope. :is | :contains | :matches -- type of match to perform EXISTS <header list> header list = string list of header names HEADER [comparator] [match-type] <header list> <key list> comparator = :comparator "i;ascii-casemap" | :comparator "i;octet" match-type = :is | :contains | :matches header list = string list of header names key list = string list of values to look for ADDRESS [address part] [comparator] [match-type] <header list> <key list> address part = :all | :localpart | :domain comparator = :comparator "i;ascii-casemap" | :comparator "i;octet" match-type = :is | :contains | :matches header list = string list of header names key list = string list of values to look for ENVELOPE [address part] [comparator] [match-type] <header list> <key list> address part = :all | :localpart | :domain comparator = :comparator "i;ascii-casemap" | :comparator "i;octet" match-type = :is | :contains | :matches header list = string list of header names -- only "to" and "from" are likely supported. key list = string list of values to look for SIZE <limit-type> <limit value> limit-type = :over | :under limit value = the number of octets. May be suffixed by "K", "M", or "G" representing a kilobyte, megabyte, or gigabyte (1024, etc) size. NOT <test> ALLOF (<test>, <test>, ..) ANYOF (<test>, <test>, ..) test = any test (exists, header, size, etc...) ACTIONS -- reject <string> fileinto <string> redirect <string> keep discard MISC -- require <string>
NOTE : it looks like the spec for the ENVELOPE test in rfc3028 is wrong. See http://www.faqs.org/rfcs/rfc3028.html. The syntax says "comparator address-part" but the example has them in the reverse order.... I'm going to assume that it should match the ADDRESS test.
copied from the MSWord document by edwardm. I've left it here for now.
Sieve is a language that can be used to create filters for email. CMU is currently using sieve on the Cyrus IMAP server.
Scripts written in Sieve are executed during final delivery, when the message is moved to the user-accessible mailbox. All Sieve scripts execute under the users access rights.
Currently, CMU has implemented a web-based GUI for creating and installing Sieve vacation notice scripts. In the future, CMU will offer web-based filtering for messages. Until then, you can create and install your own Sieve scripts to take advantage of the power Sieve offers today.
if test { block of actions }For example :
if address :is "from" "tim@example.com" { discard; }
Here the test is address :is "from" "tim@example.com", and the action block is a single action discard.