Exim Specification - 18. The pipe transport

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

# 18. The pipe transport

The pipe transport is used to deliver messages via a pipe to a command running in another process. This can happen when when a director explicitly directs a message to a pipe transport, and also when an address is expanded via an alias, filter, or forward file that specifies a pipe command. In this case, $local_part contains the local part that was aliased or forwarded, while $address_pipe contains the text of the pipe command itself.

A pipe transport can also be used from a router as a pseudo-remote transport for passing messages for remote delivery by some means other than Exim.

As pipe is a local transport, it is always run in a separate process, normally under a non-privileged uid and gid. In the common case, these are the uid and gid belonging to the user whose ``.forward'` file directed the message at the pipe. In other cases the uid and gid have to be specified explicitly, either on the transport or on the director or router that handled the address. Current and `home' directories are also controllable. See chapter 13 for details of the local delivery environment.

## 18.1 Returned status and data

If the command exits with a non-zero return code, the delivery is deemed to have failed, unless either the ignore_status option is set (in which case the return code is treated as zero), or the return code is one of those listed in the temp_errors option, which are interpreted as meaning `try again later'. In this case, delivery is deferred.

If the return code is greater than 128 and the command being run is a shell script, it normally means that the script was terminated by a signal whose value is the return code minus 128.

The return_output option can affect the result of a pipe delivery. If it is set and the command produces any output on its standard output or standard error files, it is considered to have failed, even if it gave a zero return code or if ignore_status is set. The output from the command is sent as part of the delivery failure report. However, if return_fail_output is set, output is returned only when the command exits with a failure return code, that is, a value other than zero or a code that matches temp_errors.

## 18.2 How the command is run

The command line is (by default) broken down into a command name and arguments by the pipe transport. The allow_commands and restrict_to_path options can be used to restrict the commands that may be run. Unquoted arguments are delimited by white space; in double-quoted arguments, backslash is interpreted as an escape character in the usual way. This does not happen for single-quoted arguments.

String expansion is applied to the command line except when it comes from a traditional ``.forward'` file (commands from a filter file are expanded). The expansion is applied to each argument in turn rather than to the whole line. For this reason, any string expansion item that contains white space must be quoted so as to be contained within a single argument. A setting such as

    command = /some/path ${if eq{$local_part}{postmaster}{xxx}{yyy}}

will not work, because the expansion item gets split between several arguments. You have to write

    command = /some/path "${if eq{$local_part}{postmaster}{xxx}{yyy}}"

to ensure that it is all in one argument. If the whole command line is quoted, then the internal quotes have to be escaped with backslashes (or single quotes can be used). The expansion is done in this way, argument by argument, so that the number of arguments cannot be changed as a result, and quotes or backslashes in inserted variables do not interact with external quoting.

Special handling takes place when an argument consists precisely of the text `$pipe_addresses'. This is not a general expansion variable; the only place this string is recognized is when it appears as an argument for a pipe or transport filter command. It causes each address that is being handled to be inserted in the argument list at that point as a separate argument. This avoids any problems with spaces or shell metacharacters, and is of use when a pipe transport is handling groups of addresses in a batch (see the batch option below).

The resulting command is then run in a subprocess directly from the transport, not under a shell, with the message supplied on the standard input, and the standard output and standard error both connected to a single pipe that is read by Exim. The max_output option controls how much output the command may produce, and the return_output and return_fail_output options control what is done with it.

Not running the command under a shell (by default) lessens the security risks in cases when a command from a user's filter file is built out of data that was taken from an incoming message. If a shell is required, it can of course be explicitly specified as the command to be run. However, there are circumstances where existing commands (for example, in ``.forward'` files) expect to be run under a shell and cannot easily be modified. To allow for these cases, there is an option called use_shell, which changes the way the pipe transport works. Instead of breaking up the command line as just described, it expands it as a single string and passes the result to /bin/sh. The restrict_to_path option and the $pipe_addresses facility cannot be used with use_shell, and the whole mechanism is inherently less secure.

## 18.3 Environment variables

