How can I filter my email with Sieve server-side filters?

This page is showing a generic answer.
To see a more detailed answer customized for you, type your e-mail address here:

Our servers support Sieve email filtering. You can filter incoming email messages as they’re being delivered to a mailbox on our servers.

On this page:

What can I do with Sieve?

Sieve is a powerful mail filtering system that, among other things, allows you to store mail in particular folders on the server. You can then view the folders using Webmail or another IMAP mail program. This allows you to sort your mail even if you use a mail reader like the iPhone that doesn’t directly support filtering.

Note that you can’t view server mail folders using a POP mail connection — you can only see them with Webmail and IMAP. You probably won’t want to use Sieve filters if you read email using POP (unless the only thing you’re trying to do is put some messages in your “Trash” folder on the server, meaning you don’t care if you never see them at all through your POP connection).

How does Sieve work?

Sieve filters are made up of simple rules, like “put all messages from Amazon.com into the email folder named ‘Amazon’”. The rules are written in the text-based Sieve “scripting language”.

You can write Sieve rules from scratch yourself, borrow rules from examples like the ones below, or use software that makes it easier. Some mail programs (or mail program “plugins”) can create Sieve rules for you.

However you create them, the rules need to be put in a text file that is placed on our servers. Some software can automatically put the file in the right place so you don’t need to worry about the files.

Note that Sieve filtering is different from client-side filtering rules that you might create in Webmail, Thunderbird, Outlook, or any other mail program. Those only affect mail that the client software sees. Sieve instead acts on messages at the mail server level when they arrive on our servers, before they’re seen by any mail software.

Sieve filtering for individual mailboxes

To use Sieve filtering for address@example.com, you’d place the Sieve script file at this location in the mailbox directory:

/home/ex/example.com/mailstore/address/mailbox.sieve

You can do that using an FTP connection to your home directory, or by using SFTP or a shell connection (both of which always have access to your home directory). However, we also support (and recommend) using “Manage Sieve”, which allows you to manage the scripts using the Sieve add-on for Thunderbird and other Sieve management programs. Those programs automatically put the file in the right place.

Sieve filtering for an entire domain name

In addition to filters for each mailbox, it’s possible to create filters that apply to all addresses at your domain name. This is done by placing script files named “domain-before.sieve” and/or “domain-after.sieve” in your domain’s home directory:

/home/ex/example.com/domain-before.sieve
/home/ex/example.com/domain-after.sieve

You can put these on the server using an FTP connection to your home directory, or by using SFTP or a shell connection (both of which always have access to your home directory).

A “domain-before.sieve” script (if one exists) runs before any per-mailbox “mailbox.sieve” script, and a “domain-after.sieve” script (if one exists) runs after. So when a message arrives, three different Sieve script files will be searched for and used if present, in this order:

/home/ex/example.com/domain-before.sieve
/home/ex/example.com/mailstore/address/mailbox.sieve
/home/ex/example.com/domain-after.sieve

Each script is used only if a previous script didn’t discard the message or file it into a folder, so the order matters. If you want to create domain-wide rules that override “mailbox.sieve” scripts, you’d put them in the “domain-before.sieve” script. To create domain-wide rules that are used only if “mailbox.sieve” doesn’t do anything, you’d put them in “domain-after.sieve”.

Sieve example rules

Here are some example rules to show what can be done with Sieve filtering.

Messages from a certain sender address

File a message from “someone@example.org” into a folder named “Someone”:

require ["fileinto", "mailbox"];
if address "From" "someone@example.org"
{
    fileinto :create "INBOX.Someone";
}

The “fileinto :create” rule creates the folder if necessary (you may need to restart your email program, or tell it to “subscribe to the IMAP folders”, to see the newly created folder).

Folder names should always start with “INBOX”

Note that the top level “Inbox” folder in Sieve is named INBOX, and folders “under” the Inbox are specified by prepending INBOX. before the name. So a folder shown as “Someone” in your mail program has a Sieve name of INBOX.Someone.

If you want the rule to file messages only into folders that you’ve already created, omit the “create”:

require "fileinto";
if address "From" "someone@example.org"
{
    fileinto "INBOX.Someone";
}

This next example shows how to file messages from any address @example.org into the Trash folder (which is dangerous!) using the “:domain” test to check only the part after the @ sign:

require "fileinto";
if address :domain "From" "example.org"
{
    fileinto "INBOX.Trash";
}

And this example does the same thing in a different way, by checking whether the full “From” header address “contains” @example.org:

require "fileinto";
if address :contains "From" "@example.org"
{
    fileinto "INBOX.Trash";
}

Messages to a certain address

File a message to “personal@example.com” into a folder named “Personal”:

require ["fileinto", "mailbox"];
if address "To" "personal@example.com"
{
    fileinto :create "INBOX.Personal";
}

