Postfix TLSRPT notification Howto

# Postfix TLSRPT Howto

## Table of Contents

- Introduction
- Building Postfix with TLSRPT support
- Turning on TLSRPT
- Connection reuse versus session resumption
- TLSRPT Status logging
- Delivering TLSRPT summaries via email
- MTA-STS Support via smtp_tls_policy_maps
- Limitations
- Credits

## Introduction

The TLSRPT protocol is defined in RFC 8460. With this, an email receiving domain can publish a policy in DNS, and request daily summary reports for successful and failed SMTP over TLS connections to that domain's MX hosts. Support for TLSRPT was added in Postfix 3.10.

A policy for domain `example.com` could look like this:

>     _smtp._tls.example.com. IN TXT "v=TLSRPTv1; rua=mailto:smtp-tls-report@example.com"

Instead of `mailto:`, a policy may specify an `https:` destination.

The diagram below shows how successful or failed Postfix TLS handshake events are collected and processed into daily summary reports.

> Postfix SMTP and TLS client engines | `→` | TLSRPT client library (linked into Postfix) | `→` | TLSRPT collector, fetcher, and summary generator | `→` | Email or HTTP delivery

- The Postfix SMTP and TLS client engines will generate a "success" or "failure" event for each TLS handshake,

- They will pass those events to an in-process TLSRPT client library that sends data over a local socket to

- A local TLSRPT collector that runs on each Postfix machine. A TLSRPT fetcher gathers information from individual collectors, and a central TLSRPT report generator produces daily summary reports.

The TLSRPT client library, and the infrastructure to collect, fetch, and report TLSRPT information, are implemented and maintained by sys4 at https://github.com/sys4/libtlsrpt and https://github.com/sys4/tlsrpt-reporter, respectively.

The Postfix implementation supports TLSRPT for domains with DANE (Postfix built-in) and MTA-STS (through an smtp_tls_policy_maps plug-in).

The Postfix smtp(8) client process implements the SMTP client engine. With "smtp_tls_connection_reuse = no", the smtp(8) client process also implements the TLS client engine. With "smtp_tls_connection_reuse = yes", the smtp(8) client process delegates TLS processing to a Postfix tlsproxy(8) process. Either way, Postfix will generate the exact same TLSRPT events.

## Building Postfix with TLSRPT support

These instructions assume that you build Postfix from source code as described in the INSTALL document. Some modification may be required if you build Postfix from a vendor-specific source package.

The Postfix TLSRPT client builds on a TLSRPT library which may be available as a built package (rpm, deb, etc.), or which you can build from source code from:

> https://github.com/sys4/libtlsrpt

The library is typically installed as a header file in /usr/local/include/tlsrpt.h and an object library in /usr/local/lib/libtlsrpt.a or /usr/local/lib/libtlsrpt.so. The actual pathnames will depend on OS platform conventions.

In order to build Postfix with TLSRPT support, you will need to add compiler options `-DUSE_TLSRPT` (to build with TLSRPT support) and `-I` (with the directory containing the tlsrpt.h header file), and you will need to add linker options to link with the TLSRPT client library, for example:

>     make -f Makefile.init makefiles \
>       "CCARGS=-DUSE_TLSRPT -I/usr/local/include" \
>       "AUXLIBS=-L/usr/local/lib -Wl,-rpath,/usr/local/lib -ltlsrpt"

(On Solaris systems you may need to use "`-Wl,-R`" instead of "`-Wl,-rpath`".)

Then, just run 'make'.

> Note: if your build command line already has CCARGS or AUXLIBS settings, then simply append the above settings to the existing CCARGS or AUXLIBS values:

>     make -f Makefile.init makefiles \
>       "CCARGS=... -DUSE_TLSRPT -I/usr/local/include" \
>       "AUXLIBS=... -L/usr/local/lib -Wl,-rpath,/usr/local/lib -ltlsrpt"

## Turning on TLSRPT

After installing Postfix TLSRPT support, you can enable TLSRPT support in main.cf like this:

>     smtp_tlsrpt_enable = yes
>     smtp_tlsrpt_socket_name = path/to/socket

The smtp_tlsrpt_socket_name parameter specifies either an absolute pathname, or a pathname that is relative to $queue_directory.

Notes:

- The recommended socket location is still to be determined. A good socket location would be under the Postfix queue directory, for example: "smtp_tlsrpt_socket_name = run/tlsrpt/tlsrpt.sock". The advantage of using a relative name is that it will work equally well whether or not Postfix chroot is turned on.