The following environment variables are set up when the command is invoked:

    DOMAIN               the local domain of the address
    HOME                 the `home' directory -- see below
    HOST                 the host name when called from a router
    LOCAL_PART           see below
    LOGNAME              see below
    MESSAGE_ID           the message's id
    PATH                 as specified by the path option below
    QUALIFY_DOMAIN       the configured qualification domain
    SENDER               the sender of the message
    SHELL                /bin/sh
    USER                 see below

The environment option can be used to add additional variables to this environment.

When a pipe transport is called directly from (for example) a smartuser director, LOCAL_PART is set to the local part of the address. When it is called as a result of a forward or alias expansion, LOCAL_PART is set to the local part of the address that was expanded. LOGNAME and USER are set to the same value as LOCAL_PART for compatibility with other MTAs.

HOST is set only when a pipe transport is called from a router as a pseudo-remote transport (for example, for handling batched SMTP). It is set to the first host name specified by the router (if any).

If the transport's home_directory option is set, its value is used for the HOME environment variable. Otherwise, certain directors may set a home directory value, as described in chapter 13.

## 18.4 Private options for pipe

### allow_commands (pipe)

Type: string list, expanded
Default: unset

The string is expanded, and then is interpreted as a colon-separated list of permitted commands. If restrict_to_path is not set, the only commands permitted are those in the allow_commands list. They need not be absolute paths; the path option is still used for relative paths. If restrict_to_path is set with allow_commands, the command must either be in the allow_commands list, or a name without any slashes that is found on the path. In other words, if neither allow_commands nor restrict_to_path is set, there is no restriction on the command, but otherwise only commands that are permitted by one or the other are allowed. For example, if

    allow_commands = /usr/ucb/vacation

and restrict_to_path is not set, the only permitted command is /usr/ucb/vacation. The allow_commands option may not be set if use_shell is set.

### batch (pipe)

Type: string
Default: "none"

Normally, each address that is directed or routed to a pipe transport is handled separately. In special cases it may be desirable to handle several addresses at once, for example, when passing a message with several addresses to a different mail regime (for example, UUCP). If this option is set to the string `domain', all addresses with the same domain that are directed or routed to the transport are handled in a single delivery. If it is set to `all', multiple domains are batched. The list of addresses is included in the Envelope-to: header if envelope_to_add is set. The addresses can also be set up as separate arguments to the pipe command by means of the specially-recognized argument $pipe_addresses (see above). Otherwise, the only difference between this option and bsmtp is the inclusion of SMTP command lines in the output for bsmtp. When more than one address is being delivered, $local_part is not set, and $domain is set only if they all have the same domain.

### batch_max (pipe)

Type: integer
Default: 100

This limits the number of addresses that can be handled in a batch, and applies to both the batch and the bsmtp options.

### bsmtp (pipe)

Type: string
Default: "none"

This option is used to set up a pipe transport as a pseudo-remote transport for delivering messages in batch SMTP format for onward transmission by some non-Exim means. The value of the option must be one of the strings `none', `one', `domain', or `all'. The first of these turns the feature off. When bstmp is set, the batch option automatically takes the same value. The check_string and escape_string options are forced to the values

    check_string = "."
    escape_string = ".."

when batched SMTP is in use. It is usually necessary to suppress the default settings of the prefix and suffix options. A full description of the batch SMTP mechanism is given in section 48.8. See also the use_crlf option.

### bsmtp_helo (pipe)

Type: boolean
Default: false

When this option is set, a HELO line is added to the output at the start of each message written in batch SMTP format. Some software that reads batch SMTP is unhappy without this.

### check_string (pipe)

Type: string
Default: unset

As pipe writes the message, the start of each line is tested for matching check_string, and if it does, the initial matching characters are replaced by the contents of escape_string, provided both are set. The value of check_string is a literal string, not a regular expression, and the case of any letters it contains is significant. When the bsmtp option is set, the contents of check_string and escape_string are forced to values that implement the SMTP escaping protocol. Any settings made in the configuration file are ignored.

### command (pipe)

Type: string, expanded
Default: unset

This option need not be set when pipe is being used to deliver to pipes obtained from address expansions (usually under the instance name address_pipe). In other cases, the option must be set, to provide a command to be run. It need not yield an absolute path (see the path option below). The command is split up into separate arguments by Exim, and each argument is separately expanded, as described in section 18.2 above.

### current_directory (pipe)

Type: string, expanded
Default: unset

If this option is set, it specifies the directory to make current when running the delivery process. The string is expanded at the time the transport is run. If this is not set, the current directory is taken from data associated with the address. See chapter 13 for full details of the local delivery environment.

### environment (pipe)

Type: string, expanded
Default: unset

This option is used to add additional variables to the environment in which the command runs (see section 18.3 for the default list). Its value is a string which is expanded, and then interpreted as a colon-separated list of environment settings of the form `<name>=<value>'.

### escape_string (pipe)

Type: string
Default: unset

See check_string above.

### freeze_exec_fail (pipe)

Type: boolean
Default: false

Failure to exec the command in a pipe transport is by default treated like any other failure while running the command. However, if freeze_exec_fail is set, failure to exec is treated specially, and causes the message to be frozen, whatever the setting of ignore_status.

