The Routers

Routers are the components that make decisions about message deliveries, the actual delivery is performed by the transports. There are no constraints between routers and transports; any router can assign an address to any transport.

The available routers are

accept A router that accepts any address that is passed to it
dnslookup A router that looks up domains in DNS and does MX processing
ipliteral A router that handles "IP literal" address such as "paul.valle@192.168.0.1". These are not common and i do not discuss them here
manualroute A router that routes domains using locally supplied information such as a list of domains and corresponding hosts.
queryprogram A router that runs an external program in order to route an address
redirect A router that handles several different kinds of redirection, including alias files, users .forward file, and Exim or Sieve filters. It can also explicity force failure of an address

Accept Router

This is the simplest router and accepts any address providing of course the router is run, which is deteremined by the preconditions set. You could create a catchall router (last router in the configuration file) which picks up address other routers are unable to handle. The transport option must be set unless the verify_only option is also set, in which case the address will only be checked.

accept example local_users:
   driver = accept
   check_local_user                 ## the precondition check, the router will only run if this is meet
   transport = local_delivery

DNS Router

The dnslookup router uses DNS to find the hosts that handle mail for the domain of the address. Again a transport must be set for this router unless the verify_only option is set.

simple dnslookup example notlocal:
   driver = dnslookup
   domains = ! +local_domains
   transport = remote_smtp

There are other private options but are unlikely need in most installations.

Manualroute Router

Sometimes, you exactly how you want the route a particular non-local domain, for an example, a gateway that is handling all incoming mail to a local network. The manualroute router exists to handle this kind of routing. It is configured with a list of domains that it is to handle, together with information as to what to do with them. The rules can be inline or via a file or database.

Inline rules are given via the route_list option, each rule has 3 parts, you can also have multiple rules in the route_list option

inline example

route_list = dbm;/etc/domains $value:backup.example

Note: matches domains by a DBM lookup; the data from the lookup is used in the list of hosts (/etc/domains), with an additional backup hostname.

for example bkup1.example -> bkup1.backup.example

You can send all non-local addresses to a single smart hosts for onward delivery

outline example

smarthost:
   driver = manualroute
   transport = remote_smtp
   route_list = !+local_domains smarthost.example.com

Note: causes all messages containg remote addresses to be sent to the smarthost

You can control host lookups

control host lookup example

route_list = !+local_domains smarthost.example.com byname   ## calls the system function for looking up                                                           ## host names

route_list = !+local_domains smarthost.example.com bydns    ## exim does its own DNS lookup

If a host is found not to exist, delivery is deferred and the message is frozen, but youy can take a different action by setting the host_find_failed option

Sometimes it is more convenient to keep manual routing information in a file or database rather than include it inline in the configuration file.

looked-up routing rules example

hubbed_hosts:
   driver = manualroute
   domains = "${if exist{CONFDIR/hubbed_hosts}{partial-lsearch;CONFDIR/hubbed_hosts fail}"
   same_domain_copy_routing = yes
   route_data = ${lookup{$domain}partial-lsearch{CONFDIR/hubbed_hosts}}
   transport = remote_smtp

## The hubbed_hosts would be something like
datadisk.co.uk:          mailhost      byname    ## datadisk.co.uk would be routed to mailhost
datadiskcorp.co.uk:      mailhost      byname    ## datadiskcorp.co.uk would also be routed to mailhost

I have only discussed some of the common private options for the manualroute (ones related to my companies site), you might what to go to the official web site to see all options

Queryprogram Router

The queryprogram router routes an address by running an external command and acting on its output. The commands job is to make decisions about routing of the address. Becareful when using this option can it can be a performance hit, because a new process is started to run the command which could be a Perl or PHP script.

queryprogram example

pgm_router:
   driver = queryprogram
   transport = remote_smtp
   timeout = 0                                        ## defer immediately if the script pauses, hangs
   command = /usr/exim/pgmrouter.pl $local_part $domain
   command_user = mail
   command_group = mail

The queryprogram will run for 60mins (by default) before the process is killed and delivery is deferred, you can alter this by using the timeout option.

Redirect Router

The redirect router handles several kinds of address redirection and is the most complex of the routers. It normally uses the local part or the full address to find a list of new addresses or processing instructions. Its most common uses are for resolving local part aliases from /etc/aliases and handling .forward files.

A incoming address can be redirected in the following ways

The generic transport option must not be set for redirect routers.

When obtaining redirection data the redirect router operates by interpreting a text string that is either obtained by expanding the contents of the data option, or by reading the entire contents of a file name whose name is given in the file option.

obtaing redirection data

system_aliases:
   driver = redirect
   data = ${lookup{$local_part}lsearch{/etc/alises}}

Note: the data information will be passed on to the next router

you can also lookup the full address

including the domain in the alias lookup system_aliases:
   driver = redirect
   data = ${lookup{$local_part@$domain}lsearch{/etc/aliases.full}}

Normally the child addresses are in the message, you can keep this redirection information private by setting the hide_child_in_errmsg option to be true.

Exim removes all duplicates from the list of addresses to which it is delivering. Exim deals with routing loops because it skips the second time time, the redirect router is skipped.

You can tell users about broken .forward files, using the option skip_syntax_errors it is possible to deliver error messages into such users mailbox.

broken .forward file userforward:
   driver = redirect
   check_local_user
   file = $home/.forward
   skip_syntax_errors
   syntax_errors_to = real-$local_part@$domain
   syntax_errors_text = "\
      put some message if you so wish\n\n
      or use the default one\n\"