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


SMTP processing

Two kinds of SMTP processing are supported: SMTP over TCP/IP, and so-called `batched SMTP'. The latter is the name for a process in which batches of messages are stored in files, using SMTP commands as separators and to contain the envelope information. Such batches are delivered to or received from other systems using some transport mechanism other than Exim. For each kind of SMTP processing there are two aspects: outgoing and incoming.

Outgoing SMTP over TCP/IP

This is implemented by the `smtp' transport. If the greeting line from the remote host contains the string `ESMTP', Exim sends an EHLO command instead of HELO, and if it is told that the SIZE parameter is supported, it adds SIZE=<n> to each subsequent MAIL FROM command. The value of <n> is the message size plus the value of the `size_addition' option (default 1024) to allow for additions to the message such as per-transport header lines, or changes made in a transport filter. If `size_addition' is set negative, the use of SIZE is suppressed.

Responses from the remote host are supposed to be terminated by CR followed by LF. However, there are known to be hosts that do not send CR characters, so in order to be able to interwork with such hosts, Exim treats LF on its own as a line terminator.

If a message contains a number of different addresses, all those with the same characteristics (for example, the same envelope sender) that resolve to the same set of hosts, in the same order, are sent in a single SMTP transaction, even if they are for different domains, unless there are more than the setting of the `max_rcpts' option in the `smtp' transport allows, in which case they are split into groups containing no more than `max_rcpts' addresses each. If `remote_max_parallel' is greater than one, such groups may be sent in parallel sessions. The order of hosts with identical MX values is not significant when checking whether addresses can be batched in this way.

Exim's retry hints are based on host name plus IP address, so if one address of a multi-homed host is broken, it will soon be skipped most of the time. When the `smtp' transport suffers a temporary failure while trying to deliver a message, Exim updates its `wait-smtp' database, which contains records indexed by host name that remember which messages are waiting for each particular host.

When a message is successfully delivered over a TCP/IP SMTP connection, Exim looks in the `wait-smtp' database to see if there are any queued messages waiting for the host to which it is connected. If it finds one, it creates a new process using the `-MC' option (which can only be used by a process running as root or the Exim user) and passes the TCP/IP socket to it. The new process does only those deliveries that are routed to the connected host, and may in turn pass the socket on to a third process, and so on. The `batch_max' option of the `smtp' transport can be used to limit the number of messages sent down a single connection. The second and subsequent messages delivered down an SMTP connection are identified in the main log by the addition of an asterisk after the closing square bracket of the IP address.

Incoming SMTP messages over TCP/IP

Incoming SMTP messages can be accepted in one of two ways: by running a listening daemon, or by using `inetd'. In the latter case, the entry in `/etc/inetd.conf' should be like this:


smtp  stream  tcp  nowait  exim  /opt/exim/bin/exim  in.exim  -bs

Exim distinguishes between this case and the case of a user agent using the `-bs' option by checking whether the standard input is a socket using the `getpeername()' function.

Commands from the remote host are supposed to be terminated by CR followed by LF. However, there are known to be hosts that do not send CR characters, so in order to be able to interwork with such hosts, Exim treats LF on its own as a line terminator.

The amount of disc space available is checked whenever SIZE is received on a MAIL FROM command, independently of whether `message_size_limit' or `check_spool_space' is configured. A temporary error is given if there isn't enough. If `check_spool_space' is set, the check is for that amount of space plus the value given with SIZE, that is, it checks that the addition of the incoming message will not reduce the space below the threshold.

When a message is successfully received, Exim includes the local message id in its response to the final `.' that terminates the data. If the remote host logs this text it can help with tracing what has happened to a message.

The Exim daemon can limit the number of simultaneous incoming connections it is prepared to handle (see the `smtp_accept_max' configuration option). Additional connection attempts are rejected using the SMTP temporary error code 421. On some operating systems the SIGCHLD signal that is used to detect when a subprocess has finished can get lost at busy times. However, the daemon looks for completed subprocesses every time it wakes up, so provided there are other things happening (new incoming calls, starts of queue runs), the completion of processes created to handle incoming calls should get noticed eventually. If, however, Exim appears not to be accepting as many incoming connections as expected, sending the daemon a SIGCHLD signal will wake it up and cause it to check for any completed subprocesses.

Exim can reserve some SMTP slots for specific hosts or networks, and can also be set up to reject SMTP calls from non-reserved hosts or networks at times of high system load -- for details see the `smtp_accept_reserve', `smtp_load_reserve', `smtp_reserve_hosts' and `smtp_reserve_nets' configuration options.

If neither `queue_only' nor the `-odq' command line option is set, the daemon normally starts a delivery process for each message received. However, the number of simultaneously running delivery processes started in this way can be limited by the `smtp_accept_queue' option, and the `queue_only_load' option can specify a system load average above which immediate delivery is suspended. When either limit is reached, subsequently received messages are just put on the input queue.

The controls that involve counts of incoming SMTP calls (`smtp_accept_max' and `smtp_accept_reserve') are not available when Exim is started up from the `inetd' daemon, since each connection is handled by an entirely separate Exim process. Control by load average is, however, available.

The VRFY, EXPN, and DEBUG commands

The SMTP command VRFY is accepted only when the configuration option `smtp_verify' is set, and if so, it runs exactly the same code as when Exim is called with the `-bv' option.

