Generic Router Options

This web page describes the generic router options that apply to all routers, we have already discussed two options already the driver (determines which router is to be used) and transport (once the address has been accepted it is ready to delivered via a transport).

One option you may see often is the more option, this option stops Exim passing the address to any more routers when set to false

Stop passing to any more routers more = false
no_more

The router options can be divided into the following types

Conditional Running of Routers

Exim offers an address to all the defined routers in turn, until one is found that can handle it, or until all have been tried. However before any router is run a number of preconditions are checked. They are check in the following order

Within the router definition, we can check prefixes and suffixes before the router is run, if no match is found then the router will not run

prefix and suffix example real_users:
   driver = accept                 ## accept the address providing the criteria is meet below
   check_local_user                ## checks the local part of the address to a user login name
   local_part_prefix = real-       ## if the local part begins with real- the router is run
   transport = local_delivery      ## use the local_delivery transport to send the message

You can also specify that the prefix or suffix is optional, which means the prefix or suffix is removed if present when the router runs

optional prefix and suffix example real_users:
   driver = accept                      ## accept the address providing the criteria is meet below
   check_local_user                     ## checks the local part of the address to a user login name
   local_part_prefix_optional = real-   ## if the local part begins with real- the router is run without                                         ## the prefix
   transport = local_delivery           ## use the local_delivery transport to send the message

You can also specify a wildcard which matches the longest possible sequence of arbitary characters at the start of the local part.

using wildcards real_users:
   driver = accept                      ## accept the address providing the criteria is meet below
   check_local_user                     ## checks the local part of the address to a local account name
   local_part_suffix = -*               ## match the longest possible sequence at the end
   transport = local_delivery           ## use the local_delivery transport to send the message

There are two ways to verify a users address, using the -bv option confirms if one of the routers will accept the address, -bt option displays what router and what transports will be used to accept and deliver to the address.

Verify an address

# exim4 -bv paul.valle@datadisk.co.uk    ## verify the address (if successful at least one router accepted)

# exim4 -bt paul.valle@datadisk.co.uk    ## displays what routers and transports are used

You can specify a particular domain in a router, if the address does not conatin the domain then the router will not accept the address

Specify a specific domain virtuals:
   driver = redirect
   domains = /etc/virtuals
   data = ${lookup{$local_part}lsearch{/etc/$domain.aliases}}
   no_more

You can also specify a particular local part

Specify a specific local part postmaster:
   driver = redirect
   local_parts = postmaster              ## local part must contain postmaster
   data = postmaster@datadisk.co.uk

Note: the local_part_prefix and local_part_suffix happens before the local_parts test

You can also check that the local part has a local account before running the router

local account check real_users:
   driver = accept                     
   check_local_user                     ## checks the local part of the address to a local account name
   transport = local_delivery           

You can check the existance of files before running a router

Check files existance

maildrop:
   driver = accept
   domains = +local_domains
   check_local_user
   transport = maildrop_pipe
   require_files = /usr/bin/maildrop:/usr/local/bin/maildrop    ## make sure thess files exists before                                                                 ## running the router

Note: you can also check paths and use the ! to negate and use lists (make sure you use the + sign for lists)

The last option is the condition option, this allows to use an expansion string to determine if the router should run or not

using conditions

notlocal:
   driver = dnslookup
   domains = +local_domains
   transport = remote_smtp
   condition = ${if < {$message_size}{500K}}    ## returns true if less than 500K

Note: restrict this router to messages less than 500K in size

Changing a router's successful outcome

This sections describes what happens when in some cases a router successfully handles an address

When a router redirects an adress and generates one or more child addresses, each child address has to go through the whole router check again, but sometimes you may what to jump to a particular router, thus saving some time as you know that some routers will pass the address on any way.

Redirect to a router

real_name:
   driver = redirect                                       ## redirect to the next router (see below)
   data = ${lookup{$local_part}lsearch{/etc/real_logins}}
   redirect_router = system_aliases                        ## redirect jumps to system_aliases router

system_aliases:
   ......

You can force an address to continue through the routers even if it has been accepted by using the unseen option

Continue checking copy_ceo:
   driver = redirect
   local_parts = ceo
   domains = plc@datadisk.co.uk
   data = secretary@datadisk.co.uk
   unseen                                ## even if conditions are meet, it is passed to the next router

You can ignore erroneous IP addresses, any domains that resolve to the IP addresses are treated in the same way as domains that cannot be looked up

Ignore IP addresses ignore_target_hosts = 0.0.0.0 : 127.0.0.0/8

You can change the delivery logging style as Exim has two different styles for delivery, so that you can make local and remote deliveries very different using the log_as_local option

See Exim Logging for more information on how Exim logs

Adding data for subsequent use

The header section can be modified by adding or removing individual header lines at the time it is transported

Header section

headers_remove = return-receipt-to : acknowledge-to

headers_add = "X-added-header: added by $primary_hostname" : $local_part@$domain

When an address is redirected, it is sometimes desirable to change the address to which subsequent bounce messages will be sent, the error_to option is used to change the envelope sender for deliveries of any addresses it handles or generates

Changing the return path lists:
   driver = redirect
   domains = lists.datadisk.co.uk
   no_more
   file = /usr/lists/$local_part
   forbid_pipe
   forbid_file
   errors_to = $local_part-request@$domain     ## override earlier setting if any

Message for unrouteable addresses

When none of the routers can handle an addresses you can use a specific message, however you can only use the cannot_route_message on the last router or any routers with the no_more or more set to false option.

unrouteable message cannot_route_message = Remote domain not found in DNS

Note: remember it has to be the last router or a router with no_more set.

Handling DNS timeouts

Sometimes you may not be connected to the internet all the time, so you want away to pass the address on, so that it can be handled by another router

DNS timeouts

notlocal_direct:
   driver = dnslookup
   domains = ! +local_domains
   transport = remote_smtp
   pass_on_timeout                        ## causes the router to pass if an timeout occurs
   no_more

notlocal_smarthost:
   driver = manualroute
   transport = remote_smtp
   route_list = ! +local_domains smart.host.example

Debugging Routers

There is a generic option debug_print whose sole purpose is to help debug Exim configuration. When debugging is turned the value of debug_print is expanded and added to the debugging output that is written to the standard output stream, you can use this to check variables, etc

debug_print

send_to_scanner:
   driver = accept
   transport = pipe_to_scanner
   condition = ${if !eq {$received_protocol}{scanned-ok}}
   debug_print = received_protocol=$received_protocol

Note: you must have debugging turned on, see the cheat sheet on how to do this