Exim Specification - 45. Verification of incoming mail

Go to the first, previous, next, last section, table of contents.

# 45. Verification of incoming mail

Exim always checks the syntax of SMTP commands, and rejects any that are invalid. There are a number of options that cause Exim to verify the semantic validity of the data in an incoming SMTP message. Verification failures can cause the message to be rejected, or they can just be logged. Other types of control over incoming mail are discussed in subsequent chapters. The -bh command line option can be used to run fake SMTP sessions for the purpose of testing verification options.

## 45.1 Host verification

The name of the sending host is looked up using gethostbyaddr() if its IP address matches host_lookup (which is unset in the Exim binary, but in the default configuration file is set to match all hosts). In some environments this might involve an expensive DNS lookup, so some sites may wish to disable it. However, an SMTP server for local desktop systems (which are frequently misconfigured) can normally look up their host names cheaply. This improves the contents of Exim's logs by including the correct host names.

Even if its address doesn't match host_lookup, a sending host's real name is looked up from its IP address if the argument it provides for the HELO or EHLO command is the local host's own name, or the name of one of its local domains, which seems to be a fairly common misconfiguration.

A host name that is obtained from looking up the sender's IP address is placed in the $sender_host_name variable. If no lookup was done, or if the lookup failed, that variable is left empty. Failure to look up the sending host's name is not of itself an error, nor is it by default an error for the name given in the HELO or EHLO command (which is placed in $sender_helo_name) to be different.

The RFCs specifically state that mail should not be refused on the basis of the content of the HELO or EHLO commands. However, there are installations that do want to be strict in this area, and to support them, Exim has the helo_verify option. Even when this is not set, Exim checks the syntax of the commands, and rejects them if there are syntax errors. It can be made less strict by unsetting helo_strict_syntax (which allows underscores to get through) or by setting helo_accept_junk_hosts (which permits certain hosts to send any old junk).

When helo_verify is set, a HELO or EHLO command must precede any MAIL commands in an incoming SMTP connection. If there wasn't one, all MAIL commands are rejected with a permanent error code. In addition, the argument supplied by HELO or EHLO is verified. If it is in the form of a literal IP address in square brackets, it must match the actual IP address of the sending host. If it is a domain name, the sending host's name is looked up from its IP address (whether or not it matches host_lookup) and compared against it. If the comparison fails, the IP addresses associated with the HELO or EHLO name are looked up using gethostbyname() and compared against the sending host's IP address. If none of them match, the HELO or EHLO command is rejected with a permanent error code, and an entry is written in the main and reject logs.

## 45.2 Sender verification

When sender_verify is set, Exim checks the senders of incoming SMTP messages, that is, the addresses given in the SMTP MAIL commands. This does not apply to batch SMTP input by default, but sender_verify_batch can be set true if it is required. The check is performed by running the same verification code as is used when Exim is called with the -bvs option, that is, by running the directors and routers in verify mode.

A dilemma arises when a local address is expanded by aliasing or forwarding: should verification continue with the generated addresses, or should the successful expansion of the original address be enough to verify it? Exim (since release 3.20) takes the following pragmatic approach:

- When an incoming address is aliased to just one child address, in an aliasfile or a smartuser director (but not for forwardfile), verification continues with the child address, and if that fails to verify, the original verification also fails.

This seems the most reasonable behaviour for the common use of aliasing as a way of directing different local parts to the same mailbox. It means, for example, that a pair of alias entries of the form

    A.Wol:   aw123
    aw123:   :fail: Gone away, no forwarding address

work as expected, with both local parts causing verification failure. On the other hand, when an alias generates more than one address, the behaviour is more like a mailing list, where the existence of the alias itself is sufficient for verification.

The sender verification check is performed when the MAIL command is received. If the address cannot immediately be verified (typically because of DNS timeouts), a temporary failure error response (code 451) is given after the data for the message has been received. It is delayed until this time so that the message's headers can be logged. However, if sender_try_verify is set, the sender is accepted with a warning message after a temporary verification failure.

