Issue Description
Outbound DMARC aggregate reports declare the RFC 9990 namespace (urn:ietf:params:xml:ns:dmarc-2.0) but still emit two results per record: the EHLO result (with no ) and the MAIL FROM result (mfrom). That combination is valid under neither schema:
- RFC 7489: the namespaced root element is not recognised (as noted in #1250).
- RFC 9990: only one SPF result is allowed, and only for the MAIL FROM identity:
- §3.1.1.11 (“auth_results”): spf is “O” (optional, at most one); dkim is “*”.
- §3.1.1.13: “Only the ‘MAIL FROM’ identity (see Section 2.4 of [RFC7208]) is used in DMARC.”
- Appendix A: <xs:element name=“spf” … minOccurs=“0” maxOccurs=“1”/>
Related but not a duplicate: #1250 reported the same Cloudflare 555 on v0.16.15, and the reply attributed it to Cloudflare validating against RFC 7489. That may also be true, but the reports fail RFC 9990 validation independently of it.
Where it happens, on main:
- crates/smtp/src/reporting/dmarc.rs (lines 319-323) calls with_spf_output for both spf_ehlo (SPFDomainScope::Helo) and spf_mail_from (SPFDomainScope::MailFrom).
- mail-auth 0.13.2 Record::with_spf_output pushes onto auth_results.spf: Vec, and AuthResult::to_xml (src/report/dmarc/generate.rs) serialises every element.
- Neither changed in v0.16.22.
Expected Behavior
Each contains at most one : the result for the MAIL FROM identity as defined in RFC 7208 §2.4 (for a null reverse-path, postmaster@ the HELO domain), per RFC 9990 §3.1.1.13. The EHLO check result is not emitted as a separate element. is 1.0 (§3.1.1.2: “MUST have the value 1.0”).
Actual Behavior
Every record where the EHLO SPF check ran contains two elements. The EHLO one has no , so it also reads as a second MAIL FROM result with a contradictory value (none vs pass). is emitted as 1.
Receivers that validate strictly reject the report. Between 2026-09-11 and 2026-09-16, 7 of 7 reports sent to dmarc-reports.cloudflare.net were rejected with “555 5.7.1 invalid_report_schema”. I recovered all 7 from the bounce DSNs. Each has the RFC 9990 namespace, one and two . Each fails RFC 9990 Appendix A validation only at the second , and all 7 validate once the EHLO is removed. No other schema violation exists in any of them.
Reproduction Steps
- Receive a message where both the EHLO and MAIL FROM SPF checks run, from a domain whose DMARC record has a rua.
- Let the aggregate report be generated.
- Validate it against RFC 9990 Appendix A: xmllint --noout --schema rfc9990-appendixA.xsd report.xml
Reproducer (anonymised; the original was rejected by Cloudflare on 2026-09-11):
<?xml version="1.0" encoding="UTF-8" ?>
<feedback xmlns="urn:ietf:params:xml:ns:dmarc-2.0">
<version>1</version>
<report_metadata>
<org_name>example.org</org_name>
<email>[email protected]</email>
<report_id>1788990509_14293159088052110869</report_id>
<date_range>
<begin>1788990509</begin>
<end>1789076909</end>
</date_range>
</report_metadata>
<policy_published>
<domain>example.com</domain>
<p>reject</p>
<sp>reject</sp>
<np>reject</np>
<adkim>r</adkim>
<aspf>r</aspf>
<discovery_method>treewalk</discovery_method>
<fo>1</fo>
<testing>n</testing>
</policy_published>
<record>
<row>
<source_ip>192.0.2.10</source_ip>
<count>1</count>
<policy_evaluated>
<disposition>pass</disposition>
<dkim>pass</dkim>
<spf>fail</spf>
</policy_evaluated>
</row>
<identifiers>
<envelope_from>example.net</envelope_from>
<header_from>example.com</header_from>
</identifiers>
<auth_results>
<dkim>
<domain>example.com</domain>
<selector>sel1</selector>
<result>pass</result>
</dkim>
<dkim>
<domain>esp.example.net</domain>
<selector>sel2</selector>
<result>pass</result>
</dkim>
<spf>
<domain>mail-out.example.net</domain>
<result>none</result>
</spf>
<spf>
<domain>example.net</domain>
<scope>mfrom</scope>
<result>pass</result>
</spf>
</auth_results>
</record>
</feedback>
Relevant Log Output
$ xmllint --noout --schema rfc9990-appendixA.xsd report.xml
report.xml:53: Schemas validity error : Element '{urn:ietf:params:xml:ns:dmarc-2.0}spf': This element is not expected.
report.xml fails to validate
$ # same file with only the EHLO <spf> removed
report.xml validates
Bounce DSN from the relay, original report attached:
Final-Recipient: rfc822; <redacted>@dmarc-reports.cloudflare.net
Diagnostic-Code: smtp; 555 5.7.1 invalid_report_schema. YQvpyL6J2GuD
Stalwart Version
v0.16.x
Installation Method
Docker
Database Backend
RocksDB
Blob Storage
RocksDB
Search Engine
Internal
Directory Backend
Internal
Additional Context
- Exact version: v0.16.21 (docker.io/stalwartlabs/stalwart:v0.16.21@sha256:93c574e52249c1ebf90061da2c4c0756a7b72abfcc1fec34506a03c2e38b5977), run with Podman. The generating code is unchanged in v0.16.22 and on main.
- Outbound mail goes through a Postfix smarthost, which does not modify the message body. The report XML above is the gzip attachment recovered byte-for-byte from the bounce DSN, i.e. exactly what Cloudflare received.
- Schema used: RFC 9990 Appendix A, copied verbatim from the RFC text.
I have reviewed the documentation and FAQ and confirm that my issue is NOT addressed there.
on
I have searched this support forum (open and closed topics) and confirm this is not a duplicate.
on