- Regardless of whether Postfix chroot is enabled, the TLSRPT receiver (`tlsrpt_collectd`) will need to be configured with the socket's absolute pathname.

- Do not specify a TLSRPT socket location under a Postfix socket directory such as `private` or `public`. Only Postfix programs should create sockets there.

For details on how to run the TLSRPT collection and reporting infrastructure, see the documentation at https://github.com/sys4/tlsrpt-reporter.

## Connection reuse versus session resumption

The Postfix SMTP client implements two kinds of reuse:

- SMTP Connection reuse: a Postfix SMTP client creates a new SMTP connection, sends one email message, and saves the connection instead of closing it. Later, some SMTP client reuses that connection, sends an email message, and saves or closes the connection depending on whether it has reached some reuse limit. Each connection can be used by only one Postfix SMTP client at a time.

- TLS Session resumption: a Postfix SMTP client saves the result from a "new" TLS handshake. Later, one or more SMTP clients create a new SMTP connection and resume the saved TLS session on their new connection.

Of course there is a third case:

- Combined reuse and resumption: a Postfix SMTP client creates a new SMTP connection, sends one email message, saves the result from a "new" TLS handshake, and also saves the connection instead of closing it. Later, one SMTP client reuses (and saves) that connection, one client at a time, and one or more clients create a new SMTP connection and resume the saved TLS session on their new connection.

In all cases, there is no TLS handshake when a saved SMTP connection is reused, and there is no "new" TLS handshake when a saved TLS session is resumed.

As described next, Postfix will by default log and generate only a TLSRPT event for a "new" TLS handshake.

## TLSRPT Status logging

With TLSRPT support turned on, the Postfix TLSRPT client will not only report an event to an invisible daily success/fail summary queue, but it will also log a visible record to the mail logfile.

Below are a few examples of logging from a Postfix SMTP client or tlsproxy daemon:

>     TLSRPT: status=success, domain=example.com, receiving_mx=mail.example.com[ipaddr]

>     TLSRPT: status=failure, domain=example.org, receiving_mx=mail.example.org[ipaddr],
>         failure_type=starttls_not_supported

>     TLSRPT: status=failure, domain=example.net, receiving_mx=mail.example.net[ipaddr],
>         failure_type=validation_failure, failure_reason=self-signed_certificate

Notes:

- Postfix logs and reports the TLSRPT status only for TLS handshakes on a new SMTP connection. There is no TLS handshake, and thus no TLSRPT status logging, when an SMTP connection is reused. Such connections have Postfix SMTP client logging like this:

      Verified TLS connection reused to mail.example.com[ipaddr]:25:
          TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)

      Untrusted TLS connection reused to mail.example.com[ipaddr]:25:
          TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)

- With TLSRPT enabled, the Postfix SMTP client reports the TLSRPT status for all TLS handshakes (the default as of Postfix 3.11). Specify "smtp_tlsrpt_skip_reused_handshakes = yes" (the default with Postfix 3.10) to skip reporting TLS handshakes that reuse a previously-negotiated TLS session as there would be no new information to report.

- Postfix logging for certificate verification failures may differ between new or reused TLS sessions.

  - New TLS session:

        TLSRPT: status=failure, domain=example.org, receiving_mx=mail.example.org[ipaddr],
            failure_type=validation_failure, failure_reason=self-signed_certificate

  - Reused TLS session:

        mail.example.org[ipaddr]:25: re-using session with untrusted peer
            credential, look for details earlier in the log
        TLSRPT: status=failure, domain=example.org, receiving_mx=mail.example.org[ipaddr],
            failure_type=certificate_not_trusted

  The logging may differ because a reused TLS session does not have the details for why TLS authentication failed.

## Delivering TLSRPT summaries via email

RFC 8460 Section 3 specifies that an MTA must not enforce TLS security when sending failure reports via email.

Options:

- In an email report, specify the "TLS-Required: no" message header, defined in RFC 8689, to reduce the Postfix SMTP client TLS security level to "may" (that is, do not verify remote SMTP server certificates, and fall back to plaintext if TLS is unavailable).
  This feature is available in Postfix 3.10 and later. If your outbound MTAs run an older version, you can use one of the options described below.

- Do nothing. When TLS security enforcement is required but fails, a TLSRPT summary message will be delayed until the problem is addressed, or until the message expires in the mail queue. Keep in mind that TLSRPT is not a real-time monitoring service; it takes on average 12 hours before a failure is reported through TLSRPT.