The SMTP command EXPN is is permitted only if the calling host matches `smtp_expn_hosts' (add `localhost' if you want calls to 127.0.0.1 to be able to use it) or `smtp_expn_nets'. A single-level expansion of the address is done. If an unqualified local part is given as the argument to EXPN, it is qualified with `qualify_domain'.

The SMTP command DEBUG is not supported at all.

The ETRN command

RFC 1985 describes an SMTP command called ETRN that is designed to overcome the security problems of the TURN command (which has fallen into disuse). Exim recognizes ETRN if the calling host matches an entry in `smtp_etrn_hosts' or `smtp_etrn_nets'. The ETRN command is concerned with `releasing' messages that are awaiting delivery to certain hosts. As Exim does not organize its message queue by host, the only form of ETRN that is internally supported is the one where the text starts with the `#' prefix, in which case the remainder of the text is specific to the SMTP server. A valid ETRN command causes a run of Exim with the `-R' option to happen, with the remainder of the ETRN text as its argument. For example,


ETRN #brigadoon

causes a delivery attempt on all messages with undelivered addresses containing the text `brigadoon'.

For more control over what ETRN does, the `smtp_etrn_command' option can used. This specifies a command that is run whenever ETRN is received. For example:


smtp_etrn_command = /etc/etrn_command $domain $sender_host_address

The string is split up into arguments which are independently expanded. The expansion variable `$domain' is set to the argument of the ETRN command, and no syntax checking is done on the contents of this argument. A new freestanding process is created to run the command. Exim does not wait for it to complete, so its status code is not checked. As Exim is normally running under its own uid and gid when receiving incoming SMTP, it is not possible for it to change them before running the command.

Outgoing batched SMTP

Both the `appendfile' and `pipe' transports can be used for handling batched SMTP. Each has an option called `bsmtp' which, if set to anything other than `none' causes the message to be output in SMTP format. The message is written to the file or pipe preceded by the SMTP commands MAIL FROM and RCPT TO, and followed by a line containing a single dot. The SMTP command HELO is not normally used, but if the transport's `bsmtp_helo' option is set true, a HELO command line precedes each message.

Lines in the message starting with a dot get an extra dot added. If the `prefix' option is set, its contents are included after the SMTP commands, and the contents of `suffix' apear at the end of the message, before the terminating dot; normally these options are specified as empty, to override the defaults.

The value of the `bsmtp' option determines how multiple addresses in a single message may be batched, if other conditions permit. If the value of `bsmtp' is `one', then there is no batching, and a copy of the message is output for each address. If the value is `domain' then a single copy (with multiple RCPT TO commands) is output for all addresses that have the same domain. If the value is `all' then only a single copy of the message is written. The batching is further constrained by other parameters:

Here is an example of a transport and router for batched SMTP:


# transport
smtp_appendfile:
  driver = appendfile
  directory = /var/bsmtp/${host}
  bsmtp = all
  prefix =
  suffix =
  user = exim

# router
route_append:
  driver = domainlist
  transport = smtp_appendfile
  route_list = "some.domain  batch.host"

This causes messages addressed to `some.domain' to be written in batched SMTP format to `/var/bsmtp/batch.host', with only a single copy of each message. Note that prefix and suffix must be explicitly changed from their defaults.

Incoming batched SMTP

The `-bS' command line option causes Exim to accept one or more messages by reading SMTP on the standard input, but to generate no responses. All errors are reported by sending mail. If the caller is trusted, then the senders in the MAIL FROM commands are believed; otherwise the sender is always the caller of Exim. Unqualified senders and receivers are not rejected (there seems little point) but instead just get qualified. If `sender_verify' is set, sender verification takes place unless `sender_verify_batch' is false. Receiver verification and administrative rejection is not done, even if configured. HELO and EHLO act as RSET; VRFY, EXPN, ETRN, HELP, and DEBUG act as NOOP; QUIT quits.


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