Exim Client Authentication Recipe

Written 9 years ago by Mike Cardwell

In the past I had a fairly complex setup with Exim, where it routed email out via various smart hosts which use authenticated SMTP. I don’t have that setup any more, but the configuration I used is still in place, so I thought I’d share it. I wanted a simple setup where I could drop a list of ip:username:password combinations into a file, and Exim would do the rest. Here’s how to do it:

First of all, create a file containing the following details about each of your smart hosts.  : require_ssl="true" type="cram"        user="myuser"                pass="mypass" require_ssl="true" type="login,plain" user="" pass="mypass" require_ssl="true" type="login,plain" user="" pass="mypass"

I think the contents of that file are fairly self explanatory. You must always provide all 4 options, require_ssl, type, user and pass. Make sure there is no whitespace adjecent to the equals symbols, as per my example.

At the top of your Exim configuration, add a macro which defines the path to the file you’ve just created called AUTH_CLIENT_DATA

AUTH_CLIENT_DATA = /etc/exim4/client_smtp_auth.txt

You’ll obviously want to change that to point to the location of your own file. Copy and paste the following list of macros, unchanged, below the AUTH_CLIENT_DATA macro. You don’t need to know what these do, they just make the transport and authenticator changes very simple.

AUTH_CLIENT_REQUIRED       = ${filter{${readfile{AUTH_CLIENT_DATA}{:}}}{match{$item}{\N^\s*\d{1,3}(?:\.\d{1,3}){3}(?:/[0-9]{1,2})?\s*$\N}}}
AUTH_CLIENT_REQUIRE_SSL    = ${filter{${sg{${filter{<\n${readfile{AUTH_CLIENT_DATA}}}{match{${extract{require_ssl}{$item}}}{\N^(?i)\s*(true|yes|1)\s*$\N}}}}{\N\n\N}{:}}}{match{$item}{\N^\s*\d{1,3}(?:\.\d{1,3}){3}\s*$\N}}}
AUTH_CLIENT_SEND_DATA      = ${lookup{$host_address}iplsearch{AUTH_CLIENT_DATA}}
AUTH_CLIENT_ENABLED_PLAIN  = ${if match{${extract{type}{AUTH_CLIENT_SEND_DATA}}}{\N^(?i)(.+,)*plain(,.+)*$\N}{true}{false}}
AUTH_CLIENT_ENABLED_LOGIN  = ${if match{${extract{type}{AUTH_CLIENT_SEND_DATA}}}{\N^(?i)(.+,)*login(,.+)*$\N}{true}{false}}
AUTH_CLIENT_ENABLED_CRAM   = ${if match{${extract{type}{AUTH_CLIENT_SEND_DATA}}}{\N^(?i)(.+,)*cram(,.+)*$\N}{true}{false}}

To inform your remote_smtp transport about when it should use authentication and when it should require ssl, add hosts_require_tls and hosts_require_auth options as follows.

    driver             = smtp
    hosts_require_tls  = AUTH_CLIENT_REQUIRE_SSL
    hosts_require_auth = AUTH_CLIENT_REQUIRED

In the authenticators section of your Exim config, create three authenticators for plain, login and cram.

    driver           = cram_md5
    public_name      = CRAM-MD5
    client_condition = AUTH_CLIENT_ENABLED_CRAM
    client_name      = AUTH_CLIENT_SEND_CRAM_USER
    client_secret    = AUTH_CLIENT_SEND_CRAM_PASS

    driver           = plaintext
    client_condition = AUTH_CLIENT_ENABLED_LOGIN
    client_send      = AUTH_CLIENT_SEND_LOGIN

    driver           = plaintext
    client_condition = AUTH_CLIENT_ENABLED_PLAIN
    client_send      = AUTH_CLIENT_SEND_PLAIN

Finally, create a manualroute router to define which messages should be routed out via a smarthost. Here’s an example which would route out all non local messages via Because there’s an entry for in the file you created at the beginning, remote_smtp would know to use authentication and ssl.

    driver     = manualroute
    domains    = !+local_domains
    transport  = remote_smtp
    route_data =

Job done.

Looking to hire somebody like me? I'm open to offers of full time employment and small contract jobs. Check out my hiring page. You can follow this Blog using RSS or . To read more, visit my blog index.

Feeling generous?BitcoinMoneroZcashPaypal