Email Authentication & Sender Authentication — Bulk DMARC
Pricing
$4.00 / 1,000 domain auditeds
Email Authentication & Sender Authentication — Bulk DMARC
Audit SPF, DKIM and DMARC for a list of domains. Catches SPF 10-lookup permerrors, subdomain policy gaps and Gmail/Outlook bulk-sender failures. RFC 9989 tree walk.
Pricing
$4.00 / 1,000 domain auditeds
Rating
0.0
(0)
Developer
Drumlin Labs
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
11 days ago
Last modified
Categories
Share
Email Authentication Auditor — SPF, DKIM & DMARC in Bulk
Audit SPF, DKIM and DMARC for a list of domains. Each domain is resolved from public DNS and reported with the lookups behind it, including failures that leave a record still reading correctly to a human.
Feed it domains. Get a table with a score, a Gmail/Outlook bulk-sender verdict, every step of the DMARC tree walk, the SPF lookup count across the resolved include graph, and a plain-English list of findings.
What it inspects
SPF permerrors from the 10-lookup limit.
RFC 7208 permits ten DNS-querying mechanisms. Add one more vendor include: and SPF returns
permerror — it stops passing entirely, while the record still reads correctly to a human.
This is the most common silent SPF failure. This Actor follows the include: and redirect=
graph and reports the count it reaches.
Subdomain policy gaps.
A domain can publish p=reject at the apex and sp=none one label down, leaving every
subdomain spoofable. That gap is reported explicitly.
Inherited DMARC policy. Most sending domains are subdomains, and most subdomains publish no DMARC record of their own. Which policy actually applies has to be discovered by walking up the DNS tree — and the rules for that changed in May 2026. See below.
Bulk-sender compliance.
Gmail and Outlook both enforce authentication requirements above roughly 5,000 messages/day.
Since 5 May 2025, Outlook rejects non-compliant mail outright with 550 5.7.515. Each domain
gets a pass / fail / not-applicable verdict on the DNS-checkable part of those rules.
Implemented against RFC 9989 (May 2026)
RFC 9989 — Proposed Standard, May 2026 — obsoleted RFC 7489 and changed how the organizational domain is found.
| RFC 7489 (2015, obsolete) | RFC 9989 (May 2026) | |
|---|---|---|
| Org-domain discovery | Public Suffix List, two lookups | DNS Tree Walk, up to 8 queries |
np (non-existent subdomains) | experimental extension | core |
psd (public suffix domain) | not present | stops the walk |
This Actor implements the tree walk and prints every step it took in the
dmarcTreeWalk field, so you can check the work instead of trusting a verdict.
Pricing
$0.004 per domain successfully audited — duplicates, unparseable entries and failed lookups are never billed, and your maximum cost per run is honoured as a hard ceiling, with auditing stopping at the cap rather than continuing past it.
Input
| Field | Type | Description |
|---|---|---|
domains | array | Domains to audit. Accepts bare domains (example.com), URLs (https://example.com/path) or email addresses (user@example.com) — each is normalised. Duplicates are removed. |
concurrency | integer | Parallel audits, 1–20. Default 5. |
onlyProblems | boolean | Output only domains with findings. Default false. |
{"domains": ["github.com", "mail.example.com", "user@acme.io"],"concurrency": 5,"onlyProblems": false}
Output
One row per domain. Key fields:
| Field | Description |
|---|---|
score | 0–100. Criticals dominate; the scale is deliberately coarse. |
bulkSenderVerdict | pass, fail, or not_applicable. Graded only on evidence that the domain sends mail — see sendsMail |
sendsMail / receivesMail | What DNS asserts. sendsMail is what the verdict turns on; MX sets receivesMail, not sendsMail |
nullMx | The domain publishes a null MX (RFC 7505): it declares that it accepts no mail |
dmarcPolicy / dmarcPolicySource | Effective policy and whether it came from p, sp or np |
dmarcInherited / dmarcRecordAt | Whether policy was inherited, and from which ancestor |
dmarcTreeWalk | Every step of the RFC 9989 walk, e.g. mail.acme.io:0 > acme.io:1 |
spfLookups / spfLookupLimitExceeded | DNS lookup count across the resolved include graph |
dkimSelectorsFound | Which of 12 common selectors returned a working key |
dkimWildcard | true when a wildcard under _domainkey answers every selector, so presence cannot be determined |
dkimRevokedSelectors | Selectors whose key is revoked — an empty p= per RFC 6376 §3.6.1 |
criticalFindings | Critical issues, pipe-separated |
findings | Full array — id, severity, title, detail |
MX means a domain receives mail, not that it sends any. A domain that only receives — a
forwarding address, a contact mailbox — is reported not_applicable rather than graded as a failing
bulk sender, and the summary names which non-sending case it is. See CHANGELOG.md.
A SUMMARY record is written to the key-value store with portfolio-level counts, including how
many domains have SPF permerrors and how many inherit their DMARC policy.
Check your own bill: the billing receipt
Every run writes a BILLING_RECEIPT so you can verify the charge yourself rather than take
our word for it. You will find it in two places on every run, paid or free:
- Key-value store — open the run, go to Storage → Key-value store, and open the
BILLING_RECEIPTkey. This is the complete copy. Via API:GET https://api.apify.com/v2/key-value-stores/<runKeyValueStoreId>/records/BILLING_RECEIPT - Run log — the last block of the log, under
--- billing receipt ---. Same numbers, minus the nestedskipReasonsbreakdown.
The rule the receipt exists to prove: you are billed once per distinct domain actually audited. Duplicates, unparseable entries and failed audits are delivered or reported but never charged, and a run that audits nothing costs nothing.
Your maximum cost per run is a hard ceiling, not a target we stop near. Auditing stops at the cap: nothing beyond it is audited, and no event beyond it is charged. If the cap is reached, the receipt says so and records exactly where.
| Field | What it means |
|---|---|
eventName | The charged event — domain-audited. |
delivered | Distinct domains audited and returned to you. |
billedEvents | Distinct domains actually charged. Compare this against your invoice. |
duplicatesDropped | Repeats of a domain already audited this run. Delivered once, charged once. |
failuresNotCharged | Audits that failed. Never charged. |
invalidNotCharged | Inputs that never became an audit — unparseable or duplicate. Never charged. |
skipReasons | Why those inputs were skipped, counted by reason. |
deliveredUnbilled | Work delivered to you that we did not charge for — e.g. audits already in flight when the cap was reached. Yours free. |
budgetExhausted | true if your maximum cost per run stopped the work. Charging stops at the cap, never past it. |
billingActive | false when pay-per-event pricing is not in effect — the run was free. |
declaredBySource / coverageRatio | Denominator and delivered/declared ratio where a source publishes one. null here: a domain list has no external denominator. |
note | One plain-English sentence summarising the three fields above it. |
If billedEvents exceeds the number of distinct domains you got results for, that is a bug and a
bug report — send the run ID.
Honest limitations
These are stated up front rather than discovered later.
- DKIM selectors cannot be enumerated from DNS. Only guessed. This Actor probes the 12 most
common, and neither answer is proof on its own.
A miss is not proof that DKIM is absent — the key may sit at a selector not on the list.
A hit is not proof that it is present. A domain can publish a wildcard record under
_domainkeythat answers every selector, including ones nobody published; and a record whosep=is empty is a revoked key under RFC 6376 §3.6.1, not a working one. This Actor asks for an impossible selector before it asks for any real one — if that answers, it reportsdkimWildcard: trueinstead of a list of keys the domain never published — and it reports revoked selectors separately indkimRevokedSelectors. Every result says which case it is. - Deliverability is not the same as authentication. Sending-IP reputation, content, list hygiene and engagement history all matter and none is visible from DNS. This Actor does not claim to measure them; it lists them as unverifiable instead of quietly passing them.
- Results reflect DNS at the moment of the run. Records propagate.
- Not affiliated with the IETF, Google, or Microsoft. Specification references are citations.
Also available as a free API
Single-domain audits, no account and no key, at treewalk.drumlin.dev:
GET https://treewalk.drumlin.dev/v1/audit?domain=example.com
Same engine, same fields. Use this Actor when you have a list rather than one domain.
About
Every result is checkable without trusting us: each audit carries its own DMARC tree walk, its SPF lookup count and the exact records it read, so a verdict can be re-derived from public DNS rather than taken on faith. That is the point of the receipts.
Bug reports are most useful as a domain plus what you expected. Every result carries its own tree walk and lookup count, so a disagreement can be checked precisely rather than argued.
Treewalk is a Drumlin Labs tool — labs.drumlin.dev.
Support: support@drumlin.dev — monitored, best-effort, and the right place for a wrong result or a question about how an audit was computed. Charges, invoices and refunds are handled by Apify as merchant of record, not through this address.