File a message that’s CCed to “personal@example.com” into a folder named “CCs”:

require ["fileinto", "mailbox"];
if address "CC" "personal@example.com"
{
    fileinto :create "INBOX.CCs";
}

The difference between header addresses and envelope addresses

The examples above using the “address” test only work if that address actually appears in the “From”, “To” or “CC” headers of a message. It’s possible for you to receive a message where your address doesn’t appear in either header because it’s been BCCed to you (possibly through a mailing list that effectively BCCs all mail). The “envelope to” test can be used for that, because it tests the address the message actually arrived for:

require ["envelope", "fileinto", "mailbox"];
if envelope "To" "personal@example.com"
{
    fileinto :create "INBOX.Personal";
}

In general, the “envelope to” test is the most reliable if you’re checking which address a message was sent to.

Similarly, each message has what’s called an “envelope sender” or “Return-Path” address that’s normally invisible unless you view the full headers of a message. This address is usually the same as the “From” header address, but it can sometimes be different, especially with spam or mailing lists. The “envelope from” test can be used to match that:

require ["envelope", "fileinto", "mailbox"];
if envelope "From" "someone@i-dont-like.com"
{
    fileinto :create "INBOX.Trash";
}

if envelope :domain "From" "spammer.com"
{
    fileinto :create "INBOX.Spam";
}

Messages from a name

You might want to filter all messages that include a certain name in a message’s “From”, regardless of what address it comes from. To do that, use header :contains "From":

require ["fileinto", "mailbox"];
if header :contains "From" "George Washington"
{
    fileinto :create "INBOX.Revolutionary Correspondence";
}

Detecting BCCs

One thing you might notice is that most of the spam you get appears to have been BCCed to you: your address doesn’t appear in the “To” or “CC” headers of a message. The same is true of most (but not all) mail from mailing lists.

You can detect a lot of this automated mail with this rule:

require ["fileinto", "mailbox"];
if not address ["To", "CC"] "address@example.com"
{
    fileinto :create "INBOX.Low Priority";
}

Conversely, this detects mail that is not BCCed to you, simply removing the “not”:

require ["fileinto", "mailbox"];
if address ["To", "CC"] "address@example.com"
{
    fileinto :create "INBOX.High Priority";
}

Detecting mailing lists

Well-behaved mailing lists contain an invisible “Precedence” email header with a value of “list”, and/or contain a “List-Id”. Other automated mail includes a precedence header of “bulk”.

Here’s a rule that files mail that has any of these characteristics:

require ["fileinto", "mailbox"];
if anyof
    (
        header "Precedence" "list",
        header "Precedence" "bulk",
        exists "List-Id"
    )
{
    fileinto :create "INBOX.Low Priority";
}

SpamAssassin

This example files a message that receives a SpamAssassin score of 9 or higher in a folder named “Spam”:

require ["fileinto", "mailbox"];
if header :contains "X-Spam-Level" "*********"
{
    fileinto :create "INBOX.Spam";
}

This slightly more complicated example uses the Sieve “allof” command to file a spam message only if the subject or body doesn’t contain the word “tiger”:

require ["body", "fileinto", "mailbox"];
if allof
    (
        header :contains "X-Spam-Level" "*********",
        not header :contains "Subject" "tiger",
        not body :contains "tiger"
    )
{
    fileinto :create "INBOX.Spam";
}

And this example avoids treating a message as spam if the sender’s address is whitelisted:

require ["fileinto", "mailbox", "regex"];
if allof
    (
        header :contains "X-Spam-Level" "*********",
        not header :regex "X-TigerTech-Spam-Status" "sender [[:graph:]]+ whitelisted"
    )
{
    fileinto :create "INBOX.Spam";
}

You can also flag a message if it matches a certain SpamAssassin rule. For example, this catches any message that triggers SpamAssassin’s “talks about lots of money” rule, comes from Yahoo, and don’t contain “example.com” in the "To" or "CC" header (meaning it was BCC:ed to you):

require ["envelope", "fileinto", "mailbox"];
if allof
    (
        header :contains "X-Spam-Status" "BILLION_DOLLARS=",
        envelope :domain "From" "yahoo.com",
        not address :domain ["To", "CC"] "example.com"
    )
{
    fileinto :create "INBOX.Spam";
}

This example works a little differently: it adds an X-Spam-Flag: YES header to any message that has a SpamAssassin score of 7 or above, replacing any existing header of the same name:

require ["editheader"];
if header :contains "X-Spam-Level" "*******"
{
    deleteheader "X-Spam-Flag";
    addheader "X-Spam-Flag" "YES";
}

This isn’t useful by itself, but could be useful if you configure other software to look for that header. For example, the Apple Mail software will check for that header in messages sent by anyone not in your contact list if you turn on its “Trust junk mail headers in messages” option.

Modifying a message’s subject