Exim remembers temporary sender verification errors in a hints database. Subsequent temporary errors for the same address from the same host within 24 hours cause a 451 error after MAIL instead of after the data. This reduces the data on the reject log and also the amount repeatedly transferred over the net.

If sender_verify_max_retry_rate is set greater than zero, and the rate of temporary rejection of a specific incoming sender address from a specific host, in units of rejections per hour, exceeds it, the temporary error is converted into a permanent verification error. This should help in stopping hosts hammering too frequently with temporarily failing sender addresses. The default value of the option is 12, which means that a sender address that has a temporary verification error more than once every 5 minutes will soon get permanently rejected. Once permanent rejection has been triggered, subsequent temporary failures will all cause permanent errors, until there has been an interval of at least 24 hours since the last failure. After 24 hours, the hint expires.

What happens if verification fails with a permanent error depends on the setting of the sender_verify_reject option. If it is set (the default) then the message is rejected. Otherwise a warning message is logged, and processing continues.

Because remote postmasters always want to see the message headers when there is a problem, Exim does not give an error response immediately a sender address fails, but instead it reads the data for the message first. The headers of rejected messages are written to the reject log, for use in tracking down the problem or tracing mail abusers. Up to three envelope recipients are also logged with the headers.

Unfortunately, there are a number of mailers in use that treat any SMTP error response given after the data has been transmitted as a temporary failure. Exim sends code 550 when it rejects a message because of a bad sender, and RFC 821 is quite clear in stating that all codes starting with 5 are always `permanent negative completion' replies. However, it does not give any guidance as to what should be done on receiving such replies, and some mailers persist in trying to send messages when they receive such a code at the end of the data.

To get round this, Exim keeps a database in which it remembers the bad sender address and host name when it rejects a message. If the same host sends the same bad sender address within 24 hours, Exim rejects the message at the MAIL command, before it reads the data for the message. This should prevent the sender from trying to send the message again, but there seem to be plenty of broken mailers out there that do keep on trying, sometimes for days on end.

In an attempt to shut such MTAs up, if the same host sends the same bad sender for a third time within 24 hours, MAIL is accepted, but all subsequent RCPT commands are rejected with a 550 error code. This means `unknown user' and if a remote mailer doesn't treat that as a hard error, it is very seriously broken.

The sender_verify_hosts option can be used to restrict hosts and RFC 1413 idents for which sender verification is not applied. If a cluster of hosts all check incoming external messages, there is no need to waste effort checking mail sent between them. For example:

    sender_verify_hosts = ! *.ref.book : ! exim@mailer.fict.book

## 45.3 Sender verification with callback

When Exim verifies a remote sender address by running it through the routers, as described above, it verifies the domain, but is unable to do any checking of the local part. There are situations where some means of verifying the local part is desirable, and this can be setup by configuring Exim to use an SMTP callback. If the domain in the remote address verifies successfully when calling back is enabled, Exim makes an SMTP call to the hosts to which the sender's domain resolves, and tests the address as if it were the recipient of a bounce message. Specifically, it sends

    HELO <primary host name>
    MAIL FROM:<>
    RCPT TO:<the address to be tested>
    QUIT

If the response to the RCPT command is a 2xx code, the verification succeeds. If it is 5xx, the verification fails. For anything else, and in cases when Exim cannot contact any of the relevant hosts, verification fails with a temporary error code.

Callback verification occurs only if the sending host matches sender_verify_hosts_callback (in addition to sender_verify_hosts), and the sender's domain matches sender_verify_callback_domains. Both of these options default unset. There is also an option called sender_verify_callback_timeout which sets a timeout for connecting and for each command. It defaults to 30 seconds. Callback verification is expensive, and not recommended for general use, especially on busy hosts. Two cases where it might be useful are:

- On a small host that handles only a few messages a day, to keep out junk with valid domains but invalid local parts in the senders, something that is commonly encountered in spam messages. For this you would set

      sender_verify_hosts_callback = *
      sender_verify_callback_domains = *

