DMARC Report Ingestion
Daily DMARC aggregate (RUA) reports for theaccessible.org are ingested by the
dmarc-report Cloudflare Email Worker (workers/dmarc/) instead of landing in
larry@βs inbox.
Architecture
Reporter (google.com, yahoo.com, iphmx.com, β¦) ββ emails XML report (plain / .gz / .zip attachment) ββ [email protected] (Cloudflare Email Routing β Worker: dmarc-report) ββ parse attachment β structured JSON β KV (DMARC_KV, 400-day TTL) ββ track known source IPs (KV key: sources) ββ Resend alert to [email protected] when: β’ any record fails DMARC (neither DKIM nor SPF passed), or β’ a never-before-seen source IP sends as theaccessible.orgReports go to theaccessibleorg.com, not theaccessible.org, because theaccessible.orgβs MX points at Google Workspace β Cloudflare Email Routing cannot run there, so a Cloudflare-routed sibling domain receives the reports.
- Dashboard: https://dmarc-report.larry-c6c.workers.dev/ (shared-secret login;
key in
workers/dmarc/.dashboard-key.local, gitignored) - JSON API:
GET /api/reports?limit=100,GET /api/sourcesβAuthorization: Bearer <DASHBOARD_KEY> - Health:
GET /health(no auth)
KV layout (namespace DMARC_KV, id a68836529ded42fd85ae91eaace6b19f)
| Key | Value |
|---|---|
report:<zero-padded end ts>:<report id> | Parsed DmarcReport JSON (400-day TTL) |
sources | { [ip]: { firstSeen, lastSeen, orgs[], messages } } |
Keys sort chronologically, so the dashboard lists newest-first without an index.
The very first report seeds sources silently (otherwise every IP would alert).
Secrets / vars
RESEND_API_KEY(secret) β same key as~/.claude/scripts/send-email.shDASHBOARD_KEY(secret) β dashboard + API auth; local copy in.dashboard-key.localALERT_EMAIL_FROM/ALERT_EMAIL_TO/PRIMARY_DOMAIN(vars in wrangler.toml)
One-time DNS / routing setup (manual β wrangler token lacks zone write)
Status as of 2026-07-11: all three steps DONE and verified (routing tested end-to-end with a live test email; authorization TXT resolves).
- β
theaccessibleorg.com β Email β Email Routing β Routing rules: custom address
[email protected]β action Send to Worker βdmarc-report. - β
theaccessibleorg.com β DNS: TXT record β name
theaccessible.org._report._dmarc(full nametheaccessible.org._report._dmarc.theaccessibleorg.com), contentv=DMARC1. RFC 7489 Β§7.1 external-destination authorization; without it compliant reporters (Google, Yahoo, Microsoft) verify the record, find nothing, and silently refuse to send theaccessible.org reports to a theaccessibleorg.com address. - β
theaccessible.org β DNS:
_dmarcTXT record set tov=DMARC1; p=quarantine; rua=mailto:[email protected]; pct=100; adkim=s; aspf=r; fo=1
Reporters pick up rua/authorization changes within ~24h (they re-query DNS per
report run). Verify step 2 with:
dig +short TXT theaccessible.org._report._dmarc.theaccessibleorg.com
Failure behavior
- Unparseable inbound mail is not bounced; the worker emails an ingest-error alert instead (so a broken reporter canβt silently disappear).
- A failed Resend call after a successful parse logs but does not bounce β the report is already stored.
Deploy / test
cd workers/dmarcnpm test # vitest: parser, zip/gzip decoding, alert logicnpm run typechecknpm run deploy # wrangler deployBackfill/manual insert: build [{key, value}] JSON and
npx wrangler kv bulk put file.json --namespace-id a68836529ded42fd85ae91eaace6b19f.