- On outbound MTAs that don't support the "TLS-Required: no" header feature (such as Postfix 3.9 and earlier), disable TLS security enforcement for the sender of TLSRPT summaries. Implement the configuration below on outbound MTA instances (replace noreply-smtp-tls-reporting@example.com with your actual report generator's sender address):

      /etc/postfix/main.cf:
          # Limitation: this setting is overruled with transport_maps.
          sender_dependent_default_transport_maps = inline:{
              { noreply-smtp-tls-reporting@example.com = allow-plaintext } }

      /etc/postfix/master.cf:
          # service name    type    private unpriv  chroot  wakeup  maxproc command
          allow-plaintext   unix    -       -       -       -       -       smtp
              -o { smtp_tls_security_level = may }
              -o { smtp_tls_policy_maps = static:may }

## MTA-STS Support via smtp_tls_policy_maps

Postfix supports MTA-STS through an smtp_tls_policy_maps policy plugin, which replies with a TLS security level and name=value attributes with certificate matching requirements. Postfix 3.10 and later extend the policy plugin response with additional name=value attributes that are needed for TLSRPT.

Examples of smtp_tls_policy_maps plugins with MTA-STS support are:

- postfix-tlspol, supports domains with DANE (using Postfix built-in DANE), and domains with MTA-STS.

- postfix-mta-sts-resolver, supports domains with MTA-STS as of release 1.5.0 (February 2025).

Both plugins can generate the additional name=value attributes that Postfix needs for TLSRPT support (as of February 2025). This is enabled by setting a `tlsrpt` boolean in a plugin configuration file. This setting is safe with Postfix 3.10 and later, even if Postfix TLSRPT support is disabled (at build time or at run time). Postfix versions 3.9 and earlier will report a policy error with "`invalid attribute name`".

The examples in the text below apply to this MTA-STS policy example given in RFC 8461 Section 3.2:

>     version: STSv1
>     mode: enforce
>     mx: mail.example.com
>     mx: *.example.net
>     mx: backupmx.example.com
>     max_age: 604800

The list of supported attributes is given below. Instead of `name=value`, specify `{ name = value }` when a value may contain whitespace. A policy response may contain line breaks.

- `policy_type=type`

  Specify `sts` or `no-policy-found`.

  Example: `policy_type=sts`

- `policy_domain=name`

  The domain that the MTA-STS policy applies to.

  Example: `policy_domain=example.com`

- `{ policy_string = value }`

  Specify one `policy_string` instance for each MTA-STS policy feature, enclosed inside "{" and "}" to protect whitespace in attribute values.

  Example: `{ policy_string = version: STSv1 } { policy_string = mode: enforce } ...`

  The above form ignores whitespace after the opening "{", around the "=", and before the closing "}".

- `mx_host_pattern=pattern`

  Specify one `mx_host_pattern` instance for each "mx:" feature in the MTA-STS policy.

  Example: `mx_host_pattern=mail.example.com mx_host_pattern=*.example.net ...`

- `policy_failure=type`

  If specified, forces MTA-STS policy enforcement to fail with the indicated error, even if a server certificate would satisfy conventional PKI constraints. Valid errors are `sts-policy-fetch-error, sts-policy-invalid`, `sts-webpki-invalid`, or the less informative `validation-failure`.

  Example: `policy_failure=sts-webpki-invalid`

- `policy_ttl=time` (deprecated)

  This attribute is deprecated. The time value is not used, and support for this attribute will eventually be removed from the code.

Notes:

- Postfix 3.10 and later will accept these additional attributes in an MTA-STS response even if Postfix TLSRPT support is disabled (at build time or at run time). With Postfix TLSRPT support turned off, Postfix may still use the `policy_failure` attribute, and will ignore the attributes that are used only for TLSRPT.

- It is an error to specify these attributes for a non-STS policy.

## Limitations

The Postfix TLSRPT implementation reports only TLS handshake success or failure. It does not report failure to connect, or connections that break before or after a TLS handshake.

The Postfix TLSRPT implementation reports at most one final TLS handshake status (either 'success' or 'failure') per SMTP connection. Postfix TLSRPT will not report a recoverable failure and then later report a final status of 'success' for that same connection. The reason is that it's too complicated to filter TLS errors and to report error details from the TLS engine back to the SMTP protocol engine. It just is not how Postfix works internally.

## Credits

- The TLSRPT client library, and the infrastructure to collect, fetch, and report TLSRPT information, are implemented and maintained by sys4.
- Wietse Venema implemented the integration with Postfix.