21. The queryprogram router

The queryprogram router routes an address by running an external command and acting on its output. This is an expensive way to route, and is intended mainly for use in lightly-loaded systems, or for performing experiments. However, if it is possible to use the precondition options (domains, local_parts, etc) to skip this router for most addresses, it could sensibly be used in special cases, even on a busy host. There are the following private options:

commandUse: queryprogramType: stringDefault: unset

This option must be set. It specifies the command that is to be run. The command is split up into a command name and arguments, and then each is expanded separately (exactly as for a pipe transport, described in chapter 29).

command_groupUse: queryprogramType: stringDefault: unset

This option specifies a gid to be set when running the command while routing an address for deliver. It must be set if command_user specifies a numerical uid. If it begins with a digit, it is interpreted as the numerical value of the gid. Otherwise it is looked up using getgrnam().

command_userUse: queryprogramType: stringDefault: unset

This option must be set. It specifies the uid which is set when running the command while routing an address for delivery. If the value begins with a digit, it is interpreted as the numerical value of the uid. Otherwise, it is looked up using getpwnam() to obtain a value for the uid and, if command_group is not set, a value for the gid also.

Warning: Changing uid and gid is possible only when Exim is running as root, which it does during a normal delivery in a conventional configuration. However, when an address is being verified during message reception, Exim is usually running as the Exim user, not as root. If the queryprogram router is called from a non-root process, Exim cannot change uid or gid before running the command. In this circumstance the command runs under the current uid and gid.

current_directoryUse: queryprogramType: stringDefault: /

This option specifies an absolute path which is made the current directory before running the command.

timeoutUse: queryprogramType: timeDefault: 1h

If the command does not complete within the timeout period, its process group is killed and the message is frozen. A value of zero time specifies no timeout.

The standard output of the command is connected to a pipe, which is read when the command terminates. It should consist of a single line of output, containing up to five fields, separated by white space. The maximum length of the line is 1023 characters. Longer lines are silently truncated. The first field is one of the following words (case-insensitive):

When the first word is accept, the remainder of the line consists of a number of keyed data values, as follows (split into two lines here, to fit on the page):

ACCEPT TRANSPORT=<transport> HOSTS=<list of hosts>
LOOKUP=byname|bydns DATA=<text>

The data items can be given in any order, and all are optional. If no transport is included, the transport specified by the generic transport option is used. The list of hosts and the lookup type are needed only if the transport is an smtp transport that does not itself supply a list of hosts.

The format of the list of hosts is the same as for the manualroute router. As well as host names and IP addresses with optional port numbers, as described in section 20.5, it may contain names followed by /MX to specify sublists of hosts that are obtained by looking up MX records (see section 20.6).

If the lookup type is not specified, Exim behaves as follows when trying to find an IP address for each host: First, a DNS lookup is done. If this yields anything other than HOST_NOT_FOUND, that result is used. Otherwise, Exim goes on to try a call to getipnodebyname() or gethostbyname(), and the result of the lookup is the result of that call.

If the DATA field is set, its value is placed in the $address_data variable. For example, this return line

accept hosts=x1.y.example:x2.y.example data="rule1"

routes the address to the default transport, passing a list of two hosts. When the transport runs, the string “rule1” is in $address_data.