Home / Alt manpages / sieve(1)

  • sieve(1)
  • User command
  • linux

Test and Run Mail Filters Safely with GNU sieve

You will compile a Sieve filter, inspect its generated instructions, and choose between a no-action test and a real mailbox run. The examples use GNU Mailutils sieve 3.17 from the Debian or Ubuntu mailutils package. Allow about fifteen minutes if you already have a filter and a test mailbox.

You need an ordinary shell, a Sieve script, and a mailbox that the Mailutils installation can open. The first stages are read-only. The final stage can move or otherwise act on messages, so do not point it at a production mailbox until the dry run and a small test set look correct. Elevated privileges are not normally required. Use them only when your mailbox permissions genuinely require it, and prefer fixing ownership or access policy over routinely running the filter as root.

1. Check the installed command

Confirm which executable will run and record its version. This does not read or change mail:

$ command -v sieve
/usr/bin/sieve
$ sieve --version
sieve (GNU Mailutils) 3.17

The command takes options followed by one SCRIPT. GNU Mailutils provides the option names used below. Its manual page is generated for the installed package and is dated March 2024, so keep the version check with operational notes when machines may run different Mailutils releases.

Checkpoint

If command -v finds nothing, install or enable the package through your normal system administration process. Do not copy a filter into a guessed location and assume a different program has the same language support.

2. Create a small filter

A Sieve script is configuration, not shell code. This example files messages whose subject contains [list] into the mailbox named Lists; other messages are kept:

require ["fileinto"];

if header :contains "subject" "[list]" {
    fileinto "Lists";
} else {
    keep;
}

Save it as filter.siv. The require statement enables the fileinto capability used by the action. The string comparison is case-sensitive only according to the test and comparator rules in the script; do not infer that every subject variant will match this exact condition.

The filter does not create the destination mailbox in this workflow. Check that Lists exists and that the account running sieve can use it before a real run. If you are testing a new rule, use a disposable mailbox or messages you can restore.

3. Compile without touching messages

Use --compile-only to parse and compile the script, then exit:

$ sieve --compile-only filter.siv
$ printf 'compile status: %s\n' "$?"
compile status: 0

A zero status confirms that the installed program accepted the script. It does not prove that a destination mailbox exists, that a message will match, or that the account can authenticate to the mailbox.

A syntax error produces a non-zero status and a diagnostic. Fix the script and compile it again. Keep the original working copy until the replacement has passed this check; overwriting the only known-good filter is an avoidable recovery problem.

4. Inspect the compiled actions

Use --dump when you want to see the compiled representation rather than process mail:

$ sieve --dump filter.siv
   1: LOCUS
   8: TEST: header "subject" "[list]" :contains
  15: BRZ 33
  17: LOCUS
  24: ACTION: fileinto "Lists"
  31: BRANCH 47
  33: LOCUS
  40: ACTION: keep
  47: LOCUS
  54: STOP

Line numbers and instruction addresses describe this particular script and Mailutils build. The useful check is the control flow: a matching subject reaches fileinto "Lists", while the other branch reaches keep. If the dump does not reflect your intended rule, stop here and edit the script.

5. Test inline text when debugging syntax

--expression treats the command's SCRIPT argument as Sieve program text. Combined with compilation, it is useful for a short syntax probe and does not process a mailbox:

$ sieve --expression --compile-only 'if true { keep; }'
$ printf 'expression status: %s\n' "$?"
expression status: 0

Use a file for anything you intend to keep. Shell quoting is a separate failure point: single quotes protect the Sieve text here, but they also prevent shell expansion. Do not put untrusted or multi-line input into an inline command without understanding how your shell will parse it.

6. Dry-run against the intended mailbox

Once compilation and inspection are clean, use --dry-run, also named --no-actions, with the mailbox URL you normally use for this account:

$ MBOX_URL='REPLACE_WITH_YOUR_MAILBOX_URL'
$ sieve --dry-run --mbox-url="$MBOX_URL" filter.siv
$ printf 'dry-run status: %s\n' "$?"
dry-run status: 0

The manpage says --mbox-url selects the mailbox to sieve and that the default is the user's mail spool. The dry-run option prints what would be done instead of executing actions. The exact action log depends on the mailbox, filter matches and configured logging, so a zero status is the main check here. If you omit --mbox-url, you may be testing the account's default spool rather than the mailbox you had in mind.

Safety boundary

Do not mistake a dry run for a backup. It is a preview, not a copy of the messages. Preserve or export the messages you may need before a real run, and record the original mailbox location so you can recover from an incorrect rule.

7. Run a controlled real pass

Only after the previous checkpoint passes, run the same command without --dry-run:

$ sieve --mbox-url="$MBOX_URL" filter.siv
$ printf 'sieve status: %s\n' "$?"
sieve status: 0

Use a test mailbox first and inspect the resulting folders. A zero status means the command completed successfully; it is not a guarantee that your rule expressed the business decision you wanted. If actions fail on individual messages, --keep-going tells sieve to continue when execution fails on a message. That can leave a mixed result, so use it only when you have a way to identify and revisit failures.

There is no general undo option in the command described by this manpage. Recovery depends on the mail store and the action: move messages back manually if they were filed, or restore them from the backup or test copy you made before the run. To stop future changes, remove the filter from the job or wrapper that invokes it, rather than deleting message data as a first response.

8. Diagnose the common failures

If the script path is wrong, the command fails before filtering. For example:

$ sieve --compile-only /tmp/no-such-sieve-script
sieve: cannot stat `/tmp/no-such-sieve-script': No such file or directory
$ printf 'status: %s\n' "$?"
status: 78

The wording and status come from this Mailutils build. Check the path, spelling and read permission, then rerun compilation. If a filter cannot find an included library or configuration value, inspect the configured search paths and use -I or -L only when you know which directory should be added. Keep a change to search paths local to the test until the script is proven.

For action logs, --verbose logs all actions. --debug enables debug flags, whose default is TPt in this release. Diagnostics can expose message details, mailbox names or authentication context, so avoid sending verbose output to a shared log without checking its access.

Done means

  • You confirmed that GNU Mailutils sieve 3.17 is the executable being used.
  • The filter compiled successfully with --compile-only and its dump matched the intended branches.
  • You understood whether the command used the default mail spool or an explicit --mbox-url.
  • A dry run completed before any real action was allowed.
  • The real pass was tested on a recoverable mailbox, with a known backup or restoration path.
  • You know that a successful exit status confirms execution, not the correctness of every classification.