### from_hack (pipe)

Type: boolean
Default: false

This option is obsolete and is retained only for backwards compatibility. Its value is ignored. It has been replaced by check_string and escape_string.

### group (pipe)

Type: string
Default: unset

If this option is set, it specifies the group under whose gid the delivery process is to be run. If it is not set, a value associated with a user may be used (see below); otherwise a value must have been associated with the address by the director which handled it. If the string contains no $ characters, it is resolved when Exim starts up. Otherwise, the string is expanded at the time the transport is run, and must yield either a digit string or a name which can be looked up using getgrnam().

### home_directory (pipe)

Type: string, expanded
Default: unset

If this option is set, its expanded value is used to set the HOME environment variable before running the command. This overrides any value that is set by the director. If no current directory is supplied by the director or the transport, the home directory value is used for that as well. See chapter 13 for details of the local delivery environment.

### ignore_status (pipe)

Type: boolean
Default: false

If this option is true, the status returned by the subprocess that is set up to run the command is ignored, and Exim behaves as if zero had been returned. Otherwise, a non-zero status causes an error return from the transport unless the value is EX_TEMPFAIL, which causes the delivery to be deferred and tried again later.

### initgroups (pipe)

Type: boolean
Default: false

If this option is true and the uid for the local delivery is specified by the user option, then the initgroups() function is called when running the transport to ensure that any additional groups associated with the uid are set up.

### log_defer_output (pipe)

Type: boolean
Default: false

If this option is set, and the status returned by the command is one of the codes listed in temp_errors (that is, delivery was deferred), and any output was produced, the first line of it is written to the main log.

### log_fail_output (pipe)

Type: boolean
Default: false

If this option is set, and the command returns any output, and also ends with a return code that is neither zero nor one of the return codes listed in temp_errors (that is, the delivery failed), the first line of output is written to the main log.

### log_output (pipe)

Type: boolean
Default: false

If this option is set and the command returns any output, the first line of output is written to the main log, whatever the return code.

### max_output (pipe)

Type: integer
Default: 20K

This specifies the maximum amount of output that the command may produce on its standard output and standard error file combined. If the limit is exceeded, the process running the command is killed. This is intended as a safety measure to catch runaway processes. The limit is applied whether any return_output option is set or not. Because of buffering effects, the amount of output may exceed the limit by a small amount before Exim notices.

### path (pipe)

Type: string list
Default: "/usr/bin"

This option specifies the string that is set up in the PATH environment variable of the subprocess. If the command option does not yield an absolute path name, the command is sought in the PATH directories, in the usual way.

### pipe_as_creator (pipe)

Type: boolean
Default: false

If user is not set and this option is true, the delivery process is run under the uid that was in force when Exim was originally called to accept the message. If the group id is not otherwise set (via the group option above, or by the director that processed the address), the gid that was in force when Exim was originally called to accept the message is used. Setting this option may be necessary in order to get some free-standing local delivery agents to work correctly. Note, however, that the never_users configuration option overrides.

### prefix (pipe)

Type: string, expanded
Default: see below

The string specified here is expanded and output at the start of every message. The default is the same as for the appendfile transport, namely

    prefix = "From ${if def:return_path{$return_path}{MAILER-DAEMON}}\
      ${tod_bsdinbox}\n"

This is required by the commonly used /usr/ucb/vacation program, but it must not be present if delivery is to the Cyrus IMAP server, or to the tmail local delivery agent. The prefix can be suppressed by setting

    prefix =

This is also usually necessary when doing batch SMTP deliveries.

### restrict_to_path (pipe)

Type: boolean
Default: false

