Skip to content

Analysis

A domain owner who publishes DMARC and TLS reporting records receives reports from every server that handles the domain’s mail. These include daily DMARC aggregate reports, TLS reports, and feedback reports about individual messages. The reports are machine-readable documents, and there is one from each reporting server.

Stalwart reads these reports itself. It analyses the reports sent to the domains it hosts, logs what they say and stores them. As a result, authentication or transport failures, and abuse of a domain, are noticed without anyone reading the reports by hand.

Stalwart treats a message as a report only when three conditions hold:

  • It arrives over SMTP from an unauthenticated session.
  • It is addressed to one of the inboundReportAddresses on the ReportSettings singleton (found in the WebUI under Settings › MTA › Reports › General).
  • It contains a report: a DMARC aggregate report in XML, a TLS report in JSON, or a feedback report in the Abuse Reporting Format (RFC 5965). The Abuse Reporting Format covers abuse complaints and DKIM, SPF and DMARC failure reports.

Reports compressed with gzip or zip are decompressed first. Only the first report found in a message is analysed. Messages to the report addresses that contain no report are delivered like any other message.

The report addresses are compared with the original recipient of the message. By default, the list holds postmaster@*, which intercepts the postmaster address of every domain. An entry may start or end with * to match any prefix or suffix.

Intercepting an address does not create it. The intercepted addresses must exist, as accounts, aliases or a catch-all, because the SMTP server accepts the messages only then. The following object body intercepts the addresses usually published for DMARC and TLS reports:

{
"inboundReportAddresses": {"dmarc-reports@*": true, "tls-reports@*": true, "postmaster@*": true}
}

After analysis, a report can also be delivered to a mailbox, which inboundReportForwarding decides. While it is enabled, as it is by default, an analysed report is also delivered to the mailbox of its recipient. When it is disabled, the report is not delivered to the report addresses, and a message addressed only to them is accepted and only analysed.

Compressed reports have a size limit of their own. maxInboundReportSize limits the decompressed size of a compressed report. A report that exceeds it, or that cannot be decompressed, is skipped and logged as incoming-report.decompress-error.

The results of the analysis reach the administrator through events. Each analysed report is logged at the info level as an event of the incoming-report group: incoming-report.dmarc-report, incoming-report.tls-report, incoming-report.abuse-report, incoming-report.auth-failure-report and the other feedback types.

Two events, at the warn level, signal that a report describes a problem:

  • incoming-report.dmarc-report-with-warnings: the DMARC report lists messages that failed SPF or DKIM, or that the receiver quarantined or rejected.
  • incoming-report.tls-report-with-warnings: the TLS report lists failed TLS sessions to the domain’s servers.

Reports that cannot be parsed are logged as incoming-report.message-parse-failed, incoming-report.dmarc-parse-failed, incoming-report.tls-rpc-parse-failed or incoming-report.arf-parse-failed.

A webhook or a tracer that collects the warning events turns them into alerts.

Analysed reports are stored as DmarcExternalReport, TlsExternalReport and ArfExternalReport objects. They can be viewed and deleted as described in Queue and report management.

The reports are kept for the period set by holdMtaReportsFor on the DataRetention singleton, 30 days by default. With the field set to null, reports are still analysed and logged, but they are not stored.