Previous   Next   Contents       (Exim 4.20 Specification)

10. Domain, Host, Address, and Local Part lists

A number of Exim configuration options contain lists of domains, hosts, email addresses, or local parts. For example, the hold_domains option contains a list of domains whose delivery is currently suspended. These lists are also used as data in ACL statements (see chapter 37).

Each item in one of these lists is a pattern to be matched against a domain, host, email address, or local part, respectively. In the sections below, the different types of pattern for each case are described, but first we cover some general facilities that apply to all four kinds of list.

10.1. Expansion of lists

Each list is expanded as a single string before it is used. If the expansion is forced to fail, Exim behaves as if the item it is testing (domain, host, address, or local part) is not in the list. Other expansion failures cause temporary errors.

If an item in a list is a regular expression, backslashes, dollars and possibly other special characters in the expression must be protected against misinterpretation by the string expander. The easiest way to do this is to use the \N expansion feature to indicate that the contents of the regular expression should not be expanded. For example, in an ACL you might have:

  deny senders = \N^\d{8}\w@.*\.baddomain\.example$\N :

The first item is a regular expression that is protected from expansion by \N, whereas the second uses the expansion to obtain a list of unwanted senders based on the receiving domain.

After expansion, the list is split up into separate items for matching. Normally, colon is used as the separator character, but this can be varied if necessary, as described in section 6.15.

10.2. Negated items in lists

Items in a list may be positive or negative. Negative items are indicated by a leading exclamation mark, which may be followed by optional white space. A list defines a set of items (domains, etc). When Exim processes one of these lists, it is trying to find out whether a domain, host, address, or local part (respectively) is in the set that is defined by the list. It works like this:

The list is scanned from left to right. If a positive item is matched, the subject that is being checked is in the set; if a negative item is matched, the subject is not in the set. If the end of the list is reached without the subject having matched any of the patterns, it is in the set if the last item was a negative one, but not if it was a positive one. For example, the list in

  domainlist relay_domains = !a.b.c : *.b.c

matches any domain ending in .b.c except for a.b.c. Domains that match neither a.b.c nor *.b.c do not match, because the last item in the list is positive. However, if the setting were

  domainlist relay_domains = !a.b.c

then all domains other than a.b.c would match because the last item in the list is negative. In other words, a list that ends with a negative item behaves as if it had an extra item :* on the end.

Another way of thinking about positive and negative items in lists is to read the connector as ``or'' after a positive item and as ``and'' after a negative item.

10.3. File names in lists

If an item in a domain, host, address, or local part list is an absolute file name (beginning with a slash character), each line of the file is read and processed as if it were an independent item in the list, except that further file names are not allowed, and no expansion of the data from the file takes place. Empty lines in the file are ignored, and the file may also contain comment lines:

Putting a file name in a list has the same effect as inserting each line of the file as an item in the list (blank lines and comments excepted). However, there is one important difference: the file is read each time the list is processed, so if its contents vary over time, Exim's behaviour changes.

If a file name is preceded by an exclamation mark, the sense of any match within the file is inverted. For example, if

  hold_domains = !/etc/nohold-domains

and the file contains the lines


then a.b.c is in the set of domains defined by hold_domains, whereas any domain matching *.b.c is not.

10.4. An lsearch file is not an out-of-line list

As will be described in the sections that follow, lookups can be used in lists to provide indexed methods of checking list membership. There has been some confusion about the way lsearch lookups work in lists. Because an lsearch file contains plain text and is scanned sequentially, it is sometimes thought that it is allowed to contain wild cards and other kinds of non-constant pattern. This is not the case. The keys in an lsearch file are always fixed strings, just as for any other single-key lookup type.

If you want to use a file to contain wild-card patterns that form part of a list, just give the file name on its own, without a search type, as described in the previous section.

10.5. Named lists

A list of domains, hosts, email addresses, or local parts can be given a name which is then used to refer to the list elsewhere in the configuration. This is particularly convenient if the same list is required in several different places. It also allows lists to be given meaningful names, which can improve the readability of the configuration. For example, it is conventional to define a domain list called local_domains for all the domains that are handled locally on a host, using a configuration line such as

  domainlist local_domains = localhost:my.dom.example

Named lists are referenced by giving their name preceded by a plus sign, so, for example, a router that is intended to handle local domains would be configured with the line

  domains = +local_domains

The first router in a configuration is often one that handles all domains except the local ones, using a configuration with a negated item like this:

    driver = dnslookup
    domains = ! +local_domains
    transport = remote_smtp

