Email Security Signals: DMARC, SPF, DKIM & BIMI Checker
Pricing
$20.00 / 1,000 graded domains
Email Security Signals: DMARC, SPF, DKIM & BIMI Checker
Grade a list of domains A-F on email authentication: SPF (incl. 10-lookup limit), DMARC policy and reporting vendor, DKIM, MTA-STS, TLS-RPT, BIMI, DNSSEC, security.txt. Flags Google/Yahoo/Microsoft bulk-sender compliance, detected sending vendors and sales-ready pitch reasons.
Pricing
$20.00 / 1,000 graded domains
Rating
0.0
(0)
Developer
Siftsmith
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
3 hours ago
Last modified
Categories
Share
Email Security Signals — DMARC, SPF, DKIM & BIMI Checker
Give it a list of domains. Get back an A–F email-authentication grade for each one, the exact problems found, whether it meets the Google/Yahoo/Microsoft bulk-sender rules, which vendors send mail for it, who processes its DMARC reports, and plain-English pitch reasons you can drop into outreach.
Built for MSPs, email-security and deliverability vendors, and anyone prospecting on email posture. A pay-per-domain alternative to EasyDMARC ($35.99+/month) or MxToolbox Delivery Center ($129/month) when what you need is a bulk audit of other people's domains, not monitoring of your own.
How to check DMARC, SPF and DKIM for a list of domains
- Paste your domains into Domains — bare domains, URLs or email addresses all work. Use Bulk edit to paste a long list, one per line.
- Optional: add any custom DKIM selectors you know a domain uses in Extra DKIM selectors.
- Click Start. Results stream into the dataset as they finish.
- Export as CSV, Excel or JSON, or pull the dataset from the API. Then sort by
gradeor filter onbulkSenderCompliantin your spreadsheet to build a prospect list.
To run it on a schedule or from code, use the Apify API, a scheduled task, or the Apify integrations (Make, Zapier, Clay, and more).
What you get per domain
| Field | Example / meaning |
|---|---|
grade, score | B, 80 — see the rubric below |
bulkSenderCompliant | true / false / null — Google & Yahoo (Feb 2024) and Microsoft (May 2025) bulk-sender authentication rules: valid SPF, a DMARC record (p=none is enough), and DKIM. null means SPF and DMARC pass but no DKIM key was found at the selectors checked, so compliance is unknown (see Limitations) |
spf | the record, recordCount, valid (false when SPF is a permerror: more than one record, over 10 lookups, more than 2 void lookups, an mx name with more than 10 MX hosts, an unknown or misspelled mechanism such as inclde: or ipv4:, or an include/redirect target with no SPF record), recursive lookupCount (RFC 7208 limit is 10; lookupCountIsMinimum when an include couldn't be fetched), voidLookups (a/mx/exists names in the include tree that return no records; RFC 7208 allows 2; voidLookupsIsMinimum when one of those lookups failed or the 30-name cap was reached), effective allQualifier (-all, ~all, ?all, +all; the first all wins, as receivers stop there), following redirect= (null with an spf_all_lookup_failed issue if the redirect target couldn't be fetched) |
sendingVendors | third-party senders from SPF includes: Google Workspace, Microsoft 365, SendGrid, Mailchimp/Mandrill, Mailgun, Postmark, Amazon SES, HubSpot, Salesforce/Pardot, Zendesk, Freshdesk, Intercom, Klaviyo, Brevo, Zoho, Marketo, SparkPost, Mailjet, Customer.io, … |
spfIncludes | includes that aren't in the vendor table, listed raw |
dmarc | p, sp (the subdomain policy; when the record has no valid sp= it's the p= value, as receivers apply it), np (the RFC 9989 policy for non-existent subdomains; when the record has no valid np= it's the sp value), testing (true when the record has t=y, RFC 9989 testing mode: receivers apply one policy level lower), pct, rua, ruf, the record, recordCount, valid. A record with rua but no p= is applied as p=none (RFC 7489 §6.6.3). For a subdomain with no record of its own, this is the organisational domain's record, and p is the policy that applies to the subdomain (the parent's sp= if set, else its p=) |
dmarcInheritedFrom | the parent domain whose DMARC record applies (mail.google.com → google.com), or null when the domain publishes its own record or none is found |
dmarcReportingVendor | who receives the aggregate reports: dmarcian, Valimail, EasyDMARC, Agari, Proofpoint, Red Sift OnDMARC, Mimecast, PowerDMARC, URIports, Postmark DMARC Digests, Cloudflare, Fraudmarc, MxToolbox, Sendmarc, … ; self-hosted if reports go to the domain itself, other for an unrecognised third party, null if there's no rua. dmarcReportingVendors lists all of them |
dkimSelectorsFound | selectors with a published DKIM key (p= non-empty base64; a revoked key with an empty p= and wildcard SPF/DMARC answers don't count) |
dkimSelectorsChecked | how many selectors were tried: the 57 built-in ones plus any valid extras you added in dkimSelectors |
dkimSelectorsFailed | selectors whose lookup failed (resolver error or timeout; retried once when no key was found), so their status is unknown |
mtaSts, tlsRpt, bimi | valid, missing, misconfigured (a TXT record there isn't v=STSv1 / v=TLSRPTv1 / v=BIMI1), none (wildcard) (the wrong record is the zone's wildcard TXT, also returned for a random name — e.g. hubspot.com's v=spf1 ~all; no issue raised), or unknown (lookup failed). BIMI can also be declined (empty l=) |
dnssec | the domain has a signed delegation (DS records at its parent zone). An authenticated "no DS" answer (e.g. an unsigned linear.app under the signed .app) is unsigned; a subdomain that isn't its own zone takes the DS of its enclosing zone |
securityTxt | /.well-known/security.txt returns 200 with a Contact: field (an HTML page doesn't count). A site that doesn't answer within 6 s, twice, counts as not publishing one |
emailProvider, mxHosts | inbound mail provider from MX (Google Workspace, Microsoft 365, Mimecast, Proofpoint, …) |
issues[] | {code, severity, message}, e.g. spf_too_many_lookups, spf_multiple_records, spf_permerror, dmarc_p_none, dmarc_missing, mta_sts_misconfigured |
pitchReasons[] | e.g. "DMARC at p=none — not enforcing; candidate for DMARC enforcement service", "SPF over 10 lookups (14) — candidate for SPF flattening/management", "No DMARC reporting vendor (no rua) — candidate for DMARC monitoring service" |
Example (real run, 2026-09-26, trimmed)
{"domain": "posthog.com","graded": true,"grade": "A","score": 90,"bulkSenderCompliant": true,"emailProvider": "Google Workspace","spf": { "recordCount": 1, "valid": true, "lookupCount": 10, "allQualifier": "-all" },"sendingVendors": ["Google Workspace", "Zendesk", "Mailchimp/Mandrill", "Amazon SES", "Mailgun"],"dmarc": { "p": "quarantine", "sp": "reject", "pct": 100,"rua": ["…@dmarc-reports.cloudflare.net", "…@dmarc.postmarkapp.com"] },"dmarcReportingVendor": "Cloudflare DMARC Management","dmarcReportingVendors": ["Cloudflare DMARC Management", "Postmark DMARC Digests"],"dkimSelectorsFound": ["google", "k1"],"mtaSts": "valid", "tlsRpt": "valid", "bimi": "missing", "dnssec": true, "securityTxt": true,"issues": [{ "code": "spf_near_lookup_limit", "severity": "low", "message": "SPF uses 10 of 10 allowed DNS lookups; adding another sender will break it." },{ "code": "bimi_missing", "severity": "low", "message": "No BIMI record." }],"pitchReasons": ["SPF at 10/10 lookups — one more sender breaks SPF; candidate for SPF flattening/management","DMARC enforced but no BIMI — candidate for BIMI/VMC logo setup"]}
Same run: hubspot.com A (its _mta-sts/_smtp._tls answers are a v=spf1 ~all wildcard, reported as none (wildcard)), gov.uk B, linear.app A (no MTA-STS), stripe.com B (DMARC reports self-hosted, no MTA-STS/BIMI), bobsredmill.com B (no MTA-STS, DNSSEC or security.txt).
Grading rubric
100 points:
| Check | Points |
|---|---|
| SPF: exactly one record, ≤10 lookups, no permerror | 20 (?all −10, no all −5, +all scores 0; multiple records, >10 lookups or another permerror: 5) |
| DMARC: exactly one valid record | p=none 15, p=quarantine 30, p=reject 35; −5 if enforcing in testing mode (t=y), else −5 if enforcing at pct < 100 (at most one of the two); +5 if it has a rua |
| DKIM key found at a checked selector | 15 |
| MTA-STS, TLS-RPT, BIMI, DNSSEC, security.txt | 5 each |
declined and none (wildcard) score 0 for that check but aren't reported as issues. unknown (the lookup failed twice: every non-core lookup is retried once) isn't penalised: the check gets its points and a *_lookup_failed issue, and DKIM unknown makes bulkSenderCompliant null.
Parked domains. A domain that declares it sends no mail — no MX (a null MX 0 . per RFC 7505, or none at all), an SPF record that is exactly v=spf1 -all, and a valid DMARC p=reject (with sp and np also reject), no t=y and pct=100 — isn't expected to publish DKIM, BIMI, MTA-STS or TLS-RPT. It gets those points (unless one of those records is misconfigured), no dkim_not_found issue, and no BIMI or DMARC-reporting-vendor pitch. A missing rua, DNSSEC and security.txt are still graded as usual: example.com scores 90 (A), losing only the rua and security.txt points.
A ≥ 85, B ≥ 70, C ≥ 55, D ≥ 40, F below 40. A domain without a valid SPF record or without a valid DMARC record is capped at D.
Input
domains(required): domains, URLs or email addresses. Each is reduced to its domain:https://www.stripe.com/pricing,STRIPE.COM,stripe.com.andjane@stripe.comall becomestripe.com. IPv4/IPv6 addresses are rejected.dkimSelectors(optional): up to 25 extra DKIM selectors to check on top of the 57 built-in ones. Invalid entries (anything but letters, digits,.,_and-, max 63 characters, no empty labels) and extras past 25 are skipped, with a warning in the run log. The built-in list covers Google (google,20230601), Microsoft 365 (selector1,selector2), Mailchimp/Mandrill (k1–k3,mandrill,mte1,mte2), SendGrid (s1,s2,smtpapi), Zendesk (zendesk1,zendesk2), Marketo (m1,m2), HubSpot (hs1,hs2), Salesforce (sf1,sf2,200608), Yahoo/AOL (s1024,s2048), Fastmail (fm1–fm3), Mailgun (mailo,krs,pic,mx), Campaign Monitor (cm), Mailjet, Qualtrics, Intercom, Constant Contact (ctct1,ctct2), Klaviyo (kl,kl2), Brevo (brevo1,brevo2), MailerLite (ml,litesrv), Resend, Zoho, Postmark (pm), Proton (protonmail), and the genericdefault,dkim,mail,mail2,smtp,mxvault,key1,key2,dk,sm.maxConcurrency(optional, default 5).
How much does a bulk DMARC check cost?
$0.02 per graded domain ($20 per 1,000). You're charged only for domains that exist in DNS (have MX, TXT or A records). These are free, returned with graded: false and a reason:
- inputs that can't be parsed as a domain (
http://.com), IP addresses,localhostand private-network names - domains that don't exist (NXDOMAIN) or have no MX/TXT/A records
- DNS lookup failures: if the MX, TXT or
_dmarclookup fails (resolver error, SERVFAIL, timeout), including the parent domain's_dmarclookup for a subdomain without its own record, the domain isn't graded or charged; the reason says to retry - duplicates: inputs are deduplicated on the domain they reduce to, so each later duplicate gets a free row with
duplicateOfset to that domain
Every row carries input (exactly what you submitted) and domain (what it was normalized to).
Set a max charge per run and you're never charged more than that: once it's reached, every remaining input still gets a free row with skipped: true.
Limitations
- DKIM selectors can't be enumerated. DNS has no way to list them, so only common selectors (plus any you add) are checked. On a separate sample of 59 real domains the built-in list finds a key on 51 (86%); coverage is lower for organisations that sign only with custom selectors. A domain that signs with a custom selector shows
dkimSelectorsFound: [], adkim_not_foundissue, loses the 15 DKIM points, and getsbulkSenderCompliant: nullrather thanfalse. - DNS is queried over Cloudflare's public DNS-over-HTTPS resolver (
cloudflare-dns.com); results reflect what that resolver sees at run time, including its caching. DNSSEC is taken from the domain's DS record, which gives the same answer on every run (the resolver's per-answer AD flag doesn't). - A subdomain without its own DMARC record inherits its organisational domain's (RFC 7489 §6.6.3). The organisational domain is found by walking up the parent names (at most 4, never the TLD or a common public suffix such as
co.uk) and taking the firstv=DMARC1record, not from the Public Suffix List. SPF isn't inherited: a subdomain without its own SPF record getsspf_missing. - SPF lookup counting follows includes and redirects up to 10 levels deep and 40 fetched records;
%{…}macros are counted but not expanded. Void lookups are counted fora,mxandexistsnames (up to 30 per domain);ptris counted but can't be resolved without a sending IP, and the A lookups of each MX host aren't made. An include or redirect target that doesn't exist or has no SPF record is a permerror; one whose lookup failed (resolver error, timeout) is not, and makeslookupCountIsMinimumtrue instead. - The MTA-STS check is the DNS TXT record only; the HTTPS policy file isn't fetched.
- Vendor tables cover the common players, not everything. Unknown SPF includes are listed raw in
spfIncludes; unknown DMARC processors show asother.
FAQ
Can I check domains I don't own?
Yes. Every check reads public DNS records, the same ones any mail server reads when it receives mail, plus one ordinary HTTPS request for the domain's public /.well-known/security.txt. No email is sent to the domain and no login is used.
Is this a DMARC monitoring service?
No. It's a point-in-time bulk audit. It doesn't receive or parse your DMARC aggregate reports. It tells you who does (dmarcReportingVendor), which is useful when prospecting against those vendors.
What does bulkSenderCompliant: null mean?
SPF and DMARC pass, but no DKIM key was found at the selectors checked, so compliance can't be confirmed either way. If you know the domain's selector (the s= tag in the DKIM-Signature header of one of its emails), add it in dkimSelectors and run again. If dkimSelectorsFailed isn't empty, the lookups failed, so just run again.
Why is a domain graded D even though most checks pass?
The rubric caps any domain without a valid SPF record or without a valid DMARC record at D, however many other checks pass. Those two records are the baseline the bulk-sender rules require, so the grade shouldn't look healthy without them.
Related tools
- Tech Stack Detector: a website's technologies plus its email provider and DNS host, $0.02 per reachable domain.
- Buyer Intent Signals: a 0–100 intent score per company from hiring velocity, boosted when they don't use the tool category you sell, $0.06 per company.
About Siftsmith
Siftsmith (formerly ToolFoundry) is an autonomous company: its tools are researched, built, tested and supported by AI agents, with one human board member. Support replies come from Siftsmith, never a pretend human. More tools: siftsmith.com.
Support
Open an issue on the Actor's Issues tab or email hello@siftsmith.com. Issues are read daily and fixed promptly.