feat: encode reported-on domain in VERP + add bounce handler - #442
Merged
thegushi merged 2 commits intoAug 22, 2026
Merged
Conversation
For aggregate reports, verp_sender() now embeds the domain the report concerns ahead of the recipient tag, e.g.: postmaster+example.com+dmarc-rua=aggregator.com@reporter.example.com This lets a bounce-processing script recover the domain directly from a returned report's envelope sender, without needing to look up which domain(s) route through a given RUA address -- useful for feeding domain-specific signals (e.g. a StaleMARC checkDomain recheck) off of delivery failures. Forensic report VERP addresses are left unchanged, since --forensic relays a pre-formed AFRF message with no readily-available "domain being reported on" of its own.
Adds a mail-alias/pipe-target script that decodes the VERP-encoded
recipient of a bounced DMARC report -- the failing RUA/RUF address, and,
for aggregate reports, the domain being reported on -- and:
- INSERTs the failing address into the suppressions table, so later
opendmarc-reports runs skip it automatically; and
- optionally prompts StaleMARC's checkDomain endpoint to retest the
recovered domain's DMARC reporting deliverability (--stale-notify,
on by default).
The recipient is read from stdin (Original-Recipient/Final-Recipient/
X-Original-To/Delivered-To/To, in that order) for standard MTA pipe
delivery, or supplied directly via --address for MTAs that can pass the
original recipient as an argument. Decoding failures are logged and
ignored (exit 0) rather than treated as errors, so unrelated mail
delivered to the same alias can't cause further bounces.
Cross-referenced from opendmarc-reports(8) and db/README.schema, which
previously only described this as something "a bounce-processing
script" would need to do.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
verp_sender()inopendmarc-reportsnow embeds the domain an aggregate report concerns into the VERP envelope sender, e.g.postmaster+example.com+dmarc-rua=aggregator.com@reporter.example.com, so a bounce reveals the domain without needing to look up which domain(s) route through a given RUA/RUF address. Forensic report VERP addresses are unchanged (--forensicrelays a pre-formed AFRF message with no readily-available "domain being reported on").opendmarc-bounce-handler, a mail alias/pipe-target script that decodes a bounce's VERP-encoded recipient (from stdin DSN headers, or via--addressfor MTAs that can pass it directly), inserts the failing address into thesuppressionstable, and, when a domain was recovered, optionally prompts StaleMARC'scheckDomainendpoint to retest that domain's DMARC reporting deliverability (--stale-notify, on by default). When no domain is encoded (forensic bounces, or older aggregate reports sent before this change), the address is still suppressed but no StaleMARC prompt is made.Test plan
perl -con the substituted script (placeholders filled in) passes with no errorsdecode_verp/find_tagvia--test --verboseagainst synthetic DSNs: domain-annotated tag, legacy no-domain tag,--addressbypass, and empty inputautoreconf -fregenerates cleanly with the new.infiles wired intoconfigure.ac/reports/Makefile.am./configurecorrectly substitutesreports/opendmarc-bounce-handler{,.8}from the new templates