The four kinds of named list are created by configuration lines starting with the words domainlist, hostlist, addresslist, or localpartlist, respectively. Then there follows the name that you are defining, followed by an equals sign and the list itself. For example:

  hostlist    relay_hosts = : my.friend.example
  addresslist bad_senders = cdb;/etc/badsenders

A named list may refer to other named lists:

  domainlist  dom1 = first.example : second.example
  domainlist  dom2 = +dom1 : third.example
  domainlist  dom3 = fourth.example : +dom2 : fifth.example

Warning: If the last item in a referenced list is a negative one, the effect may not be what you intended, because the negation does not propagate out to the higher level. For example, consider:

  domainlist  dom1 = !a.b
  domainlist  dom2 = +dom1 : *.b

The second list specifies ``either in the dom1 list or *.b''. The first list specifies just ``not a.b'', so the domain x.y matches it. That means it matches the second list as well. The effect is not the same as

  domainlist  dom2 = !a.b : *.b

where x.y does not match. It's best to avoid negation altogether in referenced lists if you can.

Named lists may have a performance advantage. When Exim is routing an address or checking an incoming message, it caches the result of tests on named lists. So, if you have a setting such as

  domains = +local_domains

on several of your routers or in several ACL statements, the actual test is done only for the first one. However, the caching works only if there are no expansions within the list itself or any sublists that it references. In other words, caching happens only for lists that are known to be the same each time they are referenced.

By default, there may be up to 16 named lists of each type. This limit can be extended by changing a compile-time variable. The use of domain and host lists is recommended for concepts such as local domains, relay domains, and relay hosts. The default configuration is set up like this.

10.6. Named lists compared with macros

At first sight, named lists might seem to be no different from macros in the configuration file. However, macros are just textual substitutions. If you write

  ALIST = host1 : host2
  auth_advertise_hosts = !ALIST

it probably won't do what you want, because that is exactly the same as

  auth_advertise_hosts = !host1 : host2

Notice that the second host name is not negated. However, if you use a host list, and write

  hostlist alist = host1 : host2
  auth_advertise_hosts = ! +alist

the negation applies to the whole list, and so that is equivalent to

  auth_advertise_hosts = !host1 : !host2

10.7. Domain lists

Domain lists contain patterns that are to be matched against a mail domain. The following types of item may appear in domain lists:

Here is an example that uses several different kinds of pattern:

  domainlist funny_domains = \
    @ : \ : \
    *.foundation.fict.example : \
    \N^[1-2]\d{3}\.fict\.example$\N : \
    partial-dbm;/opt/data/penguin/book : \
    nis;domains.byname : \

There are obvious processing trade-offs among the various matching modes. Using an asterisk is faster than a regular expression, and listing a few names explicitly probably is too. The use of a file or database lookup is expensive, but may be the only option if hundreds of names are required. Because the patterns are tested in order, it makes sense to put the most commonly matched patterns earlier.

10.8. Host lists

Host lists are used to control what remote hosts are allowed to do. For example, some hosts may be allowed to use the local host as a relay, and some may be permitted to use the SMTP ETRN command. Hosts can be identified in two different ways, by name or by IP address. In a host list, some types of pattern are matched to a host name, and some are matched to an IP address. You need to be particularly careful with this when single-key lookups are involved, to ensure that the right value is being used as the key.

10.9. Special host list patterns

If a host list item is the empty string, it matches only when no remote host is involved. This is the case when a message is being received from a local process using SMTP on the standard input, that is, when a TCP/IP connection is not used.

The special pattern ``*'' in a host list matches any host or no host. Neither the IP address nor the name is actually inspected.

10.10. Host list patterns that match by IP address

If an IPv4 host calls an IPv6 host and the call is accepted on an IPv6 socket, the incoming address actually appears in the IPv6 host as ``::ffff:<v4address>''. When such an address is tested against a host list, it is converted into a traditional IPv4 address first. (Not all operating systems accept IPv4 calls on IPv6 sockets, as there have been some security concerns.)

The following types of pattern in a host list check the remote host by inspecting its IP address:

10.11. Host list patterns that match by host name

The remaining types of pattern that can appear in host lists require Exim to know the name of the remote host. They are all wildcarded names of different kinds. (If a complete name is given without any wildcarding, it is used to find an IP address to match against, as described in the previous section.)

