Web and domains
Bulk SPF, DMARC and DKIM Checker for Domain Lists
Checking email authentication one domain at a time is slow. This Actor takes a list of domains and returns one record per domain with its SPF, DMARC, DKIM, MTA-STS and BIMI setup, an email security score, and optionally WHOIS, TLS and HTTP data.
SPF, DMARC & DKIM Checker — Bulk Domain WHOIS, DNS & SSL. Pay per result; see the Store page for current pricing.
The source and its limits
Everything comes from public sources: DNS records over DNS-over-HTTPS (Cloudflare, with Google as fallback), registration data from RDAP (the successor to WHOIS), and each domain's own TLS and HTTP endpoints. No API keys, proxies or browser.
The dns section reads A, AAAA, MX, NS, TXT, CAA and SOA records and checks:
- SPF: record present, syntax, lookup count and the
allqualifier. - DMARC: policy, subdomain policy,
pct, and aggregate and forensic reporting addresses. - DKIM: 18 common selectors probed, plus any you add.
- MTA-STS record and policy mode, and BIMI.
How the email security score is computed
| Check | Points |
|---|---|
| SPF record present and valid (10 lookups or fewer, no unknown terms, single record) | 25 |
DMARC policy reject / quarantine / none | 35 / 20 / 5 |
| At least one DKIM selector found | 25 |
| MTA-STS record present | 10 |
| BIMI record present | 5 |
Limits worth knowing
- DKIM selectors cannot be listed from outside, only probed. A domain whose selector is not in the list shows no DKIM even if it is configured; add your provider's selector in
dkimSelectors. - The SPF lookup count covers the top-level record only (includes are not followed), so it is a lower bound.
- Subdomains are reduced to their registrable domain, and many registries redact WHOIS contact data.
- All sections of a domain share a 20-second budget; a slow source marks its own section as an error without blocking the others.
Fields you get
| Field | What it holds |
|---|---|
dns.spfRecord, spfValid, spfAllQualifier, spfLookupCount, spfIssues | SPF |
dns.dmarcRecord, dmarcPolicy, dmarcSubdomainPolicy, dmarcPct, hasRua, hasRuf | DMARC |
dns.dkimSelectorsProbed, dkimSelectorsFound | DKIM |
dns.mtaStsPresent, mtaStsPolicyMode, bimiRecord | MTA-STS and BIMI |
dns.mx, mxProviderGuess | Mail servers and a provider guess (Google, Microsoft, Zoho and others) |
emailSecurityScore, summary | Score from 0 to 100 and a one-line summary |
whois.* | Registrar, registration and expiration dates, nameservers, DNSSEC (with whois) |
tls.*, http.* | Certificate issuer and expiry, status code, redirects, security headers, tech hints |
Example output
The email-security part of one record for github.com (from the Actor's README; values illustrative, other sections omitted):
{
"domain": "github.com",
"dns": {
"status": "ok",
"hasMx": true,
"mxProviderGuess": "google",
"spfRecord": "v=spf1 ip4:192.30.252.0/22 include:_netblocks.google.com ... ~all",
"spfValid": true,
"spfAllQualifier": "~all",
"spfLookupCount": 7,
"spfIssues": [],
"dmarcRecord": "v=DMARC1; p=reject; pct=100; rua=mailto:dmarc@github.com",
"dmarcPolicy": "reject",
"dmarcSubdomainPolicy": null,
"dmarcPct": 100,
"hasRua": true,
"hasRuf": false,
"dmarcIssues": [],
"dkimSelectorsProbed": 18,
"dkimSelectorsFound": [
"google",
"pm"
],
"mtaStsPresent": true,
"mtaStsPolicyMode": "enforce",
"bimiRecord": null
},
"dmarcPolicy": "reject",
"emailSecurityScore": 95,
"errors": {}
}
Use cases
Deliverability audit of a client list
Run the dns section over every client domain and sort by emailSecurityScore to find missing DMARC or a soft SPF policy.
Expiry watch
Run whois and tls on a schedule and alert on low daysUntilExpiry for domains and certificates.
Lead segmentation
Combine dns and http to group domains by mail provider and tech stack hints.
How to run it
You need an Apify account and its API token (Console → Settings → API & Integrations). Each run is billed per result to your account; set a maximum total charge for the run to cap spend.
With curl
The sync endpoint starts a run, waits up to 300 seconds and returns the dataset items. SPF, DMARC and DKIM for ten domains, DNS section only:
export APIFY_TOKEN=<your Apify API token>
curl -sS -X POST \
"https://api.apify.com/v2/acts/owlabee~spf-dmarc-dkim-checker/run-sync-get-dataset-items" \
-H "Authorization: Bearer ${APIFY_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"domains": [
"example.com",
"github.com",
"apify.com",
"cloudflare.com",
"mozilla.org",
"wikipedia.org",
"stripe.com",
"shopify.com",
"nytimes.com",
"python.org"
],
"sections": [
"dns"
],
"dkimSelectors": [],
"maxConcurrency": 5
}'
From an AI agent (MCP)
Apify hosts an MCP server. This config exposes only this Actor to the agent:
{
"mcpServers": {
"owlabee-spf-dmarc-dkim-checker": {
"url": "https://mcp.apify.com/?tools=owlabee/spf-dmarc-dkim-checker",
"headers": {
"Authorization": "Bearer ${APIFY_TOKEN}"
}
}
}
}
Then ask, for example: Check SPF, DMARC and DKIM for these ten domains and list the ones whose DMARC policy is not reject, with their email security score.
Python, Node.js and more examples
Runnable curl.sh, python.py, node.mjs and mcp.json files for this Actor are in examples/spf-dmarc-dkim-checker on GitHub.
FAQ
Why does a domain show no DKIM when I know it has it?
DKIM selectors are not discoverable. The Actor probes 18 common ones; add yours in dkimSelectors (for example fm1 for Fastmail or krs for Klaviyo).
Does it send email or change anything?
No. It only reads public DNS, RDAP, TLS and HTTP responses.
How many domains can I check?
The list has no fixed cap. Up to 20 domains run in parallel (maxConcurrency), and the run stops cleanly at its maximum total charge.
Why is a WHOIS field empty?
Most registries redact personal data, and some country domains offer no RDAP. The Actor reports exactly what the registry returns.
What if a site has no web server?
tls.status and http.status become unavailable; the DNS and WHOIS sections are still filled.