Exim Internet Mailer


Chapter 41 - The external authenticator

The external authenticator provides support for authentication based on non-SMTP information. The specification is in RFC 4422 Appendix A (https://tools.ietf.org/html/rfc4422). It is only a transport and negotiation mechanism; the process of authentication is entirely controlled by the server configuration.

The client presents an identity in-clear. It is probably wise for a server to only advertise, and for clients to only attempt, this authentication method on a secure (eg. under TLS) connection.

One possible use, compatible with the K-9 Mail Android client (https://k9mail.github.io/), is for using X509 client certificates.

It thus overlaps in function with the TLS authenticator (see 42) but is a full SMTP SASL authenticator rather than being implicit for TLS-connection carried client certificates only.

The examples and discussion in this chapter assume that client-certificate authentication is being done.

The client must present a certificate, for which it must have been requested via the tls_verify_hosts or tls_try_verify_hosts main options (see 43). For authentication to be effective the certificate should be verifiable against a trust-anchor certificate known to the server.

1. External options

The external authenticator has two server options:

server_param2 Use: external Type: string Default: unset

server_param3 Use: external Type: string Default: unset

These options are expanded before the server_condition option and the result are placed in $auth2 and $auth3 resectively. If the expansion is forced to fail, authentication fails. Any other expansion failure causes a temporary error code to be returned.

They can be used to clarify the coding of a complex server_condition.

2. Using external in a server

When running as a server, external performs the authentication test by expanding a string. The data sent by the client with the AUTH command, or in response to subsequent prompts, is base64 encoded, and so may contain any byte values when decoded. The decoded value is treated as an identity for authentication and placed in the expansion variable $auth1.

For compatibility with previous releases of Exim, the value is also placed in the expansion variable $1. However, the use of this variable for this purpose is now deprecated, as it can lead to confusion in string expansions that also use them for other things.

Once an identity has been received, server_condition is expanded. If the expansion is forced to fail, authentication fails. Any other expansion failure causes a temporary error code to be returned. If the result of a successful expansion is an empty string, “0”, “no”, or “false”, authentication fails. If the result of the expansion is “1”, “yes”, or “true”, authentication succeeds and the generic server_set_id option is expanded and saved in $authenticated_id. For any other result, a temporary error code is returned, with the expanded string as the error text.


  driver =            external
  public_name =       EXTERNAL

  server_advertise_condition = $tls_in_certificate_verified
  server_param2 =     ${certextract {subj_altname,mail,>:} \
  server_condition =  ${if forany {$auth2} \
                            {eq {$item}{$auth1}}}
  server_set_id =     $auth1

This accepts a client certificate that is verifiable against any of your configured trust-anchors (which usually means the full set of public CAs) and which has a mail-SAN matching the claimed identity sent by the client.

Note: up to TLS1.2, the client cert is on the wire in-clear, including the SAN. The account name is therefore guessable by an opponent. TLS 1.3 protects both server and client certificates, and is not vulnerable in this way.

3. Using external in a client

The external authenticator has one client option:

client_send Use: external Type: string Default: unset

This option is expanded and sent with the AUTH command as the identity being asserted.


  driver =      external
  public_name = EXTERNAL

  client_condition = ${if !eq{$tls_out_cipher}{}}
  client_send = myaccount@smarthost.example.net

<-previousTable of Contentsnext->