- On a corporate gateway, to check sender addresses in domain(s) that are `yours' in some sense, but not local (in the Exim sense). This could be restricted to messages received from your on-site hosts.

## 45.4 Fixing bad senders

It is unfortunately the case that lots of messages are sent out onto the Internet with invalid senders. In some cases, the message itself contains a valid return address in one of its headers. If the sender_verify_fixup option is set as well as sender_verify, Exim does not reject a message if the sender is invalid, provided it can find a Sender:, Reply-To:, or From: header containing a valid address. Instead, it replaces the sender with the valid address, and records the fact that it has done so by adding a header of the form:

    X-BadReturnPath: <invalid address> rewritten using <name> header

If there are several occurrences of any of the relevant headers, they are all checked. If any ``Resent-'` headers exist, it is those headers that are checked rather than the original ones.

The fixup happens for both permanent and temporary errors. This covers the case when the bad addresses refer to some DNS zone whose nameservers are unreachable. This approach is, of course, fixing the symptom and not the disease. If sender_verify_fixup is set when sender_verify_reject is false, Exim does not modify the message, but records in the log the fixup it would have made.

## 45.5 Header verification

Exim's sender verification options can be used to block messages with bad envelope senders. However, if a message arrives with a null envelope sender, that is, if the SMTP command was

    MAIL FROM:<>

then Exim has nothing to check, and is forced to accept the message (unless it fails another check, of course). If headers_sender_verify_errmsg is set, then for messages that have null senders (purporting to be mail delivery error messages), Exim does some checking of the RFC 822 headers. It looks for a valid address in the Sender:, Reply-To:, and From: headers, and if one cannot be found, the message is rejected, unless headers_checks_fail is false, in which case it just makes a warning entry in the reject log.

If there are several occurrences of any of the relevant headers, they are all checked. If any ``Resent-'` headers exist, it is those headers that are checked rather than the original ones.

Unfortunately, because it has to read the message before doing this check, the rejection happens after the end of the data, and it is known that some mailers do not treat hard (5xx) errors correctly at this point -- they keep the message on their spools and try again later, but that is their problem, though it does waste some resources.

The option headers_sender_verify is also available. It insists on there being a valid Sender:, Reply-To:, or From: header on all incoming SMTP messages, not just those with null senders.

The sender_verify_hosts option applies to both of these header checking options as well as to checks on envelope senders (sender_verify).

A common spamming ploy is to send syntactically invalid headers such as

    To: @

The option headers_check_syntax causes Exim to check the syntax of all headers that can contain lists of addresses (Sender:, From:, Reply-To:, To:, Cc:, and Bcc:) on all incoming messages (both local and SMTP). This is a syntax check only. Like the headers_sender_verify options, the rejection happens after the end of the data, and it is also controlled by headers_checks_fail; if that is false, a bad message is accepted, with a warning in the reject log.

## 45.6 Receiver verification

By default, Exim just checks the syntax of addresses given in the SMTP RCPT command. This minimizes the time required for an SMTP message transfer, and also makes it possible to provide special processing for unknown local parts in local domains, by using a smartuser director to pass messages with unknown local parts to a script or to another host.

Some installations prefer to check receiver addresses as they are received. If the receiver_verify option is set, the same code that is used by the -bv option is used to check incoming addresses from remote hosts that match receiver_verify_hosts, whose default setting is to match all hosts. Verification consists of running the directors and routers in verify mode. As in the case of sender verification, when an incoming address is aliased to just one child address, in an aliasfile or a smartuser director (but not for forwardfile), verification continues with the child address, and if that fails to verify, the original verification also fails.

When verification fails, a permanent negative response is given to the RCPT command. If there is a temporary failure, a temporary error is given, unless receiver_try_verify is set, in which case the address is accepted.

It is possible to restrict the addresses that are verified to certain domains by setting receiver_verify_addresses, and receiver verification can also be made conditional on the sender address by setting receiver_verify_senders. All of these options operate only when receiver_verify or receiver_try_verify is set.

Go to the first, previous, next, last section, table of contents.