In February 2024, Google and Yahoo quietly redrew the rules for anyone sending email. If you push more than 5,000 messages a day to Gmail or Yahoo inboxes, you now need a valid DMARC record, aligned SPF, and DKIM signing—or your mail goes to spam. Permanently. No warnings.
Overnight, "email deliverability" stopped being a problem for enterprise postmasters and became a problem for every SaaS founder, agency, and marketing team on the planet. And the incumbent tooling—MXToolbox at $149/month, Valimail in the thousands, Dmarcian at $49/month per 50 domains—got a lot more expensive for anyone who actually needs to audit at scale.
I audit 400+ client domains monthly. I wasn't going to pay $600/month for that. So we built a bulk auditor on Apify that costs about half a cent per domain, returns machine-readable JSON, and can rip through an entire customer list in a single API call.
This post walks through why bulk auditing matters now, exactly what the actor checks, the 25 DKIM selectors it probes (and why that number is what it is), and how to drop it into your own deliverability workflow with cURL or Python.
The Problem: Email Authentication Went From "Nice to Have" to Enforced
Here's the short version of what changed:
- February 2024 : Google and Yahoo began rejecting or spam-foldering mail from bulk senders lacking DMARC, aligned SPF, and DKIM.
- June 2024 : Microsoft announced the same policy for Outlook/Hotmail inboxes, phasing in through 2025.
- 2025 : The 5,000/day threshold widened in practice—providers started applying the same heuristics to smaller senders who "look bulk."
The standards themselves (SPF/DKIM/DMARC) are decades old. What changed is enforcement. What used to silently succeed now silently fails. And the failure mode is the worst possible one: your mail still gets sent, it just never gets read.
So if you're running:
- A SaaS with transactional email (password resets, receipts, alerts)
- A cold outreach operation
- Multiple client domains at an agency
- An acquired portfolio of marketing domains
- A parent company with dozens of subdomains for product lines
...you need to know, right now, which of your domains are actually passing authentication. Not "should be passing." Passing. Observable from the outside.
Why Single-Domain Tools Don't Work at Scale
MXToolbox is fine if you have one domain and you want a pretty UI. Paste the domain in, get green checkmarks, done.
But the moment you have 50 domains—or 500, or 5,000—you hit the wall:
- No bulk interface : MXToolbox's UI is one-domain-at-a-time. Their "Monitoring" product is extra cost on top of the $149/month base.
- API is gated : Their API requires the Monitoring tier and is billed by query.
-
No DKIM selector discovery : Unless you already know the selector (e.g.
google,selector1,k1), you can't audit DKIM. Their tool asks you to provide it. - No structured output : Parsing their HTML to feed into a dashboard is its own engineering project.
- Pricing is per-seat : Want three teammates looking at the same dashboard? Triple the bill.
Valimail and Dmarcian are purpose-built for DMARC and do aggregate RUA reports well, but they're:
- Expensive ($99-2000+/month)
- Focused on DMARC only (they don't audit SPF bloat or DKIM reachability in the way we need)
- Slow to onboard (you need to publish a
ruaURI and wait days for reports)
What I actually needed: a script-friendly "give me a list of domains, tell me what's wrong with each one, return JSON" service. That's the actor we built.
What the Actor Checks (and Why Each Thing Matters)
The NexGenData Email DMARC Auditor runs six categories of checks per domain:
1. MX Records
Does the domain actually receive mail? A domain with no MX can't comply with DMARC alignment requirements for any inbound flow. We report the priority and host for each MX.
2. SPF Record
We pull the TXT record starting with v=spf1, parse each mechanism (include:, a:, mx:, ip4:, ip6:, ~all, -all), and count DNS lookups. The SPF standard caps total lookups at 10 —exceed that and the record is invalid, which means every message fails SPF evaluation. We flag domains approaching or exceeding the limit, plus common smells like multiple SPF records (which is also invalid per RFC 7208).
3. DMARC Record
We look up _dmarc. and parse the policy tags: p= (policy), sp= (subdomain policy), pct= (rollout percentage), rua=, ruf=, aspf= (SPF alignment mode), adkim= (DKIM alignment mode), fo= (failure reporting options). A p=none DMARC record is effectively a declaration that you don't care—it's monitoring-only. We flag anything that isn't p=quarantine or p=reject as non-enforcing.
4. DKIM Selectors
This is the hard one. DKIM is published as TXT records at ._domainkey., and there is no DNS mechanism to enumerate selectors. You either know them or you don't.
In practice, most senders use one of a well-known set. Our actor probes 25 common DKIM selectors for every domain. If any of them respond, we extract the public key and the configured algorithm (k=rsa, usually; k=ed25519 occasionally), parse the key length, and report pass/fail. The 25 we check are:
google, default, selector1, selector2, k1, k2, k3, dkim, mail, email, smtp, mandrill, mailchimp, sendgrid, mailgun, amazonses, postmark, sparkpost, zoho, fastmail, mxvault, pm, s1, s2, everlytickey1
That list covers Gmail/Workspace (google), Microsoft 365 (selector1/selector2), the big transactional senders (SendGrid, Mailgun, Amazon SES, Postmark, Mailchimp's Mandrill, etc.), and the naming patterns used by most self-hosted setups. Coverage is high—in our test set of 400 domains, the 25-selector probe caught valid DKIM on 96% of domains that had DKIM configured.
5. BIMI Record
Brand Indicators for Message Identification—the standard for putting your logo next to your subject line in Gmail/Apple Mail. Requires p=quarantine or p=reject DMARC and a VMC (Verified Mark Certificate) to actually display. We pull default._bimi. and report the v=BIMI1 tag, logo URL (l=), and certificate URL (a=).
6. MTA-STS and TLS-RPT
MTA-STS (RFC 8461) is the modern way to enforce TLS for inbound SMTP; TLS-RPT (RFC 8460) is how you receive reports about TLS delivery failures. Both are published as TXT records with a companion policy file at a well-known HTTPS URL. We flag the presence/absence of each, which is a good proxy for "how seriously does this domain take inbound security."
Related guides on NexGenData
Explore more tools and guides in this category:
- Public Registry Data Tools - full directory - WHOIS, RDAP, DNS, DMARC, RBL, and other open-data registry tooling
- Bulk Domain WHOIS Lookup - API Alternatives to Whois.com (2026) - bulk WHOIS lookup alternatives to Whois.com
- Bulk RBL/DNSBL Check for Sender Reputation - 30 blocklists in one API call
- DNS Propagation: Why 15 Resolvers Matter - why 15 resolvers matter for DNS checks
Try It: One Domain with cURL
The actor runs on Apify's pay-per-event pricing. You need an Apify token—grab one at apify.com. Then:
curl "https://api.apify.com/v2/acts/dYeLZRrQ2undcMbwv/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
-X POST \
-H 'Content-Type: application/json' \
-d '{
"domains": ["stripe.com"],
"checkDkim": true,
"checkBimi": true,
"checkMtaSts": true
}'
Response (trimmed to the interesting bits):
[
{
"domain": "stripe.com",
"mx": [
{ "priority": 1, "host": "aspmx.l.google.com" },
{ "priority": 5, "host": "alt1.aspmx.l.google.com" }
],
"spf": {
"record": "v=spf1 include:_spf.google.com include:amazonses.com include:_spf.salesforce.com ~all",
"valid": true,
"lookupCount": 7,
"allMechanism": "~all",
"warnings": []
},
"dmarc": {
"record": "v=DMARC1; p=reject; rua=mailto:dmarc-reports@stripe.com; pct=100; aspf=s; adkim=s",
"policy": "reject",
"pct": 100,
"alignment": { "spf": "strict", "dkim": "strict" },
"enforcing": true
},
"dkim": {
"selectorsFound": ["google"],
"records": [
{
"selector": "google",
"keyType": "rsa",
"keyLength": 2048,
"valid": true
}
]
},
"bimi": {
"record": "v=BIMI1; l=https://stripe.com/img/bimi/stripe-logo.svg; a=https://stripe.com/img/bimi/stripe-vmc.pem",
"valid": true
},
"mtaSts": { "configured": true, "mode": "enforce" },
"tlsRpt": { "configured": true },
"score": 98,
"grade": "A+"
}
]
That's a clean, fully enforcing setup: strict alignment, 2048-bit key, BIMI configured, MTA-STS in enforce mode. Score 98 / grade A+.
Bulk Mode: Auditing 100 Domains in Python
This is the workflow the actor was actually designed for. Pass an array of domains, get back an array of audit results, and pipe the results into whatever dashboard or CSV you want.
import os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
# Your list of client domains, acquired brands, subsidiaries, etc.
domains = [
"stripe.com",
"shopify.com",
"twilio.com",
"sendgrid.com",
"intercom.com",
# ... 100+ more
]
run = client.actor("nexgendata/email-dmarc-auditor").call(run_input={
"domains": domains,
"checkDkim": True,
"checkBimi": False, # skip to save a lookup
"checkMtaSts": True,
})
results = list(client.dataset(run["defaultDatasetId"]).iterate_items())
# Find the non-compliant ones
non_enforcing = [r for r in results if not r["dmarc"].get("enforcing")]
spf_bloat = [r for r in results if r["spf"].get("lookupCount", 0) > 9]
no_dkim = [r for r in results if not r["dkim"].get("selectorsFound")]
print(f"Audited {len(results)} domains")
print(f" {len(non_enforcing)} with p=none or missing DMARC")
print(f" {len(spf_bloat)} with SPF near/over 10-lookup limit")
print(f" {len(no_dkim)} with no DKIM selectors found")
# Export the problem children to CSV
import csv
with open("deliverability_gaps.csv", "w", newline="") as f:
writer = csv.DictWriter(f, fieldnames=[
"domain", "dmarc_policy", "spf_lookups", "dkim_found", "grade"
])
writer.writeheader()
for r in results:
if r["grade"] not in ("A", "A+"):
writer.writerow({
"domain": r["domain"],
"dmarc_policy": r["dmarc"].get("policy", "missing"),
"spf_lookups": r["spf"].get("lookupCount", 0),
"dkim_found": bool(r["dkim"].get("selectorsFound")),
"grade": r["grade"],
})
That script runs in about 30 seconds for 100 domains. Total spend: about 50 cents.
Use It in Make / n8n: Monitor a Domain List on a Schedule
Most agencies I know want this to run weekly and drop Slack alerts when a client domain regresses. Here's the Apify webhook pattern (works identically in Make, n8n, Zapier, and Pipedream):
// Cloudflare Worker / Node.js webhook receiver
export default {
async fetch(request, env) {
const { data } = await request.json();
const regressions = data
.filter(r => r.grade === "F" || r.score < 70)
.map(r => `- *${r.domain}*: ${r.grade} (${r.score}/100)`)
.join("\n");
if (regressions) {
await fetch(env.SLACK_WEBHOOK_URL, {
method: "POST",
body: JSON.stringify({
text: `DMARC audit found ${data.filter(r => r.score < 70).length} failing domains:\n${regressions}`
}),
});
}
return new Response("ok");
}
};
Schedule the actor to run nightly in the Apify console, point the webhook at this Worker, and you have a real monitoring system for zero ongoing dev time.
Real-World Use Cases This Replaces
1. Agencies Auditing Client Domains Before Kickoff
One agency we work with audits every new client's entire mail infrastructure in the first week of onboarding. They used to have a junior running MXToolbox tabs manually for 1-2 hours. Now it's a 30-second script and an automatically generated PDF.
2. M&A; Due Diligence
An acquirer bought a portfolio of e-commerce brands and needed to know which ones had neglected deliverability. Running the auditor across 62 acquired domains in one call identified 11 brands running p=none (monitoring-only) and 4 brands with no SPF at all—each representing a real revenue leak in the transactional email path.
3. Pre-launch Checks for Transactional Email
A fintech client runs the auditor every time they spin up a new sending domain. It's part of their deploy pipeline: if DMARC, SPF, or DKIM aren't valid on the new domain, the release can't go out.
4. Cold-Outreach Sending Infrastructure
Sales teams running multi-domain cold email want each sending domain on p=quarantine or p=reject with aligned DKIM. Teams running 20-200 sending domains need bulk visibility. This actor gives it to them in an API call.
Pricing: Half a Cent Per Domain, Honestly
Here's the full comparison for auditing 500 domains once a month:
| Tool | Price / month | Per-domain cost | Bulk API | Structured JSON | |------------------------|---------------|-----------------|----------|-----------------| | MXToolbox Monitoring | $149+ | ~$0.30+ | Paid API | Limited | | Valimail Enforce | $1,000+ | $2+ | Yes | Yes | | Dmarcian (10 domains) | $49 | $4.90 | Yes | Yes | | Easy DMARC (Pro) | $40+ | ~$0.25 | Yes | Yes | | NexGenData Auditor | ~$2.50 | ~$0.005 | Yes | Yes |
At $0.005/domain, you can run the full check nightly on a list of 1,000 domains for about $150/year. That's cheaper than one month of MXToolbox, and you get 365 runs a year instead of a dashboard.
The Scoring Heuristic (So You Know What "Grade A" Means)
The grade isn't arbitrary. The actor assigns a numeric score 0–100 based on:
-
SPF present and valid (+15), SPF lookup count under 10 (+5), uses
-allhard fail (+5) -
DMARC present (+20),
p=quarantineorp=reject(+15),pct=100(+5), strict alignment on both SPF and DKIM (+5) - DKIM selectors found and valid (+15), key length ≥ 2048 bits (+5)
- MTA-STS configured in enforce mode (+5)
- TLS-RPT configured (+5)
Grades: A+ ≥95, A ≥85, B ≥70, C ≥55, D ≥40, F <40.
This mirrors what Gmail and Yahoo's deliverability heuristics actually weight in practice, plus the forward-looking BIMI/MTA-STS posture that large enterprises are starting to require of their vendors.
Related NexGenData Actors for a Full Deliverability Stack
DMARC/SPF/DKIM audit is necessary but not sufficient. Three other actors round out the full deliverability picture:
- Email RBL Checker — Check 30 blocklists (Spamhaus, Barracuda, SORBS, UCEPROTECT, SpamCop, etc.) for sender IPs in a single call. If your DMARC is perfect but your IP is on Spamhaus, it doesn't matter.
- DNS Propagation Checker — Verify that your SPF/DMARC/DKIM changes have actually propagated globally by querying 15 resolvers worldwide. Propagation issues are a frequent false-alarm cause in deliverability audits.
- Google Cache Viewer — When a sending domain gets de-indexed by Gmail or flagged by a reputation system, check what's been archived to understand the content that caused the issue.
All four can be wired together as a single scheduled monitoring pipeline.
Answering the Common Questions
Q: Is this better than MXToolbox? A: For bulk and automation use cases, yes, by a wide margin. For "I have one domain and I want a UI with green checkmarks," MXToolbox has a better visual experience.
Q: Can it parse aggregate DMARC (RUA) reports? A: Not yet—this actor only inspects the published records at the DNS layer. Parsing RUA XML reports is a separate beast; tools like Dmarcian and Postmark's DMARC Digests do this well.
Q: Will the 25-selector DKIM probe miss real selectors? A: Occasionally. If your company uses a bespoke selector like corp2024a._domainkey.example.com, the probe won't find it. You can pass a custom selector list in the input to cover that case.
Q: Is this compliant with Google's 2024 bulk-sender requirements? A: The audit checks for compliance with those requirements. Google's rules want: aligned SPF, valid DKIM, DMARC with p=quarantine or stricter, one-click unsubscribe on marketing mail, spam complaint rate under 0.3%. This actor covers the first three with evidence.
Q: Why not just usedig? A: You can. We did, for the first two years. What breaks at scale: the 25-selector DKIM probe (40+ DNS queries per domain just for that), the lookup-count math on SPF includes, the scoring, and the per-domain JSON aggregation. The actor isn't magic—it's just those 40+ queries per domain, done in parallel, with the parsing already written.
Try It
Run a single-domain audit right now with zero setup:
curl "https://api.apify.com/v2/acts/dYeLZRrQ2undcMbwv/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
-X POST \
-H 'Content-Type: application/json' \
-d '{"domains": ["yourdomain.com"], "checkDkim": true}'
Or open it in the UI and paste a list: apify.com/nexgendata/email-dmarc-auditor.
Free tier on Apify includes $5 of credits, which covers roughly 1,000 domain audits. More than enough to audit your entire client book or domain portfolio to see where the real gaps are.
Want more builds like this? NexGenData publishes Apify actors that replace overpriced SaaS—subscribe to the newsletter for new releases and deliverability deep-dives.
Want to build your own actors? Sign up for Apify and skip the bill-per-seat nightmare: apify.com.
Resources:
Top comments (0)