cf/README for sendmail 8.12.3

Eric Allman of the Sendmail Consortium


  1. Overview
  2. Relaying
  3. Allowing Connections
  4. Disabling STARTTLS And Setting SMTP Server Features
  5. Received: Header

In this text, cert will be used as an abreviation for X.509 certificate, DN (CN) is the distinguished (common) name of a cert, and CA is a certification authority, which signs (issues) certs.

For STARTTLS to be offered by sendmail you need to set at least this variables (the file names and paths are just examples):

define(`confCACERT_PATH', `/etc/mail/certs/')
define(`confCACERT', `/etc/mail/certs/CA.cert.pem')
define(`confSERVER_CERT', `/etc/mail/certs/my.cert.pem')
define(`confSERVER_KEY', `/etc/mail/certs/my.key.pem')

On systems which do not have the compile flag HASURANDOM set (see sendmail/README) you also must set confRAND_FILE.

See doc/op/op.{me,ps,txt} for more information about these options, especially the sections ``Certificates for STARTTLS'' and ``PRNG for STARTTLS''.

Macros related to STARTTLS are:

  • ${cert_issuer} holds the DN of the CA (the cert issuer).
  • ${cert_subject} holds the DN of the cert (called the cert subject).
  • ${cn_issuer} holds the CN of the CA (the cert issuer).
  • ${cn_subject} holds the CN of the cert (called the cert subject).
  • ${tls_version} the TLS/SSL version used for the connection, e.g., TLSv1, TLSv1/SSLv3, SSLv3, SSLv2.
  • ${cipher} the cipher used for the connection, e.g., EDH-DSS-DES-CBC3-SHA, EDH-RSA-DES-CBC-SHA, DES-CBC-MD5, DES-CBC3-SHA.
  • ${cipher_bits} the keylength (in bits) of the symmetric encryption algorithm used for the connection.
  • ${verify} holds the result of the verification of the presented cert.
    Possible values are:
    OKverification succeeded.
    NOno cert presented.
    NOTno cert requested.
    FAILcert presented but could not be verified, e.g., the cert of the signing CA is missing.
    NONESTARTTLS has not been performed.
    TEMPtemporary error occurred.
    PROTOCOLprotocol error occurred (SMTP level).
    SOFTWARESTARTTLS handshake failed.
  • ${server_name} the name of the server of the current outgoing SMTP connection.
  • ${server_addr} the address of the server of the current outgoing SMTP connection.


SMTP STARTTLS can allow relaying for senders who have successfully authenticated themselves. This is done in the ruleset RelayAuth. If the verification of the cert failed (${verify} != OK), relaying is subject to the usual rules. Otherwise the DN of the issuer is looked up in the access map using the tag CERTISSUER. If the resulting value is RELAY, relaying is allowed. If it is SUBJECT, the DN of the cert subject is looked up next in the access map using the tag CERTSUBJECT. If the value is RELAY, relaying is allowed.

To make things a bit more flexible (or complicated), the values for ${cert_issuer} and ${cert_subject} can be optionally modified by regular expressions defined in the m4 variables _CERT_REGEX_ISSUER_ and _CERT_REGEX_SUBJECT_, respectively. To avoid problems with those macros in rulesets and map lookups, they are modified as follows: each non-printable character and the characters '<', '>', '(', ')', '"', '+' are replaced by their HEX value with a leading '+'. For example:

/C=US/ST=California/ Mail (Cert)/Email=

is encoded as:

(line breaks have been inserted for readability).


To allow relaying for everyone who can present a cert signed by


simply use:

Darth+20Mail+20+28Cert+29/	RELAY

To allow relaying only for a subset of machines that have a cert signed by



Darth+20Mail+20+28Cert+29/	SUBJECT
DeathStar/		RELAY

Note: line breaks have been inserted after "CN=" for readability, each tagged entry must be one (long) line in the access map.

Of course it is also possible to write a simple ruleset that allows relaying for everyone who can present a cert that can be verified, e.g.,

R$*	$: $&{verify}

Allowing Connections

The rulesets tls_server, tls_client, and tls_rcpt are used to decide whether an SMTP connection is accepted (or should continue).

tls_server is called when sendmail acts as client after a STARTTLS command (should) have been issued. The parameter is the value of ${verify}.

tls_client is called when sendmail acts as server, after a STARTTLS command has been issued, and from check_mail. The parameter is the value of ${verify} and STARTTLS or MAIL, respectively.

Both rulesets behave the same. If no access map is in use, the connection will be accepted unless ${verify} is SOFTWARE, in which case the connection is always aborted. For tls_server/tls_client, ${client_name}/${server_name} is looked up in the access map using the tag TLS_Srv/TLS_Clt, which is done with the ruleset LookUpDomain. If no entry is found, ${client_addr} (${server_addr}) is looked up in the access map (same tag, ruleset LookUpAddr). If this doesn't result in an entry either, just the tag is looked up in the access map (included the trailing colon).
Notice: requiring that e-mail is sent to a server only encrypted, e.g., via

TLS_Srv:secure.domain	ENCR:112

doesn't necessarily mean that e-mail sent to that domain is encrypted. If the domain has multiple MX servers, e.g.,

secure.domain.	IN MX 10
secure.domain.	IN MX 50	mail.other.domain.

then mail to user@secure.domain may go unencrypted to mail.other.domain. tls_rcpt can be used to address this problem.

tls_rcpt is called before a RCPT TO: command is sent. The parameter is the current recipient. This ruleset is only defined if FEATURE(`access_db') is selected. A recipient address user@domain is looked up in the access map in four formats: TLS_Rcpt:user@domain, TLS_Rcpt:user@, TLS_Rcpt:domain, and TLS_Rcpt:; the first match is taken.

The result of the lookups is then used to call the ruleset TLS_connection, which checks the requirement specified by the RHS in the access map against the actual parameters of the current TLS connection, esp. ${verify} and ${cipher_bits}. Legal RHSs in the access map are:

VERIFY		verification must have succeeded
VERIFY:bits	verification must have succeeded and ${cipher_bits} must
		be greater than or equal bits.
ENCR:bits	${cipher_bits} must be greater than or equal bits.

The RHS can optionally be prefixed by TEMP+ or PERM+ to select a temporary or permanent error. The default is a temporary error code (403 4.7.0) unless the macro TLS_PERM_ERR is set during generation of the .cf file.

If a certain level of encryption is required, then it might also be possible that this level is provided by the security layer from a SASL algorithm, e.g., DIGEST-MD5.

Furthermore, there can be a list of extensions added. Such a list starts with '+' and the items are separated by '++'. Allowed extensions are:

CN:name		name must match ${cn_subject}
CN		${server_name} must match ${cn_subject}
CS:name		name must match ${cert_subject}
CI:name		name must match ${cert_issuer}

Example: e-mail sent to should only use an encrypted connection. E-mail received from hosts within the domain should only be accepted if they have been authenticated. The host which receives e-mail for must present a cert that uses the CN      ENCR:112      PERM+VERIFY:112

Disabling STARTTLS And Setting SMTP Server Features

By default STARTTLS is used whenever possible. However, there are some broken MTAs that don't properly implement STARTTLS. To be able to send to (or receive from) those MTAs, the ruleset try_tls (srv_features) can be used that work together with the access map. Entries for the access map must be tagged with Try_TLS (Srv_Features) and refer to the hostname or IP address of the connecting system. A default case can be specified by using just the tag. For example, the following entries in the access map:

Try_TLS:broken.server	NO
Srv_Features:my.domain	v
Srv_Features:		V

will turn off STARTTLS when sending to broken.server (or any host in that domain), and request a client certificate during the TLS handshake only for hosts in my.domain. The valid entries on the RHS for Srv_Features are listed in the "Sendmail Installation and Operations Guide".

Received: Header

The Received: header reveals whether STARTTLS has been used. It contains an extra line:

(version=${tls_version} cipher=${cipher} bits=${cipher_bits} verify=${verify})