Domain & Email Security Audit: SPF, DMARC, DKIM, SSL, DNS
Pricing
Pay per event + usage
Domain & Email Security Audit: SPF, DMARC, DKIM, SSL, DNS
Audit any domain's email and web security in seconds: SPF, DMARC, DKIM, DNSSEC, MTA-STS, BIMI, CAA, SSL certificate expiry and HTTP security headers. A-F grade plus prioritized fixes. Bulk lists or one domain at a time for AI agents.
Pricing
Pay per event + usage
Rating
0.0
(0)
Developer
Rod Services
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
0
Monthly active users
a day ago
Last modified
Categories
Share
What does Domain & Email Security Audit do?
Domain & Email Security Audit checks the email deliverability and web security setup of any domain in one to two seconds and gives it an A to F grade with a prioritized list of fixes. One run covers:
- Email authentication: SPF (with the 10 DNS lookup limit), DMARC policy, DKIM keys and key size, MTA-STS, TLS-RPT and BIMI.
- DNS: A, AAAA, MX, NS, TXT and CAA records, plus DNSSEC.
- Web security: SSL/TLS certificate (issuer, expiry, days left, SANs, TLS version, chain), HTTP security headers (HSTS, CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy) and the HTTP to HTTPS redirect.
- Optional: domain registration and expiry dates from RDAP.
It uses only public DNS, one TLS handshake and a few HTTP requests per domain. No API keys, no third-party paid services. Costs $1.50 per 1,000 domains.
Paste a list of domains for a bulk DMARC, SPF and SSL check, or call it one domain at a time as a real-time API from your app or AI agent. Run it on the Apify platform with API access, scheduling, integrations (Make, Zapier, n8n, Google Sheets, Slack, webhooks) and monitoring.
Try it now: press Start with the prefilled example (apify.com, github.com, google.com). It finishes in a few seconds.
Why use Domain & Email Security Audit?
- Email deliverability. Gmail and Yahoo require SPF, DKIM and DMARC for bulk senders. Find missing or broken records before your mail lands in spam.
- MSPs and IT consultants. Audit every client domain on a schedule. Get alerts when a certificate is about to expire or someone weakens DMARC.
- Security audits and pentest prep. Quick external posture check: spoofing risk, TLS hygiene, missing headers, no CAA, no DNSSEC.
- Lead qualification for security and email vendors. Grade thousands of prospect domains. Companies with DMARC p=none or no SPF are warm leads for your product.
- Vendor and supply-chain risk. Score the domains of your suppliers and partners.
- AI agents and LLM tools. A fast, predictable JSON endpoint. An agent asks "is example.com protected against email spoofing?" and gets findings with fixes it can explain.
How to check SPF, DMARC, DKIM and SSL for a list of domains
- Open the Input tab.
- Paste domains into Domains, one per line.
example.com,https://www.example.com/pageandjane@example.comall work. - Optional: add your own DKIM selectors. Common ones are always checked.
- Optional: untick checks you do not need.
- Press Start.
- Open the Output tab. Use the Overview, Email security, Web and TLS or Findings view. Download results as JSON, CSV, Excel or HTML, or fetch them by API.
Input
All fields are on the Input tab. Only domains must be filled. Without it the run returns one free help row.
| Field | Type | Default | Description |
|---|---|---|---|
domains | array of strings | Domains, URLs or email addresses. Duplicates and a leading www. are removed. IDN names are supported. | |
dkimSelectors | array of strings | [] | Extra DKIM selectors. Always checked: google, selector1, selector2, default, k1, s1, mail, dkim. |
checks | array of strings | all | Any of dns, spf, dmarc, dkim, dnssec, mtaSts, bimi, ssl, headers, redirect. Only these affect the grade. |
includeRdap | boolean | false | Add registrar and expiry dates from RDAP. Low volume only, 1 lookup per second, 500 per run. |
maxConcurrency | integer | 10 | Domains audited in parallel (1 to 50). |
timeoutSecs | integer | 10 | Timeout per TLS or HTTP connection (3 to 60). A whole domain is capped at 45 s. |
{"domains": ["apify.com", "github.com", "google.com"],"dkimSelectors": ["mandrill", "20230601"],"checks": ["spf", "dmarc", "dkim", "ssl", "headers"],"includeRdap": false,"maxConcurrency": 10}
Output
One item per domain. You can download the dataset in various formats such as JSON, HTML, CSV, or Excel. Shortened example:
{"domain": "github.com","grade": "A","score": 90,"summary": { "critical": 0, "high": 0, "medium": 0, "low": 5, "info": 4 },"spf": { "found": true, "all": "~all", "dnsLookups": 10, "voidLookups": 0 },"dmarc": { "found": true, "policy": "quarantine", "pct": 100, "rua": ["mailto:dmarc@github.com"] },"dkim": [{ "selector": "google", "keyType": "rsa", "keyBits": 2048 },{ "selector": "selector1", "keyType": "rsa", "keyBits": 1024 }],"dnssec": { "signed": false, "validated": false },"mtaSts": { "found": false, "tlsRpt": { "found": false } },"bimi": { "found": false },"ssl": {"issuer": "Sectigo Limited / Sectigo Public Server Authentication CA DV E36","validTo": "2026-11-29T23:59:59.000Z","daysLeft": 63,"protocol": "TLSv1.3","chainOk": true,"hostnameMatch": true},"headers": {"hsts": "max-age=31536000; includeSubdomains; preload","xFrameOptions": "deny","permissionsPolicy": null},"redirect": { "redirectsToHttps": true, "status": 301, "location": "https://github.com/" },"findings": [{"severity": "low","check": "spf","message": "SPF uses 10 of 10 allowed DNS lookups.","recommendation": "Leave headroom. Adding one more provider may break SPF."},{"severity": "low","check": "dmarc","message": "DMARC policy is p=quarantine.","recommendation": "Move to p=reject for full protection."},{"severity": "low","check": "dkim","message": "DKIM selectors \"selector1\", \"k1\" use a 1024-bit RSA key.","recommendation": "1024-bit keys still pass DKIM, but 2048-bit is recommended (RFC 8301). Rotate when convenient."}],"checkedAt": "2026-09-27T10:31:05.670Z","error": null}
Data fields
| Field | What it contains |
|---|---|
grade | A to F from score. See How the grade is calculated. |
score | 0 to 100. Starts at 100 and loses points per finding. |
dns | A, AAAA, MX, NS, TXT and CAA records (CAA inherited from parent names). nullMx marks "0 ." MX. |
spf | Record, parsed mechanisms, all qualifier, recursive DNS lookup count, void lookups, includes. |
dmarc | Record, policy, subdomain policy, pct, rua and ruf, alignment. Falls back to the parent domain. |
dkim | Keys found per selector with key type, RSA key size, test mode and revoked flag. |
dnssec | DS record present and resolver-validated (AD flag), via DNS-over-HTTPS. |
mtaSts | MTA-STS TXT record, fetched policy (mode, mx, max_age) and TLS-RPT record. |
bimi | BIMI record with logo and VMC URLs. |
ssl | Issuer, subject, validFrom, validTo, daysLeft, SANs, TLS protocol, cipher, chain and hostname check. |
headers | HSTS (max-age, includeSubDomains, preload), CSP, X-Frame-Options, and the other security headers. |
redirect | Whether http:// redirects to https://, with the redirect chain. |
rdap | Registrar, created, expires, daysToExpiry, status. Only when includeRdap is on. |
findings | severity, check, message and recommendation, worst first. |
error | Set when the domain could not be audited, for example it has no DNS records. Not charged. |
How the grade is calculated
Every domain starts at 100 points. Each finding subtracts points by severity:
| Severity | Points | Examples |
|---|---|---|
| critical | -30 | SPF +all, expired certificate, expired domain registration |
| high | -15 | no SPF, no DMARC, SPF over 10 lookups, certificate for the wrong name, cert expires soon |
| medium | -7 | DMARC p=none or partial quarantine, no DKIM key found, no HSTS, no HTTPS redirect |
| low | -2 | no CAA, no DNSSEC, no MTA-STS, missing CSP or nosniff, DMARC p=quarantine, 1024-bit DKIM |
| info | 0 | no BIMI, no Referrer-Policy, SPF ~all while DMARC enforces |
Low findings are hygiene items, so they count at most 6 points per check. Ten small header gaps never cost more than one missing HSTS header. High and critical findings are never capped.
| Score | Grade | Meaning |
|---|---|---|
| 90+ | A | Strong. Only hygiene items left. |
| 80-89 | B | Good. One real gap or several hygiene items. |
| 65-79 | C | Needs work. Usually a missing SPF, DMARC or HTTPS protection. |
| 50-64 | D | Weak. Several real gaps. Any critical finding also caps the grade at D. |
| < 50 | F | Spoofable or broken. Fix the high and critical findings first. |
Context rules keep the grade fair:
- A domain without MX, or with a null MX (
0 .), is treated as a non-mail domain. Missing DKIM, MTA-STS and BIMI are not penalised. SPF-alland DMARCp=rejectare still expected, because spoofing does not need an MX. - SPF
~allis only info when DMARC is atquarantineorrejectwithpct=100. That combination is common and safe. - Certificate expiry warnings scale with the certificate lifetime. A 6-day certificate with 4 days left is fine. A 90-day certificate is flagged below 14 days (high) and 30 days (medium).
- If TLS works but the homepage times out, the site most likely blocks data-center traffic. That is info, not a penalty.
Every finding has a recommendation, so the grade is always explained by the findings list.
Use it as an API for AI agents (Standby mode)
The Actor also runs as an always-ready HTTP API. Send one domain, get one JSON result back:
GET https://rod-analytics--domain-security-audit.apify.actor/?domain=example.comAuthorization: Bearer <YOUR_APIFY_TOKEN>
Optional query parameters: dkimSelectors=s1,s2, checks=spf,dmarc,ssl, includeRdap=true, timeoutSecs=10. url= works as an alias of domain=.
- 200 with a graded result: billed as one audited domain.
- 200 with
errorset (for example the domain has no DNS records): not billed. - 400 for an invalid domain, 402 when your maximum cost per run is reached. Not billed.
It works well as a tool in LangChain, CrewAI, n8n AI agents or any MCP client.
How much does a domain security audit cost?
Pricing is pay per event: $1.50 per 1,000 audited domains ($0.0015 per domain) plus a $0.001 start fee per run. Domains that fail (no DNS records, invalid names) are not charged. The prefilled 3-domain example costs under one cent. Platform usage is included. The Apify free plan's $5 monthly credit covers over 3,000 audits.
Set Maximum cost per run on the run options to cap spending. The Actor never charges past the limit. It stops cleanly and the status message says how many domains were skipped.
Tips and advanced options
- Find more DKIM keys. DKIM selectors cannot be listed from DNS. Open a received email, find
s=in itsDKIM-Signatureheader, and add it todkimSelectors. - Go faster. Turn off checks you do not need.
spfanddmarcalone take well under a second per domain. - Big lists. Raise
maxConcurrencyto 20 to 30. 1,000 domains take about 5 to 8 minutes at 256 MB. - Monitoring. Schedule a daily run and add a webhook or Slack integration. Alert on
ssl.daysLeft < 14or on a grade drop. - Subdomains. Enter
mail.example.comto audit it directly. DMARC falls back to the organizational domain like real receivers do.
FAQ, disclaimers and support
Is this legal? Yes. The Actor only reads public DNS records, performs a normal TLS handshake and fetches the homepage headers, the same things any mail server or browser does. It does not scan ports, brute-force anything or send email.
Why is RDAP off by default? Registries publish RDAP for occasional lookups. Verisign's RDAP terms of service (.com and .net) forbid high-volume automated queries. The option is limited to 1 request per second and 500 domains per run, and results are cached. Use it for small lists only.
Why does a site show HTTP 403? Some sites block data-center traffic with a bot-protection page. The header results then describe that page. The Actor adds an info finding when this happens.
Why did DKIM say "not found" when I sign my mail? Your provider uses a selector that is not in the common list. Add it to dkimSelectors.
What happens if my input is invalid? The run still ends SUCCEEDED and you pay only the small start fee. No domain is charged. The dataset gets one help row, and the run status message says the same:
{"error": true,"errorCode": "EMPTY_INPUT","message": "No domains in input.","howToFix": "Add at least one domain to \"domains\", e.g. [\"apify.com\"]. ..."}
EMPTY_INPUT means no domain was given. INVALID_INPUT means none of the entries is a public domain name (IP addresses, localhost and test TLDs are skipped). In a list that mixes good and bad entries, the good ones are audited and each bad one gets a free row with its error text.
Known limits. No SMTP connection to MX servers, no port scan, no blacklist lookup. The registrable-domain logic is a heuristic, so rare public suffixes may fall back incorrectly. IPv4 is used for all connections.
Found a bug or want another check? Open an issue on the Issues tab. Need a custom audit, white-label report or integration? Get in touch through the Actor page.