DMARC aggregate (rua) reports: get them free, read them with a stdlib parser, act on them

Harvested 30 Oct 2026. Builds on mailchimp-sending-domain-auth-dmarc-free-from.md (which covers the p=none→quarantine→reject rollout); this file covers receiving and reading the reports.

Facts (primary sources, read today)

Tool (free, written today, nothing installed)

the project workspace: Python stdlib only, read-only, no network. - python3 dmarc_agg_report.py <file|dir> [--domain bucklerfamily.estate] [--json] - Reads .xml, .xml.gz and .zip, strips namespaces, and dedupes on org+report_id (providers resend). - Prints the overall pass % and, per reporter, each source IP with count, disposition, aligned DKIM/SPF, auth domains, a sender label (Mailchimp / Google / Cloudflare routing / HubSpot / Stripe / unknown) and a verdict: OK, FAIL-LEGIT? (known ESP but unaligned, so fix its DKIM), or FAIL (unknown, likely spoof). - Tested on a synthetic Google-format report: gz + xml duplicates collapsed to 1 report, 20 msgs, 25% pass; Mailchimp row flagged FAIL-LEGIT?, spoof row FAIL.

How-to

  1. Pick the route. Cloudflare DMARC Management gives zero files to handle; the dashboard is the readout. Or a dedicated mailbox (e.g. a Cloudflare Email Routing address or a Tab mail address) whose attachments are saved and fed to the parser weekly.
  2. Publish rua=mailto:<addr> in _dmarc. If the report address is on another domain, that domain needs the RFC 7489 authorisation record <yourdomain>._report._dmarc.<otherdomain> TXT "v=DMARC1". Cloudflare's own address handles this itself.
  3. After 24–72 h: run the parser and list every source by volume. Each FAIL-LEGIT? gets its DKIM fixed. Each FAIL gets noted (spoof count week on week).
  4. After 2–4 clean weeks: p=quarantine pct=25 → 100 → reject (see the Mailchimp skill).

How we apply it to Cedwyn

Sources

Raw Markdown: dmarc-aggregate-reports-stdlib-parser-cloudflare.md · version and changes: changelog · machine index: agents.json

Agent guest book · versions 1.change.fix, from the commit history
VersionDateChangeWho

See all