We should first mention that we don’t recommend modifying the subject of a message, because doing so can make it impossible for other software to verify DKIM signatures. But if you’re aware of that problem and want to do it anyway, you can modify subjects using deleteheader and addheader, described in this tip on superuser.com.

Here’s an example that appends "[SPAM]" to the subject of a message:

require ["editheader", "variables"];

# store the original subject in a variable that later rules can use
if header :matches "Subject" "*"
{
    set "subject" "${1}";
}

if header :contains "X-Spam-Level" "*******"
{
    # delete the orginal subject...
    deleteheader "Subject";
    # ... and replace it with the stored subject plus "[SPAM]"
    addheader :last "Subject" "${subject} [SPAM]";
}

Plus addressing

If your email address is “address@example.com”, our servers accept mail sent to tagged addresses like “address+something@example.com”, where “something” can be any text you want.

You can file messages based on the “+something” part, called a “subaddress” in Sieve:

require ["envelope", "fileinto", "mailbox", "subaddress"];

# file address+amazon@example.com into "Amazon" folder
if envelope :detail "to" "amazon"
{
    fileinto :create "INBOX.Amazon";
}
# file address+ebay@example.com into "eBay" folder
if envelope :detail "to" "ebay"
{
    fileinto :create "INBOX.eBay";
}

Flag a message

Flag a message from a certain sender so that it’s highlighted in the Inbox of many IMAP mail programs, including Webmail:

require ["imap4flags"];
if address "From" "someone@example.org"
{
   setflag "\\Flagged";
}

Mark a message as “seen”

Mark a message as “seen” or “already read” so that it doesn’t show as a new unread message:

require ["imap4flags"];
if address "From" "someone@example.org"
{
   setflag "\\Seen";
}

You can also combine this with rules that file messages into folders, so the folders don’t show any unread messages:

require ["fileinto", "mailbox", "imap4flags"];
if address "From" "someone@example.org"
{
   setflag "\\Seen";
   fileinto :create "INBOX.Trash";
}

Discarding all new mail

We occasionally hear from customers who need to keep all existing mail in a mailbox (perhaps for legal reasons), but want to discard all new mail, and don’t even want it to take up disk space in the Trash. You can do this with a sieve file containing this single line:

discard;

This is, of course, very dangerous. There’s no way to get it back if you do this.

Handling “bounces”

If a spammer forges your address and you get a lot of “bounces”, you can put them in a separate folder:

require ["envelope", "fileinto", "mailbox"];
if envelope :matches "From" [
    "MAILER-DAEMON",
    "MAILER-DAEMON@*",
    "postmaster@*"
    ]
{
    fileinto :create "INBOX.Bounces";
}

“Mailbombing” signups

Occasionally we hear from people who are the victim of “mailbombing”, where people try to sign you up for many lists, bombarding you with messages asking you to confirm the subscriptions.

This is a difficult situation to deal with, but something like this could filter many of them:

require ["fileinto", "mailbox"];
if header :contains "Subject" [
  "confirm your subscription",
  "confirmation of subscription",
  "subscription confirmation",
  "please confirm subscription",
  "confirmation instructions",
  "confirm mailing list subscription",
  "Copy of: "
  ]
{
    fileinto :create "INBOX.Signups";
}

if header :contains "X-Spam-Status" "TT_NEW_SENDING_DOMAIN="
{
    fileinto :create "INBOX.Signups";
}

(The TT_NEW_SENDING_DOMAIN SpamAssassin rule matches messages from senders that our servers have never seen before.)

Forwarding messages

You can forward a copy of a message to a different address using Sieve. This example sends a copy of the message to a different address, saving the original in your Inbox, too:

require ["copy"];
if header :contains "Subject" "tiger"
{
    redirect :copy "other@example.net";
}

This version saves a copy of the forwarded message in a folder:

require ["copy", "fileinto", "mailbox"];
if header :contains "Subject" "tiger"
{
    redirect :copy "other@example.net";
    fileinto :create "INBOX.Forwarded Messages";
}

Whereas this much more dangerous example sends a copy to another address and discards the original without putting it in your Inbox:

if header :contains "Subject" "tiger"
{
    redirect "other@example.net";
}

It’s wise to always include the “:copy” to avoid deleting the original. If you really think you don’t want to keep a copy of forwarded messages, you might want to put them in the Trash instead of discarding them, so you can retrieve them if something goes wrong:

require ["copy", "fileinto"];
if header :contains "Subject" "tiger"
{
    redirect :copy "other@example.net";
    fileinto "INBOX.Trash";
}

Using regular expressions (regex)

Sometimes, just knowing whether a message contains certain specific text isn’t sufficient. You can match more complicated patterns using Sieve’s “regex” rules.

This example looks for messages that have a blank subject and only a link in the message body (which is a common spam pattern):

