Email Domain Security Auditor: SPF, DKIM, DMARC, DNSSEC
Pricing
from $2.00 / 1,000 domain auditeds
Email Domain Security Auditor: SPF, DKIM, DMARC, DNSSEC
Bulk-audit domains for SPF, DMARC, DKIM, MX, MTA-STS, TLS-RPT, BIMI, DNSSEC and CAA. Each domain gets a 0-100 score, an A-F grade and fixes. Point-in-time check of public DNS records. Not a security audit, guarantee, or certification. Run only on domains you own or are authorized to assess.
Pricing
from $2.00 / 1,000 domain auditeds
Rating
0.0
(0)
Developer
Rowland
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
5 days ago
Last modified
Categories
Security
Limited permissionsShare
Email Domain Security Auditor
Audit hundreds of domains for SPF, DKIM, DMARC, MTA-STS, TLS-RPT, BIMI, DNSSEC, CAA and MX in one run, and get an A–F grade with plain-language fixes for every domain.
Point-in-time check of public DNS records. Not a security audit, guarantee, or certification. Run only on domains you own or are authorized to assess.
Do not use to identify domains for spoofing, phishing, or unsolicited email.
What does it do?
Paste a list of domains, URLs or email addresses. The Actor reads each domain's public DNS records, checks them against the email-authentication and DNS-security standards, and returns one row per domain with:
- a 0–100 score and an A–F grade,
- every issue found, ranked by severity (critical, high, medium, low, info),
- a specific fix for each issue,
- an
insurerReadyflag for the DMARC/SPF baseline that cyber-insurance and vendor-security questionnaires commonly ask about, with aninsurerReadyNoteon every row (no insurer has reviewed, endorsed or accepted this flag or the grade), - the parsed records behind every verdict, so you can check the evidence.
Export the results to CSV, Excel or JSON, or send them to a spreadsheet, CRM or ticketing tool with Apify integrations.
What it checks
| Check | What you learn |
|---|---|
| MX | Whether the domain receives mail, the detected mail provider, and Null MX (RFC 7505) on domains that send no mail |
| SPF | The parsed record and its all qualifier (-all, ~all, ?all, +all). DNS lookups are counted against the 10-lookup limit, with includes and redirects followed recursively. Also reports void lookups, broken includes, ptr use and duplicate records |
| DKIM | Probes 17 common selectors plus any you add, and reports key type, RSA key size, revoked keys and test mode. Wildcard DNS is detected, so it doesn't report false positives |
| DMARC | p, sp, pct, rua, ruf, adkim/aspf alignment, fallback to the organizational domain, tag errors, and whether third-party report addresses are authorized |
| MTA-STS | The _mta-sts TXT record, the HTTPS policy file (mode, max_age), and whether every MX host is covered by the policy |
| TLS-RPT | The _smtp._tls record and its report destination |
| BIMI | The default._bimi record, logo URL and whether a VMC/CMC certificate is present |
| DNSSEC | signed, unsigned, bogus (DS present but validation fails) or ds-present-not-validated |
| CAA | Which certificate authorities may issue certificates for the domain (inherited from parent domains), wildcard rules and iodef |
Grades and fixes
Every issue deducts points: critical −35, high −20, medium −10, low −4 (info costs nothing). Domains start at 100.
| Grade | Score | Typical meaning |
|---|---|---|
| A | 90–100 | Enforcing DMARC, a clean SPF record, only optional extras missing |
| B | 80–89 | Solid basics, with a few medium or low items to tidy up |
| C | 65–79 | Gaps that weaken spoofing protection or reporting |
| D | 50–64 | Significant weaknesses |
| F | below 50 | Spoofable, or broken records |
Each issue comes with a recommendation written for the person who edits the DNS. For example:
| Severity | Issue | Recommendation |
|---|---|---|
| medium | DMARC has no rua= address, so you get no aggregate reports about who sends as your domain. | Add rua=mailto:<reports address> to the record. |
| low | DNSSEC is not enabled, so DNS answers (including SPF/DMARC/MX) can be spoofed in transit. | Enable DNSSEC signing at your DNS host and add the DS record at your registrar. |
| low | DKIM selector "k1" uses a 1024-bit RSA key. | Rotate to a 2048-bit RSA key when convenient. |
insurerReady is true when DMARC is enforcing (quarantine or reject at pct=100), there is exactly one SPF record, and that record isn't +all. DKIM is reported separately (dkimSelectorsFound), because selectors can't be listed from DNS. Every row also carries:
insurerReadyNote: "Meets common cyber-insurer email-auth baselines (SPF, DKIM, DMARC enforcement); not reviewed or endorsed by any insurer"
The flag is a technical self-check against common questionnaire items. It is not an insurer's decision: no insurer has reviewed or endorsed this Actor, and none is bound to accept its grade or flag. Your insurer's own questionnaire and assessment always decide.
Who is it for?
- IT admins and security teams checking their own domains and brands before an audit, or after changing mail providers.
- MSPs and IT consultants reviewing many client domains at once and turning the
issueslist into tickets. - Anyone asked for email-authentication evidence: cyber-insurance applications, vendor security questionnaires, or proof that DMARC is enforced.
- Deliverability and marketing ops making sure SPF, DKIM and DMARC are aligned before a campaign.
How it works, and what it never does
- Public DNS only. It queries public DNS-over-HTTPS resolvers, with an automatic fallback resolver.
- At most one HTTPS GET per domain. It fetches the MTA-STS policy file, and only when the domain advertises one.
- Passive checks only. No port scans, no SMTP connections, no email sent, no subdomain brute-forcing.
- Polite by default. A global DNS rate limit (40 queries/second), a concurrency cap, a per-domain timeout, exponential backoff with jitter on rate limits (HTTP 429), SERVFAIL and timeouts, failover to the second public resolver, a hard stop if the resolvers keep refusing (it never rotates IPs or works around a provider's limits), and a cache for repeated lookups such as shared SPF includes.
- No personal data. Mailbox names in DNS records or in your input are redacted (
redacted@example.com). Only domain-level configuration is returned.
Input
| Field | Default | Notes |
|---|---|---|
domains (required) | – | Domains, URLs or email addresses. Inputs are normalized, lower-cased, IDN-converted and de-duplicated. www. is stripped by default |
dkimSelectors | [] | Your own DKIM selectors, probed in addition to the 17 common ones |
checkDkim | true | Turn off to save about 18 lookups per domain |
fetchMtaStsPolicy | true | Download and validate the MTA-STS policy file |
verifyExternalDmarcReports | true | Check authorization records for third-party rua/ruf domains |
resolver | doh-cloudflare | doh-cloudflare, doh-google or system |
concurrency | 10 | Domains audited in parallel (1–50) |
maxQueriesPerSecond | 40 | Global DNS rate limit (1–40; 40 is the hard maximum) |
domainTimeoutSecs | 60 | A slower domain is returned with status: "error" and is not charged |
stripWww | true | Audit example.com when you enter www.example.com |
maxDomains | 10000 | Safety cap per run |
Example input:
{"domains": ["example.com","https://www.example.org/contact","someone@example.net"],"dkimSelectors": ["mycustomselector"],"concurrency": 10}
Output
You get one dataset row per unique input. The Overview view shows the summary columns. The Issues and fixes view lists one row per issue. Full details for each check (parsed records, includes, selectors, policies) are in the nested objects mx, spf, dmarc, dkim, mtaSts, tlsRpt, bimi, dnssec and caa.
A real row from a test run on Apify, shortened:
{"domain": "example.com","status": "ok","score": 86,"grade": "B","insurerReady": true,"insurerReadyNote": "Meets common cyber-insurer email-auth baselines (SPF, DKIM, DMARC enforcement); not reviewed or endorsed by any insurer","summary": "Grade B (86/100): 1 medium, 1 low, 1 info","mxProvider": null,"spfAll": "-all","spfLookups": 0,"dmarcPolicy": "reject","dkimSelectorsFound": [],"mtaStsMode": null,"tlsRptPresent": false,"bimiPresent": false,"dnssecStatus": "signed","caaPresent": false,"issueCount": 2,"criticalCount": 0,"issues": [{"check": "dmarc","severity": "medium","issue": "DMARC has no rua= address, so you get no aggregate reports about who sends as your domain.","recommendation": "Add rua=mailto:<reports address> to the record."},{"check": "caa","severity": "low","issue": "No CAA record: any certificate authority may issue certificates for this domain.","recommendation": "Publish CAA records on example.com naming only the CAs you use, e.g. 0 issue \"letsencrypt.org\"."},{"check": "mx","severity": "info","issue": "Null MX published: the domain explicitly accepts no email.","recommendation": "Make sure SPF is \"v=spf1 -all\" and DMARC is p=reject so the domain cannot be spoofed."}],"spf": { "record": "v=spf1 -all", "allQualifier": "-all", "dnsLookups": 0, "lookupLimitExceeded": false },"dmarc": { "record": "v=DMARC1;p=reject;sp=reject;adkim=s;aspf=s", "policy": "reject", "subdomainPolicy": "reject", "pct": 100 },"dnssec": { "status": "signed", "dsPresent": true, "validated": true },"lookupErrors": [],"durationMs": 2477}
A domain that doesn't exist is returned as a free row:
{"domain": "this-domain-should-not-exist-zz91.com","status": "domain_not_found","score": null,"grade": null,"issues": []}
status values
| Status | Meaning | Charged? |
|---|---|---|
ok | Complete audit | Yes |
incomplete | Some DNS lookups failed, so the result may be partial | No |
domain_not_found | The domain doesn't exist (NXDOMAIN) | No |
invalid_input | The entry couldn't be read as a domain | No |
error | A timeout or unexpected failure | No |
A run summary is saved in the default key-value store under SUMMARY: counts by status, the grade distribution, the number of charged rows, and the DNS queries used.
Pricing
Pay per event: $0.003 per domain audited, which is $3 per 1,000 domains.
- You're charged only for complete rows (
status: "ok"). - Invalid entries, non-existent domains, timeouts and incomplete audits are free.
- Duplicates are removed before auditing, so you never pay twice for the same domain in one run.
- To cap spending, set Maximum cost per run in the run options. When the cap is reached, the Actor stops cleanly and the
SUMMARYrecord shows how many domains were skipped.
FAQ
Why does DKIM say "not found" when my domain signs mail?
DNS has no way to list DKIM selectors, so the Actor has to guess them. It probes 17 common ones. If your provider uses a custom selector, add it to dkimSelectors. You can find it as the s= value in the DKIM-Signature header of an email you sent. When _domainkey exists but no common selector matches, the Actor reports "custom selector likely" (low severity), not missing DKIM.
Why isn't my grade an A even though email works?
The grade measures protection against spoofing and downgrade attacks, not delivery. Missing optional protections such as MTA-STS, TLS-RPT or DNSSEC each cost a few points. The issues list explains every deduction and how to fix it.
Does it send email or connect to mail servers? No. It makes no SMTP connections and sends no messages. It reads public DNS and, at most, one public MTA-STS policy file per domain.
Can I check domains I don't own? Every check reads public records that any receiving mail server reads. Even so, run it only against domains you own or are authorized to assess.
Why is a result incomplete?
A DNS lookup failed after a retry, for example a SERVFAIL, a timeout or a broken DNSSEC chain. The row lists the failed lookups in lookupErrors and isn't charged. Re-run those domains later.
How fast is it? A domain needs roughly 25–35 DNS queries. At the default limit of 40 queries per second, 1,000 domains take about 15 minutes. The rate limit is the bottleneck by design, to stay polite to public resolvers.
Can I monitor my domains on a schedule?
Yes. Save your input as a task and schedule it. Compare score and issues between runs to catch regressions, such as a removed DMARC record or an SPF record that went over the lookup limit.
Is this legal or compliance advice? No. The results describe DNS configuration as seen at run time. Use them as technical evidence, not as a certification. This is a point-in-time check of public DNS records, not a security audit, guarantee, or certification.
How do I report a problem? Open an issue on this Actor's Issues tab with the domain and the row you got.
Limitations
- DKIM selectors are guessed. Only the 17 common selectors and the ones you supply are checked (see the FAQ).
- DNSSEC status comes from the public resolver. It's based on the validating resolver's AD flag; the Actor doesn't validate signatures itself. For subdomains, the status reflects that exact name.
- Organizational domain detection (used for DMARC fallback) relies on a built-in list of common multi-label suffixes such as
co.ukandcom.au, not the full Public Suffix List. - Point-in-time results. DNS is read as public resolvers see it at run time, so recent changes can take up to the record's TTL to show.
- MTA-STS checks the policy file once and doesn't follow redirects, as RFC 8461 requires.
- Spending cap: when the maximum cost per run is reached, audits already in progress are discarded and not charged.
Point-in-time check of public DNS records. Not a security audit, guarantee, or certification. Run only on domains you own or are authorized to assess.
Do not use to identify domains for spoofing, phishing, or unsolicited email.