As a message passes through Exim, it can be inspected by a number of different filters, filters work as follows:
Sieve is now the standard for filtering which is defined in RFC3028. The first line of users filter determines which kind of filter it is:
Example of Filter Commands
Here are some example filters, all will be explained below
|Simple||# Exim filter
Note: standard .forward file instructing to deliver to the above address
# Exim filter
Note: pass the message via a pipe using the above command
|Vacation handling||# Exim filter
if personal then vacation endif
Note: this is being handle entirely by a Exim filter without running another program
|Sort into different mailboxes||# Exim filter
if $header_subject: contains "empire" or $header_subject contains "foundation"
|Discarding Messages||# Exim filter
if $sender_address contains "@spam.address" and $sender_address does not contain "postmaster@"
|Mulitple personal mailboxes||# Exim filter
if $local_part_suffix is "-foo"
elif $local_part_suffix is "-bar"
Users filters are handled by the redirect router as an alternative form of forwarding information.If the allow_filter option is set foe the router and the first line of the redirection begins with
the file is interpreted as a filter instead of a normal forwarding file. You can stop filtering using the options forbid_sieve_filter and forbid_exim_filter. You can disable certain features
A system filter differs from a users filter in that it only runs once per delivery process, you enable a system filter by specifying the system_filter option. Sieve filtering cannot be used for system filtering.
|System filter example||system_filter = /etc/mail/exim.filter|
There are a number of other options available
You should always test your filters, Exim has a way to test both exim and sieve filters before implementing them, you can also use this method to test .forward files.
|Testing a Filter||# exim -bf new-filter <test-message
# exim -bvf new-filter <test-message ## adding verbose
# exim -bf new-filter -f firstname.lastname@example.org <test-message ## specify the sender
# exim -bF system-filter <test-message ## test a system filter
There are a number of options you can pass to the exim command to change the address
|change the domain||-bfd|
|change the local part||-bfl|
|specify the prefix||-bfp|
|specify the suffix||-bfs|
Format of Exim Filters
The first line of an Exim filter must be the following, this distinguishes it from a Sieve filter or a .forward file.
The remainder of the filter is a sequence of commands, these consist of keywords and data values seperated by whitespace or line breaks, except when using conditional statements like if.
|filter command||deliver email@example.com
Note: deliver is the keyword and firstname.lastname@example.org is the data value
There are a number of fileter commands
|add||increament a users variable|
|deliver||deliver to an email address|
|fail||fail delivery (system filter only)|
|finish||end filter processing|
|freeze||freeze delivery (system filter only)|
|headers||add/remove header lines (system filter only)|
|logfile||define log file|
|logwrite||write to log file|
|send a message|
|pipe||pipe to a command|
|save||save to a file|
|testprint||print while testing|
|vacation||a special version of mail|
The add command provides a basic means of counting within a filter, the syntax is as follows
## add <number> to <user variable>
add 2 to n3
The names of the user variables consist of the letter n followed by a single digit, therefore there are 10 user variables n0-n9, you get at the variable by using $n3. All variables are initialized with zero to start with, at the end of a system variable their values are copied into $sn0-$sn9 so they can be referenced in users filters. You can subtract by using a negative number.
The deliver command sets up message deliveries, such deliveries are significant actions unless the command is preceded by unseen
## deliver <mail address>
The above example is the same as putting a forwarding address in the .forward file.
The save command causes a copy of the message to be appended to the given file, you can use multiple save commands, however this may be forbidden by setting the forbid_file on the router.
## save <file name>
save $home/mail/vallep ## system filter you must use an absolute path
Again there are a number of router options that can affect the save command: filter_prepend_home, system_filter_directory_transport, directory_transport.
The pipe command causes a seprate process to be run, and a copy of the message is passed to it on its standard input.
## pipe <command>
pipe "/usr/bin/countmail $sender_address" ## use a script to count mail
You can ignore deliver error messages by using unseen with noerror
|ignoring error messages||unseen noerror pipe $home/bin/mailscan
unseen - ensures normal delivery is not affected
noerror - ensures that a failure of the pipe doe not cause a bounce message to be generated
The mail and vacation commands sends a message
|mail and vacation example||
## mail to <address-list>
mail text "Got you message about $h_subject:"
vacation once_repeat 14d ## send a message 14 days after the last one was sent
The logfile can keep the actions taken by a filter, again some options can impact the logfile command. The logfile is updated immediately while the filter is running, the logwrite command write to the specified logfile
## logfile <file name>
|logging to a different file||
Note: the :reject: means that this will be logged to the reject log instead of mainlog. you can point to any of the logfiles (mainlog, reject and panic), you can also write to a number of logfiles at the same time using :main,reject:
:reject: - write to the reject logfile
The testprint command enable you to print out variable values, it has no impact on the mail being delivered
## testprint <text>
testprint "home=$home reply_address=$reply_address"
The finish command which has no arugements, causes Exim to stop interpreting the filter
It is possible to have conditional statements in a filter
|conditional if||## if <condition>
## then <commands>
## elif <condition>
## then <commands>
## else <commands>
String Test Conditions
|start of string||<text1> begins <text2>
<text1> does not begin <text2>
|end of string||<text1> ends <text2>
<text1> does not end <text2>
|exact string||<text1> is <text2>
<text1> is not <text2>
|partial string||<text1> contains <text2>
<text1> does not contain <text2>
|regular expression string||<text1> matchess <text2>
<text1> does not match <text2>
Number Test Conditions
<number1> is above <number2>
Other Test Conditions
|significant actions||if not delivered than save mail/anomalous|
|error message||if error_message then finish endif|
|list of addresses||foranyaddress <string> (<condition>)|
Additional System Filters
The fail command prevents any deliveries of the message from taking place
## fail text <text>
fail text "admin rejection"
The freeze command prevents any deliveries other than those previously set up in the filter from taking place
## freeze text <text>
freeze text "admin rejection"
The headers command add's or remove's the text to the end of the message's header line
## headers add <text>
headers add " - $primary_hostname"