Message Filtering
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:
Here are some example filters, all will be explained below
Simple | # Exim filter deliver paul.valle@datadisk.co.uk Note: standard .forward file instructing to deliver to the above address |
Vacation handling | # 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" then save $home/mail/f+e endif |
Discarding Messages | # Exim filter if $sender_address contains "@spam.address" and $sender_address does not contain "postmaster@" then seen finish endif |
Mulitple personal mailboxes | # Exim filter if $local_part_suffix is "-foo" then save $home/mail/foo elif $local_part_suffix is "-bar" then save $home/mail/bar endif |
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 paul.valle@datadisk.co.uk <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 |
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 paul.valle@datadisk.co.uk Note: deliver is the keyword and paul.valle@datadisk.co.uk 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) |
if | test condition |
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 example | ## 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 example | ## deliver <mail address> deliver paul.valle@datadisk.co.uk |
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 example | ## 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 example | ## 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 Note: 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 example | ## logfile <file name> logfile $home/filter.log |
logging to a different file | warn 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 example | ## 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> ## endif |
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 |
|
number testing | <number1> is above <number2> |
Other Test Conditions |
|
personal mail | personal |
significant actions | if not delivered than save mail/anomalous |
error message | if error_message then finish endif |
list of addresses | foranyaddress <string> (<condition>) |
The fail command prevents any deliveries of the message from taking place
fail example | ## 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 example | ## 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
header example | ## headers add <text> headers add " - $primary_hostname" |