require ["regex", "body", "fileinto"];
if allof (
  not header :regex "Subject" "[[:graph:]]",
  body :regex "^[[:space:]]*http://[[:graph:]]+[[:space:]]*$"
  )
{
  fileinto "INBOX.Trash";
}

This first checks that the message subject does not contain any printable characters, then checks that the message body contains only “http://” followed by one or more printable characters, possibly surrounded by spaces (but nothing else) on both sides.

Blocking certain filenames or attachments

Sieve lets you examine the filenames and MIME types of attachments. This example matches any message with an ".exe" or ".bin" file attachment:

require ["mime", "foreverypart", "fileinto"];
foreverypart
{
  if header :mime :anychild :param "filename" :matches "Content-Disposition" [ "*.exe", "*.bin" ]
  {
    fileinto "INBOX.Trash";
  }
}

(The Sieve syntax for this is admittedly very complex; what this does is “look in the Content-Disposition header of each MIME part and see if it contains a filename=something.exe or filename=something.bin”.)

Alternately, you can search by the MIME type of the attachment. This matches messages with a Content-Type: video/mp4 MIME attachment, for example:

require ["mime", "foreverypart", "fileinto"];
foreverypart
{
  if header :mime :anychild :contenttype "Content-Type" "video/mp4"
  {
    fileinto "INBOX.Trash";
  }
}

Note that unlike our general malicious filetype blocking, this kind of thing only catches top-level filenames, and can’t “look inside” a .zip file, for example.

Learning more about Sieve

Other samples, and much more information, can be found on the Sieve home page.

The Sieve “reject” action

Some versions of Sieve offer a “reject” action, which creates a new outgoing “bounce” message to the person who sent the original email.

We intentionally do not support “reject”. This is because it’s very difficult to tell who the true sender of a message is — in particular, if a message is spam, the spammer almost certainly forged the sending address.

If you used a “reject” action, you’d end up sending copies of spam to innocent strangers (this is called backscatter). Those strangers will complain to their ISP, who will block all mail from your domain name. You’ll then be unable to send any email to people who use AOL, or Comcast, or another large site. This is not what you want.

Instead of using “reject”, file the message into a folder (or use “discard” if you’re feeling brave, although we’d never do that ourselves).

What settings should I use with the Mozilla Thunderbird Sieve add-on?

The Sieve add-on for Thunderbird is a useful and free way of managing Sieve scripts from the Thunderbird email program.

The correct settings for the add-on in the “Server” and “Security” screens are:

Server Name:IMAP Server: mail.tigertech.net
Server Port:4190 (Default)
Connection Security:Force TLS
Username:IMAP Username and Password

The other settings should usually be left alone, at their defaults.

If you have trouble connecting to the server, make sure that the “Proxy” setting is Direct Connection; we’ve seen a couple of cases where it somehow gets set to use a proxy instead.

How can technically advanced users see what Sieve rules match against certain messages?

If you just want to see what Sieve would do with each message in your INBOX or another folder, you can run the "sieve-filter" test program from the command line shell like these examples:

sieve-filter -v -C -u address@example.com ~/domain-before.sieve INBOX
sieve-filter -v -C -u address@example.com ~/mailstore/address/mailbox.sieve INBOX.Sent
sieve-filter -v -C -u address@example.com ~/domain-before.sieve INBOX.Sent

If you need more details about which rules match, or you need to examine mail files outside your normal folders, a program named “sieve-test” can be used. For example:

cd ~/mailstore/address/cur
sieve-test ~/domain-before.sieve 1234567890.M957459P6285:2

This example shows exactly which rules match every message in that directory:

for a in 1*; do
  echo $a:
  sieve-test ~/domain-before.sieve $a 2>&1
done | less

Some technical notes

Sieve rules can be complicated, and there’s a lot to remember. Here are some notes about Sieve features that we often have to look up ourselves:

  • You can specify a mail subfolder by listing all of the folders on the “path” to the subfolder, each separated by a dot. For example, if you have a folder named “Travel” which then has a subfolder named “Summer Vacation”, you can specify the subfolder using fileinto "INBOX.Travel.Summer Vacation".
  • The different comparisons available are :is (an exact, full match — recommended for full addresses or domain names), :contains (matches a substring), :matches (a full match that allows DOS-style wildcards ? and *), and :regex (which matches regular expressions). If you don’t specify a comparison, :is will be used, so header :is "Subject" "Spam" does the same thing as header "Subject" "Spam".
  • By default, string comparisons are case-insensitive. Checking address "From" "address@example.com" does the same thing as checking address "From" "address@EXAMPLE.COM". (If you really want case-sensitive comparisons, RFC 3028 section 2.7.3 explains how.)
  • By default, the Sieve body check presents the message body as a single line string that contains no carriage returns or line feeds, allowing you to easily match regex rules against the entire message as in the “body :regex” example above.