<!DOCTYPE html PUBLIC "XSLT-compat"> <html lang="en-GB"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <link rel="stylesheet" type="text/css" href="../../../../common.css"> <meta name="author" content="The Exim Project. <http://www.exim.org/>"> <meta name="copyright" content="Copyright ©2010 The Exim Project. All rights reserved"> <meta name="description" content="Exim is a message transfer agent (MTA) developed at the University of Cambridge for use on Unix systems connected to the Internet."> <meta name="keywords" content="exim,smtp,mta,email"> <meta name="robots" content="noodp,noydir,index,follow"> <meta name="viewport" content="width=device-width"> <title>43. System-wide message filtering</title> <link rel="stylesheet" type="text/css" href="../../../../doc/chapter.css"> <link rel="canonical" href="http://www.exim.org/exim-html-current/doc/html/spec_html/ch43.html"> </head> <body> <h1 id="header"><a href="../../../..">Exim Internet Mailer</a></h1> <div id="outer"> <ul id="nav_flow" class="nav"> <li><a href="../../../../index.html">Home</a></li> <li><a href="../../../../mirrors.html">Download</a></li> <li><a href="../../../../docs.html">Documentation</a></li> <li><a href="../../../../maillist.html">Mailing Lists</a></li> <li><a href="http://wiki.exim.org/">Wiki</a></li> <li><a href="http://www.exim.org/bugzilla/">Bugs</a></li> <li><a href="../../../../credits.html">Credits</a></li> <li class="search"><form action="http://www.google.com/search" method="get"> <span class="search_field_container"><input type="search" name="q" placeholder="Search Docs" class="search_field"></span><input type="hidden" name="hl" value="en"><input type="hidden" name="ie" value="UTF-8"><input type="hidden" name="as_qdr" value="all"><input type="hidden" name="q" value="site:www.exim.org"><input type="hidden" name="q" value="inurl:exim-html-current"> </form></li> </ul> <div id="inner"><div id="content"> <a class="previous_page" href="ch42.html"><-previous</a><a class="next_page" href="ch44.html">next-></a><div id="chapter" class="chapter"> <h2 id="CHAPsystemfilter" class="">Chapter 43 - System-wide message filtering</h2> <p> The previous chapters (on ACLs and the local scan function) describe checks that can be applied to messages before they are accepted by a host. There is also a mechanism for checking messages once they have been received, but before they are delivered. This is called the <span class="docbook_emphasis">system filter</span>. </p> <p> The system filter operates in a similar manner to users’ filter files, but it is run just once per message (however many recipients the message has). It should not normally be used as a substitute for routing, because <span class="docbook_option">deliver</span> commands in a system router provide new envelope recipient addresses. The system filter must be an Exim filter. It cannot be a Sieve filter. </p> <p> The system filter is run at the start of a delivery attempt, before any routing is done. If a message fails to be completely delivered at the first attempt, the system filter is run again at the start of every retry. If you want your filter to do something only once per message, you can make use of the <span class="docbook_option">first_delivery</span> condition in an <span class="docbook_option">if</span> command in the filter to prevent it happening on retries. </p> <p> <span class="docbook_emphasis">Warning</span>: Because the system filter runs just once, variables that are specific to individual recipient addresses, such as $local_part and $domain, are not set, and the “personal” condition is not meaningful. If you want to run a centrally-specified filter for each recipient address independently, you can do so by setting up a suitable <span class="docbook_command">redirect</span> router, as described in section <a href="ch43.html#SECTperaddfil" title="43. System-wide message filtering">43.8</a> below. </p> <div class="section"> <h3 id="SECID212" class="">1. Specifying a system filter</h3> <p> The name of the file that contains the system filter must be specified by setting <span class="docbook_option">system_filter</span>. If you want the filter to run under a uid and gid other than root, you must also set <span class="docbook_option">system_filter_user</span> and <span class="docbook_option">system_filter_group</span> as appropriate. For example: </p> <div class="docbook_literallayout"><pre> system_filter = /etc/mail/exim.filter system_filter_user = exim </pre></div> <p> If a system filter generates any deliveries directly to files or pipes (via the <span class="docbook_option">save</span> or <span class="docbook_option">pipe</span> commands), transports to handle these deliveries must be specified by setting <span class="docbook_option">system_filter_file_transport</span> and <span class="docbook_option">system_filter_pipe_transport</span>, respectively. Similarly, <span class="docbook_option">system_filter_reply_transport</span> must be set to handle any messages generated by the <span class="docbook_option">reply</span> command. </p> </div> <div class="section"> <h3 id="SECID213" class="">2. Testing a system filter</h3> <p> You can run simple tests of a system filter in the same way as for a user filter, but you should use <span class="docbook_option">-bF</span> rather than <span class="docbook_option">-bf</span>, so that features that are permitted only in system filters are recognized. </p> <p> If you want to test the combined effect of a system filter and a user filter, you can use both <span class="docbook_option">-bF</span> and <span class="docbook_option">-bf</span> on the same command line. </p> </div> <div class="section"> <h3 id="SECID214" class="">3. Contents of a system filter</h3> <p> The language used to specify system filters is the same as for users’ filter files. It is described in the separate end-user document <span class="docbook_emphasis">Exim’s interface to mail filtering</span>. However, there are some additional features that are available only in system filters; these are described in subsequent sections. If they are encountered in a user’s filter file or when testing with <span class="docbook_option">-bf</span>, they cause errors. </p> <p> There are two special conditions which, though available in users’ filter files, are designed for use in system filters. The condition <span class="docbook_option">first_delivery</span> is true only for the first attempt at delivering a message, and <span class="docbook_option">manually_thawed</span> is true only if the message has been frozen, and subsequently thawed by an admin user. An explicit forced delivery counts as a manual thaw, but thawing as a result of the <span class="docbook_option">auto_thaw</span> setting does not. </p> <p> <span class="docbook_emphasis">Warning</span>: If a system filter uses the <span class="docbook_option">first_delivery</span> condition to specify an “unseen” (non-significant) delivery, and that delivery does not succeed, it will not be tried again. If you want Exim to retry an unseen delivery until it succeeds, you should arrange to set it up every time the filter runs. </p> <p> When a system filter finishes running, the values of the variables $n0 – $n9 are copied into $sn0 – $sn9 and are thereby made available to users’ filter files. Thus a system filter can, for example, set up “scores” to which users’ filter files can refer. </p> </div> <div class="section"> <h3 id="SECID215" class="">4. Additional variable for system filters</h3> <p> The expansion variable $recipients, containing a list of all the recipients of the message (separated by commas and white space), is available in system filters. It is not available in users’ filters for privacy reasons. </p> </div> <div class="section"> <h3 id="SECID216" class="">5. Defer, freeze, and fail commands for system filters</h3> <p> There are three extra commands (<span class="docbook_option">defer</span>, <span class="docbook_option">freeze</span> and <span class="docbook_option">fail</span>) which are always available in system filters, but are not normally enabled in users’ filters. (See the <span class="docbook_option">allow_defer</span>, <span class="docbook_option">allow_freeze</span> and <span class="docbook_option">allow_fail</span> options for the <span class="docbook_command">redirect</span> router.) These commands can optionally be followed by the word <span class="docbook_option">text</span> and a string containing an error message, for example: </p> <div class="docbook_literallayout"><pre> fail text "this message looks like spam to me" </pre></div> <p> The keyword <span class="docbook_option">text</span> is optional if the next character is a double quote. </p> <p> The <span class="docbook_option">defer</span> command defers delivery of the original recipients of the message. The <span class="docbook_option">fail</span> command causes all the original recipients to be failed, and a bounce message to be created. The <span class="docbook_option">freeze</span> command suspends all delivery attempts for the original recipients. In all cases, any new deliveries that are specified by the filter are attempted as normal after the filter has run. </p> <p> The <span class="docbook_option">freeze</span> command is ignored if the message has been manually unfrozen and not manually frozen since. This means that automatic freezing by a system filter can be used as a way of checking out suspicious messages. If a message is found to be all right, manually unfreezing it allows it to be delivered. </p> <p> The text given with a fail command is used as part of the bounce message as well as being written to the log. If the message is quite long, this can fill up a lot of log space when such failures are common. To reduce the size of the log message, Exim interprets the text in a special way if it starts with the two characters <code class="docbook_literal"><<</code> and contains <code class="docbook_literal">>></code> later. The text between these two strings is written to the log, and the rest of the text is used in the bounce message. For example: </p> <div class="docbook_literallayout"><pre> fail "<<filter test 1>>Your message is rejected \ because it contains attachments that we are \ not prepared to receive." </pre></div> <p> Take great care with the <span class="docbook_option">fail</span> command when basing the decision to fail on the contents of the message, because the bounce message will of course include the contents of the original message and will therefore trigger the <span class="docbook_option">fail</span> command again (causing a mail loop) unless steps are taken to prevent this. Testing the <span class="docbook_option">error_message</span> condition is one way to prevent this. You could use, for example </p> <div class="docbook_literallayout"><pre> if $message_body contains "this is spam" and not error_message then fail text "spam is not wanted here" endif </pre></div> <p> though of course that might let through unwanted bounce messages. The alternative is clever checking of the body and/or headers to detect bounces generated by the filter. </p> <p> The interpretation of a system filter file ceases after a <span class="docbook_option">defer</span>, <span class="docbook_option">freeze</span>, or <span class="docbook_option">fail</span> command is obeyed. However, any deliveries that were set up earlier in the filter file are honoured, so you can use a sequence such as </p> <div class="docbook_literallayout"><pre> mail ... freeze </pre></div> <p> to send a specified message when the system filter is freezing (or deferring or failing) a message. The normal deliveries for the message do not, of course, take place. </p> </div> <div class="section"> <h3 id="SECTaddremheasys" class="">6. Adding and removing headers in a system filter</h3> <p> Two filter commands that are available only in system filters are: </p> <div class="docbook_literallayout"><pre> headers add <string> headers remove <string> </pre></div> <p> The argument for the <span class="docbook_option">headers add</span> is a string that is expanded and then added to the end of the message’s headers. It is the responsibility of the filter maintainer to make sure it conforms to RFC 2822 syntax. Leading white space is ignored, and if the string is otherwise empty, or if the expansion is forced to fail, the command has no effect. </p> <p> You can use “\n” within the string, followed by white space, to specify continued header lines. More than one header may be added in one command by including “\n” within the string without any following white space. For example: </p> <div class="docbook_literallayout"><pre> headers add "X-header-1: ....\n \ continuation of X-header-1 ...\n\ X-header-2: ...." </pre></div> <p> Note that the header line continuation white space after the first newline must be placed before the backslash that continues the input string, because white space after input continuations is ignored. </p> <p> The argument for <span class="docbook_option">headers remove</span> is a colon-separated list of header names. This command applies only to those headers that are stored with the message; those that are added at delivery time (such as <span class="docbook_emphasis">Envelope-To:</span> and <span class="docbook_emphasis">Return-Path:</span>) cannot be removed by this means. If there is more than one header with the same name, they are all removed. </p> <p> The <span class="docbook_option">headers</span> command in a system filter makes an immediate change to the set of header lines that was received with the message (with possible additions from ACL processing). Subsequent commands in the system filter operate on the modified set, which also forms the basis for subsequent message delivery. Unless further modified during routing or transporting, this set of headers is used for all recipients of the message. </p> <p> During routing and transporting, the variables that refer to the contents of header lines refer only to those lines that are in this set. Thus, header lines that are added by a system filter are visible to users’ filter files and to all routers and transports. This contrasts with the manipulation of header lines by routers and transports, which is not immediate, but which instead is saved up until the message is actually being written (see section <a href="ch44.html#SECTheadersaddrem" title="44. Message processing">44.17</a>). </p> <p> If the message is not delivered at the first attempt, header lines that were added by the system filter are stored with the message, and so are still present at the next delivery attempt. Header lines that were removed are still present, but marked “deleted” so that they are not transported with the message. For this reason, it is usual to make the <span class="docbook_option">headers</span> command conditional on <span class="docbook_option">first_delivery</span> so that the set of header lines is not modified more than once. </p> <p> Because header modification in a system filter acts immediately, you have to use an indirect approach if you want to modify the contents of a header line. For example: </p> <div class="docbook_literallayout"><pre> headers add "Old-Subject: $h_subject:" headers remove "Subject" headers add "Subject: new subject (was: $h_old-subject:)" headers remove "Old-Subject" </pre></div> </div> <div class="section"> <h3 id="SECID217" class="">7. Setting an errors address in a system filter</h3> <p> In a system filter, if a <span class="docbook_option">deliver</span> command is followed by </p> <div class="docbook_literallayout"><pre> errors_to <some address> </pre></div> <p> in order to change the envelope sender (and hence the error reporting) for that delivery, any address may be specified. (In a user filter, only the current user’s address can be set.) For example, if some mail is being monitored, you might use </p> <div class="docbook_literallayout"><pre> unseen deliver monitor@spying.example errors_to root@local.example </pre></div> <p> to take a copy which would not be sent back to the normal error reporting address if its delivery failed. </p> </div> <div class="section"> <h3 id="SECTperaddfil" class="">8. Per-address filtering</h3> <p> In contrast to the system filter, which is run just once per message for each delivery attempt, it is also possible to set up a system-wide filtering operation that runs once for each recipient address. In this case, variables such as $local_part and $domain can be used, and indeed, the choice of filter file could be made dependent on them. This is an example of a router which implements such a filter: </p> <div class="docbook_literallayout"><pre> central_filter: check_local_user driver = redirect domains = +local_domains file = /central/filters/$local_part no_verify allow_filter allow_freeze </pre></div> <p> The filter is run in a separate process under its own uid. Therefore, either <span class="docbook_option">check_local_user</span> must be set (as above), in which case the filter is run as the local user, or the <span class="docbook_option">user</span> option must be used to specify which user to use. If both are set, <span class="docbook_option">user</span> overrides. </p> <p> Care should be taken to ensure that none of the commands in the filter file specify a significant delivery if the message is to go on to be delivered to its intended recipient. The router will not then claim to have dealt with the address, so it will be passed on to subsequent routers to be delivered in the normal way. </p> </div> </div> <a class="previous_page" href="ch42.html"><-previous</a><a class="next_page" href="ch44.html">next-></a> </div></div> <iframe id="branding" name="branding" src="../../../../branding/branding.html" height="0" frameborder="no" scrolling="no"></iframe><div id="footer">Website design by <a href="https://secure.grepular.com/">Mike Cardwell</a>, of <a href="http://cardwellit.com/">Cardwell IT Ltd.</a> </div> <div class="left_bar"></div> <div class="right_bar"></div> <div id="toc"> <ul class="hidden"></ul> <img src="../../../../doc/contents.png" width="16" height="155"> </div> </div> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script><script type="text/javascript" src="../../../../common.js"></script><script type="text/javascript" src="../../../../doc/chapter.js"></script> </body> </html>