Access Control Lists (ACLs) are defined in a separate section of the run time configuration file, headed by “begin acl”. Each ACL definition starts with a name, terminated by a colon. Here is a complete ACL section that contains just one very small ACL:
begin acl small_acl: accept hosts = one.host.only
You can have as many lists as you like in the ACL section, and the order in which they appear does not matter. The lists are self-terminating.
The majority of ACLs are used to control Exim’s behaviour when it receives certain SMTP commands. This applies both to incoming TCP/IP connections, and when a local process submits a message using SMTP by specifying the -bs option. The most common use is for controlling which recipients are accepted in incoming messages. In addition, you can define an ACL that is used to check local non-SMTP messages. The default configuration file contains an example of a realistic ACL for checking RCPT commands. This is discussed in chapter 7.
The -bh command line option provides a way of testing your ACL configuration locally by running a fake SMTP session with which you interact. The host relay-test.mail-abuse.org provides a service for checking your relaying configuration (see section 40.49 for more details).
In order to cause an ACL to be used, you have to name it in one of the relevant options in the main part of the configuration. These options are:
| acl_not_smtp | ACL for non-SMTP messages |
| acl_not_smtp_mime | ACL for non-SMTP MIME parts |
| acl_not_smtp_start | ACL at start of non-SMTP message |
| acl_smtp_auth | ACL for AUTH |
| acl_smtp_connect | ACL for start of SMTP connection |
| acl_smtp_data | ACL after DATA is complete |
| acl_smtp_etrn | ACL for ETRN |
| acl_smtp_expn | ACL for EXPN |
| acl_smtp_helo | ACL for HELO or EHLO |
| acl_smtp_mail | ACL for MAIL |
| acl_smtp_mailauth | ACL for the AUTH parameter of MAIL |
| acl_smtp_mime | ACL for content-scanning MIME parts |
| acl_smtp_notquit | ACL for non-QUIT terminations |
| acl_smtp_predata | ACL at start of DATA command |
| acl_smtp_quit | ACL for QUIT |
| acl_smtp_rcpt | ACL for RCPT |
| acl_smtp_starttls | ACL for STARTTLS |
| acl_smtp_vrfy | ACL for VRFY |
For example, if you set
acl_smtp_rcpt = small_acl
the little ACL defined above is used whenever Exim receives a RCPT command in an SMTP dialogue. The majority of policy tests on incoming messages can be done when RCPT commands arrive. A rejection of RCPT should cause the sending MTA to give up on the recipient address contained in the RCPT command, whereas rejection at other times may cause the client MTA to keep on trying to deliver the message. It is therefore recommended that you do as much testing as possible at RCPT time.
The non-SMTP ACLs apply to all non-interactive incoming messages, that is, they apply to batched SMTP as well as to non-SMTP messages. (Batched SMTP is not really SMTP.) Many of the ACL conditions (for example, host tests, and tests on the state of the SMTP connection such as encryption and authentication) are not relevant and are forbidden in these ACLs. However, the sender and recipients are known, so the senders and sender_domains conditions and the $sender_address and $recipients variables can be used. Variables such as $authenticated_sender are also available. You can specify added header lines in any of these ACLs.
The acl_not_smtp_start ACL is run right at the start of receiving a non-SMTP message, before any of the message has been read. (This is the analogue of the acl_smtp_predata ACL for SMTP input.) In the case of batched SMTP input, it runs after the DATA command has been reached. The result of this ACL is ignored; it cannot be used to reject a message. If you really need to, you could set a value in an ACL variable here and reject based on that in the acl_not_smtp ACL. However, this ACL can be used to set controls, and in particular, it can be used to set
control = suppress_local_fixups
This cannot be used in the other non-SMTP ACLs because by the time they are run, it is too late.
The acl_not_smtp_mime ACL is available only when Exim is compiled with the content-scanning extension. For details, see chapter 41.
The acl_not_smtp ACL is run just before the local_scan() function. Any kind of rejection is treated as permanent, because there is no way of sending a temporary error for these kinds of message.
The ACL test specified by acl_smtp_connect happens at the start of an SMTP session, after the test specified by host_reject_connection (which is now an anomaly) and any TCP Wrappers testing (if configured). If the connection is accepted by an accept verb that has a message modifier, the contents of the message override the banner message that is otherwise specified by the smtp_banner option.
The ACL test specified by acl_smtp_helo happens when the client issues an EHLO or HELO command, after the tests specified by helo_accept_junk_hosts, helo_allow_chars, helo_verify_hosts, and helo_try_verify_hosts. Note that a client may issue more than one EHLO or HELO command in an SMTP session, and indeed is required to issue a new EHLO or HELO after successfully setting up encryption following a STARTTLS command.
If the command is accepted by an accept verb that has a message modifier, the message may not contain more than one line (it will be truncated at the first newline and a panic logged if it does). Such a message cannot affect the EHLO options that are listed on the second and subsequent lines of an EHLO response.
Two ACLs are associated with the DATA command, because it is two-stage command, with two responses being sent to the client. When the DATA command is received, the ACL defined by acl_smtp_predata is obeyed. This gives you control after all the RCPT commands, but before the message itself is received. It offers the opportunity to give a negative response to the DATA command before the data is transmitted. Header lines added by MAIL or RCPT ACLs are not visible at this time, but any that are defined here are visible when the acl_smtp_data ACL is run.
You cannot test the contents of the message, for example, to verify addresses in the headers, at RCPT time or when the DATA command is received. Such tests have to appear in the ACL that is run after the message itself has been received, before the final response to the DATA command is sent. This is the ACL specified by acl_smtp_data, which is the second ACL that is associated with the DATA command.
For both of these ACLs, it is not possible to reject individual recipients. An error response rejects the entire message. Unfortunately, it is known that some MTAs do not treat hard (5xx) responses to the DATA command (either before or after the data) correctly – they keep the message on their queues and try again later, but that is their problem, though it does waste some of your resources.
The acl_smtp_mime option is available only when Exim is compiled with the content-scanning extension. For details, see chapter 41.
The ACL for the SMTP QUIT command is anomalous, in that the outcome of the ACL does not affect the response code to QUIT, which is always 221. Thus, the ACL does not in fact control any access. For this reason, the only verbs that are permitted are accept and warn.
This ACL can be used for tasks such as custom logging at the end of an SMTP session. For example, you can use ACL variables in other ACLs to count messages, recipients, etc., and log the totals at QUIT time using one or more logwrite modifiers on a warn verb.
Warning: Only the $acl_cx variables can be used for this, because the $acl_mx variables are reset at the end of each incoming message.
You do not need to have a final accept, but if you do, you can use a message modifier to specify custom text that is sent as part of the 221 response to QUIT.
This ACL is run only for a “normal” QUIT. For certain kinds of disastrous failure (for example, failure to open a log file, or when Exim is bombing out because it has detected an unrecoverable error), all SMTP commands from the client are given temporary error responses until QUIT is received or the connection is closed. In these special cases, the QUIT ACL does not run.
The not-QUIT ACL, specified by smtp_notquit_acl, is run in most cases when an SMTP session ends without sending QUIT. However, when Exim itself is is bad trouble, such as being unable to write to its log files, this ACL is not run, because it might try to do things (such as write to log files) that make the situation even worse.
Like the QUIT ACL, this ACL is provided to make it possible to do customized logging or to gather statistics, and its outcome is ignored. The delay modifier is forbidden in this ACL, and the only permitted verbs are accept and warn.
When the not-QUIT ACL is running, the variable $smtp_notquit_reason is set to a string that indicates the reason for the termination of the SMTP connection. The possible values are:
acl-drop | Another ACL issued a drop command |
bad-commands | Too many unknown or non-mail commands |
command-timeout | Timeout while reading SMTP commands |
connection-lost | The SMTP connection has been lost |
data-timeout | Timeout while reading message data |
local-scan-error | The local_scan() function crashed |
local-scan-timeout | The local_scan() function timed out |
signal-exit | SIGTERM or SIGINT |
synchronization-error | SMTP synchronization error |
tls-failed | TLS failed to start |
In most cases when an SMTP connection is closed without having received QUIT,
Exim sends an SMTP response message before actually closing the connection.
With the exception of the acl-drop case, the default message can be
overridden by the message modifier in the not-QUIT ACL. In the case of a
drop verb in another ACL, it is the message from the other ACL that is
used.
The value of an acl_smtp_xxx option is expanded before use, so you can use different ACLs in different circumstances. For example,
acl_smtp_rcpt = ${if ={25}{$interface_port} \
{acl_check_rcpt} {acl_check_rcpt_submit} }
In the default configuration file there are some example settings for providing an RFC 4409 message submission service on port 587 and a non-standard “smtps” service on port 465. You can use a string expansion like this to choose an ACL for MUAs on these ports which is more appropriate for this purpose than the default ACL on port 25.
The expanded string does not have to be the name of an ACL in the configuration file; there are other possibilities. Having expanded the string, Exim searches for an ACL as follows:
If the string begins with a slash, Exim uses it as a file name, and reads its contents as an ACL. The lines are processed in the same way as lines in the Exim configuration file. In particular, continuation lines are supported, blank lines are ignored, as are lines whose first non-whitespace character is “#”. If the file does not exist or cannot be read, an error occurs (typically causing a temporary failure of whatever caused the ACL to be run). For example:
acl_smtp_data = /etc/acls/\
${lookup{$sender_host_address}lsearch\
{/etc/acllist}{$value}{default}}
This looks up an ACL file to use on the basis of the host’s IP address, falling back to a default if the lookup fails. If an ACL is successfully read from a file, it is retained in memory for the duration of the Exim process, so that it can be re-used without having to re-read the file.
If the string does not start with a slash, and does not contain any spaces, Exim searches the ACL section of the configuration for an ACL whose name matches the string.
If no named ACL is found, or if the string contains spaces, Exim parses the string as an inline ACL. This can save typing in cases where you just want to have something like
acl_smtp_vrfy = accept
in order to allow free use of the VRFY command. Such a string may contain newlines; it is processed in the same way as an ACL that is read from a file.
Except for the QUIT ACL, which does not affect the SMTP return code (see section 40.8 above), the result of running an ACL is either “accept” or “deny”, or, if some test cannot be completed (for example, if a database is down), “defer”. These results cause 2xx, 5xx, and 4xx return codes, respectively, to be used in the SMTP dialogue. A fourth return, “error”, occurs when there is an error such as invalid syntax in the ACL. This also causes a 4xx return code.
For the non-SMTP ACL, “defer” and “error” are treated in the same way as “deny”, because there is no mechanism for passing temporary errors to the submitters of non-SMTP messages.
ACLs that are relevant to message reception may also return “discard”. This has the effect of “accept”, but causes either the entire message or an individual recipient address to be discarded. In other words, it is a blackholing facility. Use it with care.
If the ACL for MAIL returns “discard”, all recipients are discarded, and no ACL is run for subsequent RCPT commands. The effect of “discard” in a RCPT ACL is to discard just the one recipient address. If there are no recipients left when the message’s data is received, the DATA ACL is not run. A “discard” return from the DATA or the non-SMTP ACL discards all the remaining recipients. The “discard” return is not permitted for the acl_smtp_predata ACL.
The local_scan() function is always run, even if there are no remaining recipients; it may create new recipients.
The default actions when any of the acl_xxx options are unset are not all the same. Note: These defaults apply only when the relevant ACL is not defined at all. For any defined ACL, the default action when control reaches the end of the ACL statements is “deny”.
For acl_smtp_quit and acl_not_smtp_start there is no default because these two are ACLs that are used only for their side effects. They cannot be used to accept or reject anything.
For acl_not_smtp, acl_smtp_auth, acl_smtp_connect, acl_smtp_data, acl_smtp_helo, acl_smtp_mail, acl_smtp_mailauth, acl_smtp_mime, acl_smtp_predata, and acl_smtp_starttls, the action when the ACL is not defined is “accept”.
For the others (acl_smtp_etrn, acl_smtp_expn, acl_smtp_rcpt, and acl_smtp_vrfy), the action when the ACL is not defined is “deny”. This means that acl_smtp_rcpt must be defined in order to receive any messages over an SMTP connection. For an example, see the ACL in the default configuration file.
When a MAIL or RCPT ACL, or either of the DATA ACLs, is running, the variables that contain information about the host and the message’s sender (for example, $sender_host_address and $sender_address) are set, and can be used in ACL statements. In the case of RCPT (but not MAIL or DATA), $domain and $local_part are set from the argument address. The entire SMTP command is available in $smtp_command.
When an ACL for the AUTH parameter of MAIL is running, the variables that contain information about the host are set, but $sender_address is not yet set. Section 33.2 contains a discussion of this parameter and how it is used.
The $message_size variable is set to the value of the SIZE parameter on the MAIL command at MAIL, RCPT and pre-data time, or to -1 if that parameter is not given. The value is updated to the true message size by the time the final DATA ACL is run (after the message data has been received).
The $rcpt_count variable increases by one for each RCPT command received. The $recipients_count variable increases by one each time a RCPT command is accepted, so while an ACL for RCPT is being processed, it contains the number of previously accepted recipients. At DATA time (for both the DATA ACLs), $rcpt_count contains the total number of RCPT commands, and $recipients_count contains the total number of accepted recipients.
When an ACL is being run for AUTH, EHLO, ETRN, EXPN, HELO, STARTTLS, or VRFY, the remainder of the SMTP command line is placed in $smtp_command_argument, and the entire SMTP command is available in $smtp_command. These variables can be tested using a condition condition. For example, here is an ACL for use with AUTH, which insists that either the session is encrypted, or the CRAM-MD5 authentication method is used. In other words, it does not permit authentication methods that use cleartext passwords on unencrypted connections.
acl_check_auth:
accept encrypted = *
accept condition = ${if eq{${uc:$smtp_command_argument}}\
{CRAM-MD5}}
deny message = TLS encryption or CRAM-MD5 required
(Another way of applying this restriction is to arrange for the authenticators that use cleartext passwords not to be advertised when the connection is not encrypted. You can use the generic server_advertise_condition authenticator option to do this.)
An individual ACL consists of a number of statements. Each statement starts with a verb, optionally followed by a number of conditions and “modifiers”. Modifiers can change the way the verb operates, define error and log messages, set variables, insert delays, and vary the processing of accepted messages.
If all the conditions are met, the verb is obeyed. The same condition may be used (with different arguments) more than once in the same statement. This provides a means of specifying an “and” conjunction between conditions. For example:
deny dnslists = list1.example dnslists = list2.example
If there are no conditions, the verb is always obeyed. Exim stops evaluating the conditions and modifiers when it reaches a condition that fails. What happens then depends on the verb (and in one case, on a special modifier). Not all the conditions make sense at every testing point. For example, you cannot test a sender address in the ACL that is run for a VRFY command.
The ACL verbs are as follows:
accept: If all the conditions are met, the ACL returns “accept”. If any of the conditions are not met, what happens depends on whether endpass appears among the conditions (for syntax see below). If the failing condition is before endpass, control is passed to the next ACL statement; if it is after endpass, the ACL returns “deny”. Consider this statement, used to check a RCPT command:
accept domains = +local_domains endpass verify = recipient
If the recipient domain does not match the domains condition, control passes to the next statement. If it does match, the recipient is verified, and the command is accepted if verification succeeds. However, if verification fails, the ACL yields “deny”, because the failing condition is after endpass.
The endpass feature has turned out to be confusing to many people, so its use is not recommended nowadays. It is always possible to rewrite an ACL so that endpass is not needed, and it is no longer used in the default configuration.
If a message modifier appears on an accept statement, its action depends on whether or not endpass is present. In the absence of endpass (when an accept verb either accepts or passes control to the next statement), message can be used to vary the message that is sent when an SMTP command is accepted. For example, in a RCPT ACL you could have:
accept <some conditions> message = OK, I will allow you through todayYou can specify an SMTP response code, optionally followed by an “extended response code” at the start of the message, but the first digit must be the same as would be sent by default, which is 2 for an accept verb.
If endpass is present in an accept statement, message specifies an error message that is used when access is denied. This behaviour is retained for backward compatibility, but current “best practice” is to avoid the use of endpass.
defer: If all the conditions are true, the ACL returns “defer” which, in
an SMTP session, causes a 4xx response to be given. For a non-SMTP ACL,
defer is the same as deny, because there is no way of sending a
temporary error. For a RCPT command, defer is much the same as using a
redirect router and :defer: while verifying, but the defer verb can
be used in any ACL, and even for a recipient it might be a simpler approach.
deny: If all the conditions are met, the ACL returns “deny”. If any of the conditions are not met, control is passed to the next ACL statement. For example,
deny dnslists = blackholes.mail-abuse.org
rejects commands from hosts that are on a DNS black list.
discard: This verb behaves like accept, except that it returns “discard” from the ACL instead of “accept”. It is permitted only on ACLs that are concerned with receiving messages. When all the conditions are true, the sending entity receives a “success” response. However, discard causes recipients to be discarded. If it is used in an ACL for RCPT, just the one recipient is discarded; if used for MAIL, DATA or in the non-SMTP ACL, all the message’s recipients are discarded. Recipients that are discarded before DATA do not appear in the log line when the log_recipients log selector is set.
If the log_message modifier is set when discard operates, its contents are added to the line that is automatically written to the log. The message modifier operates exactly as it does for accept.
drop: This verb behaves like deny, except that an SMTP connection is forcibly closed after the 5xx error message has been sent. For example:
drop message = I don't take more than 20 RCPTs
condition = ${if > {$rcpt_count}{20}}
There is no difference between deny and drop for the connect-time ACL. The connection is always dropped after sending a 550 response.
require: If all the conditions are met, control is passed to the next ACL statement. If any of the conditions are not met, the ACL returns “deny”. For example, when checking a RCPT command,
require message = Sender did not verify
verify = sender
passes control to subsequent statements only if the message’s sender can be verified. Otherwise, it rejects the command. Note the positioning of the message modifier, before the verify condition. The reason for this is discussed in section 40.18.
warn: If all the conditions are true, a line specified by the log_message modifier is written to Exim’s main log. Control always passes to the next ACL statement. If any condition is false, the log line is not written. If an identical log line is requested several times in the same message, only one copy is actually written to the log. If you want to force duplicates to be written, use the logwrite modifier instead.
If log_message is not present, a warn verb just checks its conditions and obeys any “immediate” modifiers (such as control, set, logwrite, and add_header) that appear before the first failing condition. There is more about adding header lines in section 40.22.
If any condition on a warn statement cannot be completed (that is, there is some sort of defer), the log line specified by log_message is not written. This does not include the case of a forced failure from a lookup, which is considered to be a successful completion. After a defer, no further conditions or modifiers in the warn statement are processed. The incident is logged, and the ACL continues to be processed, from the next statement onwards.
When one of the warn conditions is an address verification that fails, the text of the verification failure message is in $acl_verify_message. If you want this logged, you must set it up explicitly. For example:
warn !verify = sender
log_message = sender verify failed: $acl_verify_message
At the end of each ACL there is an implicit unconditional deny.
As you can see from the examples above, the conditions and modifiers are written one to a line, with the first one on the same line as the verb, and subsequent ones on following lines. If you have a very long condition, you can continue it onto several physical lines by the usual backslash continuation mechanism. It is conventional to align the conditions vertically.
There are some special variables that can be set during ACL processing. They can be used to pass information between different ACLs, different invocations of the same ACL in the same SMTP connection, and between ACLs and the routers, transports, and filters that are used to deliver a message. The names of these variables must begin with $acl_c or $acl_m, followed either by a digit or an underscore, but the remainder of the name can be any sequence of alphanumeric characters and underscores that you choose. There is no limit on the number of ACL variables. The two sets act as follows:
The values of those variables whose names begin with $acl_c persist throughout an SMTP connection. They are never reset. Thus, a value that is set while receiving one message is still available when receiving the next message on the same SMTP connection.
The values of those variables whose names begin with $acl_m persist only while a message is being received. They are reset afterwards. They are also reset by MAIL, RSET, EHLO, HELO, and after starting up a TLS session.
When a message is accepted, the current values of all the ACL variables are preserved with the message and are subsequently made available at delivery time. The ACL variables are set by a modifier called set. For example:
accept hosts = whatever
set acl_m4 = some value
accept authenticated = *
set acl_c_auth = yes
Note: A leading dollar sign is not used when naming a variable that is to be set. If you want to set a variable without taking any action, you can use a warn verb without any other modifiers or conditions.
What happens if a syntactically valid but undefined ACL variable is referenced depends on the setting of the strict_acl_vars option. If it is false (the default), an empty string is substituted; if it is true, an error is generated.
Versions of Exim before 4.64 have a limited set of numbered variables, but their names are compatible, so there is no problem with upgrading.
An exclamation mark preceding a condition negates its result. For example:
deny domains = *.dom.example
!verify = recipient
causes the ACL to return “deny” if the recipient domain ends in dom.example and the recipient address cannot be verified. Sometimes negation can be used on the right-hand side of a condition. For example, these two statements are equivalent:
deny hosts = !192.168.3.4 deny !hosts = 192.168.3.4
However, for many conditions (verify being a good example), only left-hand side negation of the whole condition is possible.
The arguments of conditions and modifiers are expanded. A forced failure of an expansion causes a condition to be ignored, that is, it behaves as if the condition is true. Consider these two statements:
accept senders = ${lookup{$host_name}lsearch\
{/some/file}{$value}fail}
accept senders = ${lookup{$host_name}lsearch\
{/some/file}{$value}{}}
Each attempts to look up a list of acceptable senders. If the lookup succeeds, the returned list is searched, but if the lookup fails the behaviour is different in the two cases. The fail in the first statement causes the condition to be ignored, leaving no further conditions. The accept verb therefore succeeds. The second statement, however, generates an empty list when the lookup fails. No sender can match an empty list, so the condition fails, and therefore the accept also fails.
ACL modifiers appear mixed in with conditions in ACL statements. Some of them specify actions that are taken as the conditions for a statement are checked; others specify text for messages that are used when access is denied or a warning is generated. The control modifier affects the way an incoming message is handled.
The positioning of the modifiers in an ACL statement important, because the processing of a verb ceases as soon as its outcome is known. Only those modifiers that have already been encountered will take effect. For example, consider this use of the message modifier:
require message = Can't verify sender
verify = sender
message = Can't verify recipient
verify = recipient
message = This message cannot be used
If sender verification fails, Exim knows that the result of the statement is “deny”, so it goes no further. The first message modifier has been seen, so its text is used as the error message. If sender verification succeeds, but recipient verification fails, the second message is used. If recipient verification succeeds, the third message becomes “current”, but is never used because there are no more conditions to cause failure.
For the deny verb, on the other hand, it is always the last message modifier that is used, because all the conditions must be true for rejection to happen. Specifying more than one message modifier does not make sense, and the message can even be specified after all the conditions. For example:
deny hosts = ...
!senders = *@my.domain.example
message = Invalid sender from client host
The “deny” result does not happen until the end of the statement is reached, by which time Exim has set up the message.
The ACL modifiers are as follows:
This modifier specifies one or more header lines that are to be added to an incoming message, assuming, of course, that the message is ultimately accepted. For details, see section 40.22.
This modifier does nothing of itself, and processing of the ACL always continues with the next condition or modifier. The value of continue is in the side effects of expanding its argument. Typically this could be used to update a database. It is really just a syntactic tidiness, to avoid having to write rather ugly lines like this:
condition = ${if eq{0}{<some expansion>}{true}{true}}Instead, all you need is
continue = <some expansion>This modifier affects the subsequent processing of the SMTP connection or of an incoming message that is accepted. The effect of the first type of control lasts for the duration of the connection, whereas the effect of the second type lasts only until the current message has been received. The message-specific controls always apply to the whole message, not to individual recipients, even if the control modifier appears in a RCPT ACL.
As there are now quite a few controls that can be applied, they are described separately in section 40.20. The control modifier can be used in several different ways. For example:
It can be at the end of an accept statement:
accept ...some conditions
control = queue_only
In this case, the control is applied when this statement yields “accept”, in other words, when the conditions are all true.
It can be in the middle of an accept statement:
accept ...some conditions...
control = queue_only
...some more conditions...
If the first set of conditions are true, the control is applied, even if the statement does not accept because one of the second set of conditions is false. In this case, some subsequent statement must yield “accept” for the control to be relevant.
It can be used with warn to apply the control, leaving the decision about accepting or denying to a subsequent verb. For example:
warn ...some conditions...
control = freeze
accept ...
This example of warn does not contain message, log_message, or logwrite, so it does not add anything to the message and does not write a log entry.
If you want to apply a control unconditionally, you can use it with a require verb. For example:
require control = no_multiline_responses
This modifier may appear in any ACL. It causes Exim to wait for the time interval before proceeding. However, when testing Exim using the -bh option, the delay is not actually imposed (an appropriate message is output instead). The time is given in the usual Exim notation, and the delay happens as soon as the modifier is processed. In an SMTP session, pending output is flushed before the delay is imposed.
Like control, delay can be used with accept or deny, for example:
deny ...some conditions...
delay = 30s
The delay happens if all the conditions are true, before the statement returns “deny”. Compare this with:
deny delay = 30s
...some conditions...
which waits for 30s before processing the conditions. The delay modifier can also be used with warn and together with control:
warn ...some conditions...
delay = 2m
control = freeze
accept ...
If delay is encountered when the SMTP PIPELINING extension is in use, responses to several commands are no longer buffered and sent in one packet (as they would normally be) because all output is flushed before imposing the delay. This optimization is disabled so that a number of small delays do not appear to the client as one large aggregated delay that might provoke an unwanted timeout. You can, however, disable output flushing for delay by using a control modifier to set no_delay_flush.
This modifier, which has no argument, is recognized only in accept and discard statements. It marks the boundary between the conditions whose failure causes control to pass to the next statement, and the conditions whose failure causes the ACL to return “deny”. This concept has proved to be confusing to some people, so the use of endpass is no longer recommended as “best practice”. See the description of accept above for more details.
This modifier sets up a message that is used as part of the log message if the ACL denies access or a warn statement’s conditions are true. For example:
require log_message = wrong cipher suite $tls_cipher
encrypted = DES-CBC3-SHA
log_message is also used when recipients are discarded by discard. For example:
discard <some conditions> log_message = Discarded $local_part@$domain because...When access is denied, log_message adds to any underlying error message that may exist because of a condition failure. For example, while verifying a recipient address, a :fail: redirection might have already set up a message.
The message may be defined before the conditions to which it applies, because the string expansion does not happen until Exim decides that access is to be denied. This means that any variables that are set by the condition are available for inclusion in the message. For example, the $dnslist_<xxx> variables are set after a DNS black list lookup succeeds. If the expansion of log_message fails, or if the result is an empty string, the modifier is ignored.
If you want to use a warn statement to log the result of an address verification, you can use $acl_verify_message to include the verification error message.
If log_message is used with a warn statement, “Warning:” is added to the start of the logged message. If the same warning log message is requested more than once while receiving a single email message, only one copy is actually logged. If you want to log multiple copies, use logwrite instead of log_message. In the absence of log_message and logwrite, nothing is logged for a successful warn statement.
If log_message is not present and there is no underlying error message (for example, from the failure of address verification), but message is present, the message text is used for logging rejections. However, if any text for logging contains newlines, only the first line is logged. In the absence of both log_message and message, a default built-in message is used for logging rejections.
This modifier makes it possible to specify which logs are used for messages
about ACL rejections. Its argument is a colon-separated list of words that can
be “main”, “reject”, or “panic”. The default is main:reject. The list
may be empty, in which case a rejection is not logged at all. For example, this
ACL fragment writes no logging information when access is denied:
deny <some conditions> log_reject_target =This modifier can be used in SMTP and non-SMTP ACLs. It applies to both permanent and temporary rejections.
This modifier writes a message to a log file as soon as it is encountered when processing an ACL. (Compare log_message, which, except in the case of warn and discard, is used only if the ACL statement denies access.) The logwrite modifier can be used to log special incidents in ACLs. For example:
accept <some special conditions> control = freeze logwrite = froze message because ...By default, the message is written to the main log. However, it may begin with a colon, followed by a comma-separated list of log names, and then another colon, to specify exactly which logs are to be written. For example:
logwrite = :main,reject: text for main and reject logs logwrite = :panic: text for panic log only
This modifier sets up a text string that is expanded and used as a response message when an ACL statement terminates the ACL with an “accept”, “deny”, or “defer” response. (In the case of the accept and discard verbs, there is some complication if endpass is involved; see the description of accept for details.)
The expansion of the message happens at the time Exim decides that the ACL is to end, not at the time it processes message. If the expansion fails, or generates an empty string, the modifier is ignored. Here is an example where message must be specified first, because the ACL ends with a rejection if the hosts condition fails:
require message = Host not recognized
hosts = 10.0.0.0/8
(Once a condition has failed, no further conditions or modifiers are processed.)
For ACLs that are triggered by SMTP commands, the message is returned as part of the SMTP response. The use of message with accept (or discard) is meaningful only for SMTP, as no message is returned when a non-SMTP message is accepted. In the case of the connect ACL, accepting with a message modifier overrides the value of smtp_banner. For the EHLO/HELO ACL, a customized accept message may not contain more than one line (otherwise it will be truncated at the first newline and a panic logged), and it cannot affect the EHLO options.
When SMTP is involved, the message may begin with an overriding response code, consisting of three digits optionally followed by an “extended response code” of the form n.n.n, each code being followed by a space. For example:
deny message = 599 1.2.3 Host not welcome
hosts = 192.168.34.0/24
The first digit of the supplied response code must be the same as would be sent by default. A panic occurs if it is not. Exim uses a 550 code when it denies access, but for the predata ACL, note that the default success code is 354, not 2xx.
Notwithstanding the previous paragraph, for the QUIT ACL, unlike the others, the message modifier cannot override the 221 response code.
The text in a message modifier is literal; any quotes are taken as literals, but because the string is expanded, backslash escapes are processed anyway. If the message contains newlines, this gives rise to a multi-line SMTP response.
If message is used on a statement that verifies an address, the message specified overrides any message that is generated by the verification process. However, the original message is available in the variable $acl_verify_message, so you can incorporate it into your message if you wish. In particular, if you want the text from :fail: items in redirect routers to be passed back as part of the SMTP response, you should either not use a message modifier, or make use of $acl_verify_message.
For compatibility with previous releases of Exim, a message modifier that is used with a warn verb behaves in a similar way to the add_header modifier, but this usage is now deprecated. However, message acts only when all the conditions are true, wherever it appears in an ACL command, whereas add_header acts as soon as it is encountered. If message is used with warn in an ACL that is not concerned with receiving a message, it has no effect.
This modifier puts a value into one of the ACL variables (see section 40.17).
The control modifier supports the following settings:
This modifier allows a client host to use the SMTP AUTH command even when it has not been advertised in response to EHLO. Furthermore, because there are apparently some really broken clients that do this, Exim will accept AUTH after HELO (rather than EHLO) when this control is set. It should be used only if you really need it, and you should limit its use to those broken clients that do not work without it. For example:
warn hosts = 192.168.34.25
control = allow_auth_unadvertised
Normally, when an Exim server receives an AUTH command, it checks the name of the authentication mechanism that is given in the command to ensure that it matches an advertised mechanism. When this control is set, the check that a mechanism has been advertised is bypassed. Any configured mechanism can be used by the client. This control is permitted only in the connection and HELO ACLs.
These two controls are permitted only in the ACL specified by acl_smtp_rcpt (that is, during RCPT processing). By default, the contents of $local_part are lower cased before ACL processing. If “caseful_local_part” is specified, any uppercase letters in the original local part are restored in $local_part for the rest of the ACL, or until a control that sets “caselower_local_part” is encountered.
These controls affect only the current recipient. Moreover, they apply only to local part handling that takes place directly in the ACL (for example, as a key in lookups). If a test to verify the recipient is obeyed, the case-related handling of the local part during the verification is controlled by the router configuration (see the caseful_local_part generic router option).
This facility could be used, for example, to add a spam score to local parts containing upper case letters. For example, using $acl_m4 to accumulate the spam score:
warn control = caseful_local_part
set acl_m4 = ${eval:\
$acl_m4 + \
${if match{$local_part}{[A-Z]}{1}{0}}\
}
control = caselower_local_part
Notice that we put back the lower cased version afterwards, assuming that is what is wanted for subsequent tests.
These controls make it possible to be selective about when SMTP synchronization is enforced. The global option smtp_enforce_sync specifies the initial state of the switch (it is true by default). See the description of this option in chapter 14 for details of SMTP synchronization checking.
The effect of these two controls lasts for the remainder of the SMTP connection. They can appear in any ACL except the one for the non-SMTP messages. The most straightforward place to put them is in the ACL defined by acl_smtp_connect, which is run at the start of an incoming SMTP connection, before the first synchronization check. The expected use is to turn off the synchronization checks for badly-behaved hosts that you nevertheless need to work with.
This control works in exactly the same way as fakereject (described below) except that it causes an SMTP 450 response after the message data instead of a 550 response. You must take care when using fakedefer because it causes the messages to be duplicated when the sender retries. Therefore, you should not use fakedefer if the message is to be delivered normally.
This control is permitted only for the MAIL, RCPT, and DATA ACLs, in other words, only when an SMTP message is being received. If Exim accepts the message, instead the final 250 response, a 550 rejection message is sent. However, Exim proceeds to deliver the message as normal. The control applies only to the current message, not to any subsequent ones that may be received in the same SMTP connection.
The text for the 550 response is taken from the control modifier. If no message is supplied, the following is used:
550-Your message has been rejected but is being 550-kept for evaluation. 550-If it was a legitimate message, it may still be 550 delivered to the target recipient(s).
This facility should be used with extreme caution.
This control is permitted only for the MAIL, RCPT, DATA, and non-SMTP ACLs, in other words, only when a message is being received. If the message is accepted, it is placed on Exim’s queue and frozen. The control applies only to the current message, not to any subsequent ones that may be received in the same SMTP connection.
This modifier can optionally be followed by /no_tell. If the global option
freeze_tell is set, it is ignored for the current message (that is, nobody
is told about the freezing), provided all the control=freeze modifiers that
are obeyed for the current message have the /no_tell option.
Exim normally flushes SMTP output before implementing a delay in an ACL, to avoid unexpected timeouts in clients when the SMTP PIPELINING extension is in use. This control, as long as it is encountered before the delay modifier, disables such output flushing.
Exim normally flushes SMTP output before performing a callout in an ACL, to avoid unexpected timeouts in clients when the SMTP PIPELINING extension is in use. This control, as long as it is encountered before the verify condition that causes the callout, disables such output flushing.
This control is available when Exim is compiled with the content scanning extension. Content scanning may require a copy of the current message, or parts of it, to be written in “mbox format” to a spool file, for passing to a virus or spam scanner. Normally, such copies are deleted when they are no longer needed. If this control is set, the copies are not deleted. The control applies only to the current message, not to any subsequent ones that may be received in the same SMTP connection. It is provided for debugging purposes and is unlikely to be useful in production.
This control is permitted for any ACL except the one for non-SMTP messages. It seems that there are broken clients in use that cannot handle multiline SMTP responses, despite the fact that RFC 821 defined them over 20 years ago.
If this control is set, multiline SMTP responses from ACL rejections are suppressed. One way of doing this would have been to put out these responses as one long line. However, RFC 2821 specifies a maximum of 512 bytes per response (“use multiline responses for more” it says – ha!), and some of the responses might get close to that. So this facility, which is after all only a sop to broken clients, is implemented by doing two very easy things:
Extra information that is normally output as part of a rejection caused by sender verification failure is omitted. Only the final line (typically “sender verification failed”) is sent.
If a message modifier supplies a multiline response, only the first line is output.
The setting of the switch can, of course, be made conditional on the calling host. Its effect lasts until the end of the SMTP connection.
This control turns off the advertising of the PIPELINING extension to SMTP in the current session. To be useful, it must be obeyed before Exim sends its response to an EHLO command. Therefore, it should normally appear in an ACL controlled by acl_smtp_connect or acl_smtp_helo. See also pipelining_advertise_hosts.
This control is permitted only for the MAIL, RCPT, DATA, and non-SMTP ACLs, in other words, only when a message is being received. If the message is accepted, it is placed on Exim’s queue and left there for delivery by a subsequent queue runner. No immediate delivery process is started. In other words, it has the effect as the queue_only global option. However, the control applies only to the current message, not to any subsequent ones that may be received in the same SMTP connection.
This control is permitted only for the MAIL, RCPT, and start of data ACLs (the latter is the one defined by acl_smtp_predata). Setting it tells Exim that the current message is a submission from a local MUA. In this case, Exim operates in “submission mode”, and applies certain fixups to the message if necessary. For example, it add a Date: header line if one is not present. This control is not permitted in the acl_smtp_data ACL, because that is too late (the message has already been created).
Chapter 44 describes the processing that Exim applies to messages. Section 44.1 covers the processing that happens in submission mode; the available options for this control are described there. The control applies only to the current message, not to any subsequent ones that may be received in the same SMTP connection.
This control applies to locally submitted (non TCP/IP) messages, and is the
complement of control = submission. It disables the fixups that are
normally applied to locally-submitted messages. Specifically:
Any Sender: header line is left alone (in this respect, it is a dynamic version of local_sender_retain).
No Message-ID:, From:, or Date: header lines are added.
There is no check that From: corresponds to the actual sender.
This control may be useful when a remotely-originated message is accepted, passed to some scanning program, and then re-submitted for delivery. It can be used only in the acl_smtp_mail, acl_smtp_rcpt, acl_smtp_predata, and acl_not_smtp_start ACLs, because it has to be set before the message’s data is read.
Note: This control applies only to the current message, not to any others that are being submitted at the same time using -bs or -bS.
All four possibilities for message fixups can be specified:
Locally submitted, fixups applied: the default.
Locally submitted, no fixups applied: use control =
suppress_local_fixups.
Remotely submitted, no fixups applied: the default.
Remotely submitted, fixups applied: use control = submission.
The add_header modifier can be used to add one or more extra header lines to an incoming message, as in this example:
warn dnslists = sbl.spamhaus.org : \
dialup.mail-abuse.org
add_header = X-blacklisted-at: $dnslist_domain
The add_header modifier is permitted in the MAIL, RCPT, PREDATA, DATA, MIME, and non-SMTP ACLs (in other words, those that are concerned with receiving a message). The message must ultimately be accepted for add_header to have any significant effect. You can use add_header with any ACL verb, including deny (though this is potentially useful only in a RCPT ACL).
If the data for the add_header modifier contains one or more newlines that
are not followed by a space or a tab, it is assumed to contain multiple header
lines. Each one is checked for valid syntax; X-ACL-Warn: is added to the
front of any line that is not a valid header line.
Added header lines are accumulated during the MAIL, RCPT, and predata ACLs. They are added to the message before processing the DATA and MIME ACLs. However, if an identical header line is requested more than once, only one copy is actually added to the message. Further header lines may be accumulated during the DATA and MIME ACLs, after which they are added to the message, again with duplicates suppressed. Thus, it is possible to add two identical header lines to an SMTP message, but only if one is added before DATA and one after. In the case of non-SMTP messages, new headers are accumulated during the non-SMTP ACLs, and are added to the message after all the ACLs have run. If a message is rejected after DATA or by the non-SMTP ACL, all added header lines are included in the entry that is written to the reject log.
Header lines are not visible in string expansions until they are added to the message. It follows that header lines defined in the MAIL, RCPT, and predata ACLs are not visible until the DATA ACL and MIME ACLs are run. Similarly, header lines that are added by the DATA or MIME ACLs are not visible in those ACLs. Because of this restriction, you cannot use header lines as a way of passing data between (for example) the MAIL and RCPT ACLs. If you want to do this, you can use ACL variables, as described in section 40.17.
The add_header modifier acts immediately it is encountered during the processing of an ACL. Notice the difference between these two cases:
accept add_header = ADDED: some text <some condition>accept <some condition> add_header = ADDED: some textIn the first case, the header line is always added, whether or not the condition is true. In the second case, the header line is added only if the condition is true. Multiple occurrences of add_header may occur in the same ACL statement. All those that are encountered before a condition fails are honoured.
For compatibility with previous versions of Exim, a message modifier for a warn verb acts in the same way as add_header, except that it takes effect only if all the conditions are true, even if it appears before some of them. Furthermore, only the last occurrence of message is honoured. This usage of message is now deprecated. If both add_header and message are present on a warn verb, both are processed according to their specifications.
By default, new header lines are added to a message at the end of the existing header lines. However, you can specify that any particular header line should be added right at the start (before all the Received: lines), immediately after the first block of Received: lines, or immediately before any line that is not a Received: or Resent-something: header.
This is done by specifying “:at_start:”, “:after_received:”, or “:at_start_rfc:” (or, for completeness, “:at_end:”) before the text of the header line, respectively. (Header text cannot start with a colon, as there has to be a header name first.) For example:
warn add_header = \
:after_received:X-My-Header: something or other...
If more than one header line is supplied in a single add_header modifier, each one is treated independently and can therefore be placed differently. If you add more than one line at the start, or after the Received: block, they end up in reverse order.
Warning: This facility currently applies only to header lines that are added in an ACL. It does NOT work for header lines that are added in a system filter or in a router or transport.
Some of conditions listed in this section are available only when Exim is compiled with the content-scanning extension. They are included here briefly for completeness. More detailed descriptions can be found in the discussion on content scanning in chapter 41.
Not all conditions are relevant in all circumstances. For example, testing senders and recipients does not make sense in an ACL that is being run as the result of the arrival of an ETRN command, and checks on message headers can be done only in the ACLs specified by acl_smtp_data and acl_not_smtp. You can use the same condition (with different parameters) more than once in the same ACL statement. This provides a way of specifying an “and” conjunction. The conditions are as follows:
The possible values of the argument are the same as for the acl_smtp_xxx options. The named or inline ACL is run. If it returns “accept” the condition is true; if it returns “deny” the condition is false. If it returns “defer”, the current ACL returns “defer” unless the condition is on a warn verb. In that case, a “defer” return makes the condition false. This means that further processing of the warn verb ceases, but processing of the ACL continues.
If the nested acl returns “drop” and the outer condition denies access, the connection is dropped. If it returns “discard”, the verb must be accept or discard, and the action is taken immediately – no further conditions are tested.
ACLs may be nested up to 20 deep; the limit exists purely to catch runaway loops. This condition allows you to use different ACLs in different circumstances. For example, different ACLs can be used to handle RCPT commands for different local users or different local domains.
If the SMTP connection is not authenticated, the condition is false. Otherwise, the name of the authenticator is tested against the list. To test for authentication by any authenticator, you can set
authenticated = *
This feature allows you to make up custom conditions. If the result of expanding the string is an empty string, the number zero, or one of the strings “no” or “false”, the condition is false. If the result is any non-zero number, or one of the strings “yes” or “true”, the condition is true. For any other value, some error is assumed to have occurred, and the ACL returns “defer”. However, if the expansion is forced to fail, the condition is ignored. The effect is to treat it as true, whether it is positive or negative.
This condition is available only when Exim is compiled with the content-scanning extension, and it is allowed only in the ACL defined by acl_smtp_mime. It causes the current MIME part to be decoded into a file. If all goes well, the condition is true. It is false only if there are problems such as a syntax error or a memory shortage. For more details, see chapter 41.
This condition is available only when Exim is compiled with the content-scanning extension. Its use is described in section 41.6.
This condition checks for entries in DNS black lists. These are also known as “RBL lists”, after the original Realtime Blackhole List, but note that the use of the lists at mail-abuse.org now carries a charge. There are too many different variants of this condition to describe briefly here. See sections 40.24–40.34 for details.
This condition is relevant only after a RCPT command. It checks that the domain of the recipient address is in the domain list. If percent-hack processing is enabled, it is done before this test is done. If the check succeeds with a lookup, the result of the lookup is placed in $domain_data until the next domains test.
Note carefully (because many people seem to fall foul of this): you cannot use domains in a DATA ACL.
If the SMTP connection is not encrypted, the condition is false. Otherwise, the name of the cipher suite in use is tested against the list. To test for encryption without testing for any specific cipher suite(s), set
encrypted = *
This condition tests that the calling host matches the host list. If you have name lookups or wildcarded host names and IP addresses in the same host list, you should normally put the IP addresses first. For example, you could have:
accept hosts = 10.9.8.7 : dbm;/etc/friendly/hosts
The lookup in this example uses the host name for its key. This is implied by the lookup type “dbm”. (For a host address lookup you would use “net-dbm” and it wouldn’t matter which way round you had these two items.)
The reason for the problem with host names lies in the left-to-right way that Exim processes lists. It can test IP addresses without doing any DNS lookups, but when it reaches an item that requires a host name, it fails if it cannot find a host name to compare with the pattern. If the above list is given in the opposite order, the accept statement fails for a host whose name cannot be found, even if its IP address is 10.9.8.7.
If you really do want to do the name check first, and still recognize the IP address even if the name lookup fails, you can rewrite the ACL like this:
accept hosts = dbm;/etc/friendly/hosts accept hosts = 10.9.8.7
The default action on failing to find the host name is to assume that the host is not in the list, so the first accept statement fails. The second statement can then check the IP address.
If a hosts condition is satisfied by means of a lookup, the result of the lookup is made available in the $host_data variable. This allows you, for example, to set up a statement like this:
deny hosts = net-lsearch;/some/file message = $host_data
which gives a custom error message for each denied host.
This condition is relevant only after a RCPT command. It checks that the local part of the recipient address is in the list. If percent-hack processing is enabled, it is done before this test. If the check succeeds with a lookup, the result of the lookup is placed in $local_part_data, which remains set until the next local_parts test.
This condition is available only when Exim is compiled with the content-scanning extension. It causes the incoming message to be scanned for viruses. For details, see chapter 41.
This condition is available only when Exim is compiled with the content-scanning extension, and it is allowed only in the ACL defined by acl_smtp_mime. It causes the current MIME part to be scanned for a match with any of the regular expressions. For details, see chapter 41.
This condition can be used to limit the rate at which a user or host submits messages. Details are given in section 40.35.
This condition is relevant only after a RCPT command. It checks the entire recipient address against a list of recipients.
This condition is available only when Exim is compiled with the content-scanning extension, and is available only in the DATA, MIME, and non-SMTP ACLs. It causes the incoming message to be scanned for a match with any of the regular expressions. For details, see chapter 41.
This condition tests the domain of the sender of the message against the given domain list. Note: The domain of the sender address is in $sender_address_domain. It is not put in $domain during the testing of this condition. This is an exception to the general rule for testing domain lists. It is done this way so that, if this condition is used in an ACL for a RCPT command, the recipient’s domain (which is in $domain) can be used to influence the sender checking.
Warning: It is a bad idea to use this condition on its own as a control on relaying, because sender addresses are easily, and commonly, forged.
This condition tests the sender of the message against the given list. To test for a bounce message, which has an empty sender, set
senders = :
Warning: It is a bad idea to use this condition on its own as a control on relaying, because sender addresses are easily, and commonly, forged.
This condition is available only when Exim is compiled with the content-scanning extension. It causes the incoming message to be scanned by SpamAssassin. For details, see chapter 41.
This condition is true in an SMTP session if the session is encrypted, and a certificate was received from the client, and the certificate was verified. The server requests a certificate only if the client matches tls_verify_hosts or tls_try_verify_hosts (see chapter 39).
This condition checks whether the sending host (the client) is authorized to send email. Details of how this works are given in section 40.46.
This condition is relevant only in an ACL that is run after a message has been received, that is, in an ACL specified by acl_smtp_data or acl_not_smtp. It checks that there is a verifiable address in at least one of the Sender:, Reply-To:, or From: header lines. Such an address is loosely thought of as a “sender” address (hence the name of the test). However, an address that appears in one of these headers need not be an address that accepts bounce messages; only sender addresses in envelopes are required to accept bounces. Therefore, if you use the callout option on this check, you might want to arrange for a non-empty address in the MAIL command.
Details of address verification and the options are given later, starting at section 40.40 (callouts are described in section 40.41). You can combine this condition with the senders condition to restrict it to bounce messages only:
deny senders = :
message = A valid sender header is required for bounces
!verify = header_sender
This condition is relevant only in an ACL that is run after a message has been received, that is, in an ACL specified by acl_smtp_data or acl_not_smtp. It checks the syntax of all header lines that can contain lists of addresses (Sender:, From:, Reply-To:, To:, Cc:, and Bcc:). Unqualified addresses (local parts without domains) are permitted only in locally generated messages and from hosts that match sender_unqualified_hosts or recipient_unqualified_hosts, as appropriate.
Note that this condition is a syntax check only. However, a common spamming ploy used to be to send syntactically invalid headers such as
To: @
and this condition can be used to reject such messages, though they are not as common as they used to be.
This condition is true if a HELO or EHLO command has been received from the client host, and its contents have been verified. If there has been no previous attempt to verify the HELO/EHLO contents, it is carried out when this condition is encountered. See the description of the helo_verify_hosts and helo_try_verify_hosts options for details of how to request verification independently of this condition.
For SMTP input that does not come over TCP/IP (the -bs command line option), this condition is always true.
This condition checks that there are no blind (bcc) recipients in the message. Every envelope recipient must appear either in a To: header line or in a Cc: header line for this condition to be true. Local parts are checked case-sensitively; domains are checked case-insensitively. If Resent-To: or Resent-Cc: header lines exist, they are also checked. This condition can be used only in a DATA or non-SMTP ACL.
There are, of course, many legitimate messages that make use of blind (bcc) recipients. This check should not be used on its own for blocking messages.
This condition is relevant only after a RCPT command. It verifies the current recipient. Details of address verification are given later, starting at section 40.40. After a recipient has been verified, the value of $address_data is the last value that was set while routing the address. This applies even if the verification fails. When an address that is being verified is redirected to a single address, verification continues with the new address, and in that case, the subsequent value of $address_data is the value for the child address.
This condition ensures that a verified host name has been looked up from the IP address of the client host. (This may have happened already if the host name was needed for checking a host list, or if the host matched host_lookup.) Verification ensures that the host name obtained from a reverse DNS lookup, or one of its aliases, does, when it is itself looked up in the DNS, yield the original IP address.
If this condition is used for a locally generated message (that is, when there is no client host involved), it always succeeds.
This condition is relevant only after a MAIL or RCPT command, or after a message has been received (the acl_smtp_data or acl_not_smtp ACLs). If the message’s sender is empty (that is, this is a bounce message), the condition is true. Otherwise, the sender address is verified.
If there is data in the $address_data variable at the end of routing, its value is placed in $sender_address_data at the end of verification. This value can be used in subsequent conditions and modifiers in the same ACL statement. It does not persist after the end of the current statement. If you want to preserve the value for longer, you can save it in an ACL variable.
Details of verification are given later, starting at section 40.40. Exim caches the result of sender verification, to avoid doing it more than once per message.
This is a variation of the previous option, in which a modified address is verified as a sender.
In its simplest form, the dnslists condition tests whether the calling host is on at least one of a number of DNS lists by looking up the inverted IP address in one or more DNS domains. For example, if the calling host’s IP address is 192.168.62.43, and the ACL statement is
deny dnslists = blackholes.mail-abuse.org : \
dialups.mail-abuse.org
the following records are looked up:
43.62.168.192.blackholes.mail-abuse.org 43.62.168.192.dialups.mail-abuse.org
As soon as Exim finds an existing DNS record, processing of the list stops. Thus, multiple entries on the list provide an “or” conjunction. If you want to test that a host is on more than one list (an “and” conjunction), you can use two separate conditions:
deny dnslists = blackholes.mail-abuse.org
dnslists = dialups.mail-abuse.org
If a DNS lookup times out or otherwise fails to give a decisive answer, Exim behaves as if the host does not match the list item, that is, as if the DNS record does not exist. If there are further items in the DNS list, they are processed.
This is usually the required action when dnslists is used with deny (which is the most common usage), because it prevents a DNS failure from blocking mail. However, you can change this behaviour by putting one of the following special items in the list:
+include_unknown behave as if the item is on the list+exclude_unknown behave as if the item is not on the list (default)+defer_unknown give a temporary errorEach of these applies to any subsequent items on the list. For example:
deny dnslists = +defer_unknown : foo.bar.example
Testing the list of domains stops as soon as a match is found. If you want to warn for one list and block for another, you can use two different statements:
deny dnslists = blackholes.mail-abuse.org
warn message = X-Warn: sending host is on dialups list
dnslists = dialups.mail-abuse.org
DNS list lookups are cached by Exim for the duration of the SMTP session, so a lookup based on the IP address is done at most once for any incoming connection. Exim does not share information between multiple incoming connections (but your local name server cache should be active).
By default, the IP address that is used in a DNS list lookup is the IP address of the calling host. However, you can specify another IP address by listing it after the domain name, introduced by a slash. For example:
deny dnslists = black.list.tld/192.168.1.2
This feature is not very helpful with explicit IP addresses; it is intended for use with IP addresses that are looked up, for example, the IP addresses of the MX hosts or nameservers of an email sender address. For an example, see section 40.27 below.
There are some lists that are keyed on domain names rather than inverted IP addresses (see for example the domain based zones link at http://www.rfc-ignorant.org/). No reversing of components is used with these lists. You can change the name that is looked up in a DNS list by listing it after the domain name, introduced by a slash. For example,
deny message = Sender's domain is listed at $dnslist_domain
dnslists = dsn.rfc-ignorant.org/$sender_address_domain
This particular example is useful only in ACLs that are obeyed after the RCPT or DATA commands, when a sender address is available. If (for example) the message’s sender is user@tld.example the name that is looked up by this example is
tld.example.dsn.rfc-ignorant.org
A single dnslists condition can contain entries for both names and IP addresses. For example:
deny dnslists = sbl.spamhaus.org : \
dsn.rfc-ignorant.org/$sender_address_domain
The first item checks the sending host’s IP address; the second checks a domain name. The whole condition is true if either of the DNS lookups succeeds.
The syntax described above for looking up explicitly-defined values (either names or IP addresses) in a DNS blacklist is a simplification. After the domain name for the DNS list, what follows the slash can in fact be a list of items. As with all lists in Exim, the default separator is a colon. However, because this is a sublist within the list of DNS blacklist domains, it is necessary either to double the separators like this:
dnslists = black.list.tld/name.1::name.2
or to change the separator character, like this:
dnslists = black.list.tld/<;name.1;name.2
If an item in the list is an IP address, it is inverted before the DNS blacklist domain is appended. If it is not an IP address, no inversion occurs. Consider this condition:
dnslists = black.list.tld/<;192.168.1.2;a.domain
The DNS lookups that occur are:
2.1.168.192.black.list.tld a.domain.black.list.tld
Once a DNS record has been found (that matches a specific IP return address, if specified – see section 40.30), no further lookups are done. If there is a temporary DNS error, the rest of the sublist of domains or IP addresses is tried. A temporary error for the whole dnslists item occurs only if no other DNS lookup in this sublist succeeds. In other words, a successful lookup for any of the items in the sublist overrides a temporary error for a previous item.
The ability to supply a list of items after the slash is in some sense just a syntactic convenience. These two examples have the same effect:
dnslists = black.list.tld/a.domain : black.list.tld/b.domain dnslists = black.list.tld/a.domain::b.domain
However, when the data for the list is obtained from a lookup, the second form is usually much more convenient. Consider this example:
deny message = The mail servers for the domain \
$sender_address_domain \
are listed at $dnslist_domain ($dnslist_value); \
see $dnslist_text.
dnslists = sbl.spamhaus.org/<|${lookup dnsdb {>|a=<|\
${lookup dnsdb {>|mxh=\
$sender_address_domain} }} }
Note the use of >| in the dnsdb lookup to specify the separator for
multiple DNS records. The inner dnsdb lookup produces a list of MX hosts
and the outer dnsdb lookup finds the IP addresses for these hosts. The result
of expanding the condition might be something like this:
dnslists = sbl.spahmaus.org/<|192.168.2.3|192.168.5.6|...
Thus, this example checks whether or not the IP addresses of the sender domain’s mail servers are on the Spamhaus black list.
The key that was used for a successful DNS list lookup is put into the variable $dnslist_matched (see section 40.29).
DNS lists are constructed using address records in the DNS. The original RBL just used the address 127.0.0.1 on the right hand side of each record, but the RBL+ list and some other lists use a number of values with different meanings. The values used on the RBL+ list are:
Section 40.30 below describes how you can distinguish between different values. Some DNS lists may return more than one address record; see section 40.32 for details of how they are checked.