If the remote host name is not already known when Exim encounters one of these patterns, a system function (gethostbyaddr() or getipnodebyaddr() if available) is used to find it from the IP address. This typically causes a reverse DNS lookup to occur. Although many sites on the Internet are conscientious about maintaining reverse DNS data for their hosts, there are also many that do not do this. Consequently, a name cannot always be found, and this may lead to unwanted effects.

If the DNS lookup fails, that is, if there is no reverse DNS entry for the IP address, Exim behaves as if the host does not match the list. This may not always be what you want to happen. To change Exim's behaviour, the special item ``+include_unknown'' may appear in the list (at top level - it is not recognized in an indirected file). If any subsequent items require a host name, but no name can be found, Exim behaves as if the host does match the list. For example,

  host_reject_connection = +include_unknown:*.enemy.ex

rejects connections from any host whose name matches *.enemy.ex, and also any hosts whose name it cannot find.

Warning: Take care when configuring host lists with wildcarded name patterns. Consider what will happen if a name cannot be found.

As a result of aliasing, hosts may have more than one name. When processing any of the following types of pattern, all the host's names are checked:

10.12. Mixing wildcarded host names and addresses in host lists

If you have name lookups or wildcarded host names and IP addresses in the same host list, you should normally put the IP addresses first. For example, in an ACL you could have:

  accept hosts = : *.friend.example

The reason for this lies in the left-to-right way that Exim processes lists. It can test IP addresses without doing any DNS lookups, but when it reaches an item that requires a host name, it fails if it cannot find a host name to compare with the pattern. If the above list is given in the opposite order, the accept statement fails for a host whose name cannot be found, even if its IP address is

If you really do want to do the name check first, and still recognize the IP address, you can rewrite the ACL like this:

  accept hosts = *.friend.example
  accept hosts =

If the first accept fails, Exim goes on to try the second one. See chapter 37 for details of ACLs.

10.13. Address lists

Address lists contain patterns that are matched against mail addresses. There is one special case to be considered: the sender address of a bounce message is always empty. You can test for this by providing an empty item in an address list. For example, you can set up a router to process bounce messages by using this option setting:

  senders = :

The presence of the colon creates an empty item. If you do not provide any data, the list is empty and matches nothing. The empty sender can also be detected by a regular expression that matches an empty string.

The following kinds of pattern are supported in address lists:

Warning: there is an important difference between the address list items in these two examples:

  senders = +my_list
  senders = *@+my_list

In the first one, my_list is a named address list, whereas in the second example it is a named domain list.

10.14. Case of letters in address lists

Domains in email addresses are always handled caselessly, but for local parts case may be significant on some systems (see caseful_local_part for how Exim deals with this when routing addresses). However, RFC 2505 (Anti-Spam Recommendations for SMTP MTAs) suggests that matching of addresses to blocking lists should be done in a case-independent manner. Since most address lists in Exim are used for this kind of control, Exim attempts to do this by default.

The domain portion of an address is always lowercased before matching it to an address list. The local part is lowercased by default, and any string comparisons that take place are done caselessly. This means that the data in the address list itself, in files included as plain file names, and in any file that is looked up using the ``@@'' mechanism, can be in any case. However, the keys in files that are looked up by a search type other than lsearch (which works caselessly) must be in lower case, because these lookups are not case-independent.

To allow for the possibility of caseful address list matching, if an item in an address list is the string ``+caseful'', the original case of the local part is restored for any comparisons that follow, and string comparisons are no longer case-independent. This does not affect the domain, which remains in lower case. However, although independent matches on the domain alone are still performed caselessly, regular expressions that match against an entire address become case-sensitive after ``+caseful'' has been seen.

10.15. Local part lists

Case-sensitivity in local part lists is handled in the same way as for address lists, as just described. The ``+caseful'' item can be used if required. In a setting of the local_parts option in a router with caseful_local_part set false, the subject is lowercased and the matching is initially case-insensitive. In this case, ``+caseful'' will restore case-sensitive matching in the local part list, but not elsewhere in the router. If caseful_local_part is set true in a router, matching in the local_parts option is case-sensitive from the start.

If a local part list is indirected to a file (see section 10.3), comments are handled in the same way as address lists - they are recognized only if the # is preceded by white space or the start of the line. Otherwise, local part lists are matched in the same way as domain lists, except that the special items that refer to the local host (@, @[], @mx_any, @mx_primary, and @mx_secondary) are not recognized. Refer to section 10.7 for details of the other available item types.

Previous  Next  Contents       (Exim 4.20 Specification)