When this option is set, any command name not listed in allow_commands must contain no slashes. The command is searched for only in the directories listed in the path option. This option is intended for use in the case when a pipe command has been generated from a user's ``.forward'` file. This is usually handled by a pipe transport called address_pipe.

### retry_use_local_part (pipe)

Type: boolean
Default: true

When a local delivery suffers a temporary failure, both the local part and the domain are normally used to form a key that is used to determine when next to try the address. This handles common cases such as exceeding a quota, where the failure applies to the specific local part. However, when local delivery is being used to collect messages for onward transmission by some other means, a temporary failure may not depend on the local part at all. Setting this option false causes Exim to use only the domain when handling retries for this transport.

### return_fail_output (pipe)

Type: boolean
Default: false

If this option is true, and the command produced any output and ended with a return code other than zero or one of the codes listed in temp_errors (that is, the delivery failed), the output is returned in the delivery error message. However, if the message has a null sender (that is, it is itself a delivery error message), output from the command is discarded.

### return_output (pipe)

Type: boolean
Default: false

If this option is true, and the command produced any output, the delivery is deemed to have failed whatever the return code from the command, and the output is returned in the delivery error message. Otherwise, the output is just discarded. However, if the message has a null sender (that is, it is a delivery error message), output from the command is always discarded, whatever the setting of this option.

### suffix (pipe)

Type: string, expanded
Default: "\n"

The string specified here is expanded and output at the end of every message. The default is the same as for the appendfile transport. It can be suppressed by setting

    suffix =

and this is usually necessary when doing batch SMTP deliveries.

### temp_errors (pipe)

Type: string
Default: see below

This option contains a colon-separated list of numbers. If ignore_status is false and the command exits with a return code that matches one of the numbers, the failure is treated as temporary and the delivery is deferred. The default setting contains the codes defined by EX_TEMPFAIL and EX_CANTCREAT in sysexits.h. If Exim is compiled on a system that does not define these macros, it assumes values of 75 and 73, respectively.

### timeout (pipe)

Type: time
Default: 1h

If the command fails to complete within this time, it is killed. This normally causes the delivery to fail. A zero time interval specifies no timeout. In order to ensure that any subprocesses created by the command are also killed, Exim makes the initial process a process group leader, and kills the whole process group on a timeout. However, this can be defeated if one of the processes starts a new process group.

### umask (pipe)

Type: octal integer
Default: 022

This specifies the umask setting for the subprocess that runs the command.

### use_crlf (pipe)

Type: boolean
Default: false

This option causes lines to be terminated with the two-character CRLF sequence (carriage return, linefeed) instead of just a linefeed character. In the case of batched SMTP, the byte sequence written to the pipe is then an exact image of what would be sent down a real SMTP connection.

The contents of the prefix and suffix options are written verbatim, so must contain their own carriage return characters if these are needed. Since the default values for both prefix and suffix end with a single linefeed, their values almost always need to be changed if use_crlf is set.

### use_shell (pipe)

Type: boolean
Default: false

If this option is set, it causes the command to be passed to /bin/sh instead of being run directly from the transport as described in section 18.2. This is less secure, but is needed in some situations where the command is expected to be run under a shell and cannot easily be modified. The allow_commands and restrict_to_path options, and the `$pipe_addresses' facility are incompatible with use_shell. The command is expanded as a single string, and handed to /bin/sh as data for its -c option.

### user (pipe)

Type: string
Default: unset

If this option is set, it specifies the user under whose uid the delivery process is to be run. If it is not set, a value must have been associated with the address by the director that handled it. If the string contains no $ characters, it is resolved when Exim starts up. Otherwise, the string is expanded at the time the transport is run, and must yield either a digit string or a name which can be looked up using getpwnam(). When getpwnam() is used, either at start-up time or later, the group id value associated with the user is taken as the value to be used if the group option is not set.

## 18.5 Using an external local delivery agent

The pipe transport can be used to pass all messages that require local delivery to a separate local delivery agent such as procmail. When doing this, care must be taken to ensure that the pipe is run under an appropriate uid and gid. In some configurations one wants this to be a uid that is trusted by the delivery agent to supply the correct sender of the message. It may be necessary to recompile or reconfigure the delivery agent so that it trusts an appropriate user. The following is an example transport and director configuration for procmail:

    # transport
    procmail_pipe:
      driver = pipe
      command = /opt/local/bin/procmail -d $local_part
      return_path_add
      delivery_date_add
      envelope_to_add
      check_string = "From "
      escape_string = ">From "
      user = $local_part
      group = mail

    # director
    procmail:
      driver = localuser
      transport = procmail_pipe

In this example, the pipe is run as the local user, but with the group set to mail. An alternative is to run the pipe as a specific user such as mail or exim, but in this case you must arrange for procmail to trust that user to supply a correct sender address. If you don't specify either a group or a user option, the pipe command is run as the local user. The home directory is the user's home directory by default.

Note that the command that the pipe transport runs does not begin with

    IFS=" "

as shown in the procmail documentation, because Exim does not by default use a shell to run pipe commands.

The next example shows a transport and a director for a system where local deliveries are handled by the Cyrus IMAP server.

    # transport
    local_delivery_cyrus:
      driver = pipe
      command = /usr/cyrus/bin/deliver \
                -m ${substr_1:$local_part_suffix} -- $local_part
      user = cyrus
      group = mail
      return_output
      log_output
      prefix =
      suffix =

    # director
    local_user_cyrus:
      driver = localuser
      suffix = .*
      transport = local_delivery_cyrus

Note the unsetting of prefix and suffix, and the use of return_output to cause any text written by Cyrus to be returned to the sender.

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