Email Deliverability Check — MX, Disposable & Role Detection avatar

Email Deliverability Check — MX, Disposable & Role Detection

Pricing

from $2.40 / 1,000 successful checks

Go to Apify Store
Email Deliverability Check — MX, Disposable & Role Detection

Email Deliverability Check — MX, Disposable & Role Detection

Check email deliverability risk without SMTP: MX/A record presence, SPF/DMARC/DKIM presence, disposable-domain detection, role-address flagging, and provider fingerprinting. smtpVerified is always false — no SMTP probe is made. Pay only for addresses with a real mail route.

Pricing

from $2.40 / 1,000 successful checks

Rating

0.0

(0)

Developer

Adrian Voss

Adrian Voss

Maintained by Community

Actor stats

1

Bookmarked

2

Total users

1

Monthly active users

2 days ago

Last modified

Share

You give this actor a list of email addresses. For each one it answers a narrower question than "is this mailbox real": does this domain accept mail, where does it go, and how well is it protected against spoofing? It resolves the domain's MX record (falling back to the A record per RFC 5321 §5.1), checks the domain against a community-maintained disposable/temp-mail blocklist, flags role-based local parts (info@, support@, noreply@, ...), fingerprints the mail provider (Google Workspace, Microsoft 365, Zoho Mail, and others) from the MX hosts, and reads its SPF, DMARC, and DKIM records. It never opens an SMTP connection — outbound port 25 is blocked on Apify's runtime, as on most cloud platforms, so no actor here can confirm a specific mailbox is live. Every row it returns says so explicitly: smtpVerified is always false.

Who it's for

The accountable_eel catalogue sells company intelligence columns for outbound. Each actor takes a list of domains or company identifiers and returns one flat, stably-named row per input — firmographics, registry IDs, tech stack, email route, hiring activity — the shape a Clay table, an n8n workflow, or an AI agent can consume without post-processing. Pricing is pay-per-event and per-domain: a few tenths of a cent for a row that was actually found, and nothing for a miss, so a list that doesn't enrich costs you next to nothing. Where an official source exists — VIES, GLEIF, SEC EDGAR, Brønnøysund, PRH, RDAP — it is queried directly instead of scraped. No seat licence, no monthly minimum, no credit system to decode. For email specifically: this actor answers "will mail sent here bounce immediately" — it does not and cannot answer "will this person read it."

Why this one

  • Confident misses. A domain with no MX and no A record can't receive mail at all — that's a clean found: false, not a guess, and it's never billed.
  • Honest about the SMTP boundary. smtpVerified is hardcoded false on every row. No catch-all guessing, no fabricated confidence score dressed up as a mailbox check.
  • Disposable-domain list refreshed every run. The 35k+-domain blocklist is fetched fresh at actor start, not bundled and going stale in the code.
  • Provider fingerprint as a free side effect. Knowing a domain runs Google Workspace or Microsoft 365 is a useful signal on its own, and it comes from the same MX lookup you're already paying for.
  • SPF, DMARC, and DKIM presence, not just MX. A domain can accept mail and still be trivial to spoof if it never set up sender authentication — this actor checks all three, honestly scoped (see FAQ for why DKIM's answer is "found under a common selector," not "definitely absent").
  • Pay only for a real mail route. Addresses whose domain can't receive mail cost nothing — you're billed for information, not for attempts.

What you get

One row per email address you submit. Every column below is a stable field name — safe to map into a Clay column or an n8n expression without it moving later.

FieldTypeDescription
querystringThe email address exactly as submitted.
foundbooleantrue if the domain has a mail route; false if it can't receive mail at all or the address isn't valid.
statusstringOK on a hit; NOT_FOUND or BAD_FORMAT on a miss.
emailstringThe email address (present on found rows).
domainstringThe domain portion of the address, e.g. apify.com.
hasMxRecordbooleantrue if the domain publishes an explicit MX record. false with found: true means it accepts mail only via its A record (RFC 5321 §5.1) — unusual, and flagged as risk.
mxHostsarray of stringsThe mail-exchanger hostnames from the MX record, e.g. ["aspmx.l.google.com"]. Empty when mail is accepted only via A record.
emailProviderstring or nullGoogle Workspace, Microsoft 365, Zoho Mail, Mailgun, SendGrid, Proton Mail, other, or null if no MX hosts matched any fingerprint.
isDisposableDomainbooleantrue if the domain appears on the community-maintained disposable/temp-mail blocklist.
isRoleAddressbooleantrue if the local part (before the @) matches a known role/generic pattern (admin, sales, support, noreply, and similar) rather than a named person.
riskLevelstringlow, medium, or high, derived from the flags above (see FAQ for how it's computed).
riskReasonsarray of stringsPlain-language reasons behind the risk level, e.g. ["role-based address, not an individual"]. Empty on a clean low-risk row.
smtpVerifiedbooleanAlways false. No SMTP connection is ever made — see the note at the top of this README and the FAQ.
hasSpfbooleantrue if the domain publishes an SPF record (a v=spf1 TXT record at the domain itself).
spfRecordstring or nullThe raw SPF record, e.g. v=spf1 include:_spf.google.com ~all. null when there isn't one.
hasDmarcbooleantrue if the domain publishes a DMARC record (a v=DMARC1 TXT record at _dmarc.<domain>).
dmarcRecordstring or nullThe raw DMARC record. null when there isn't one.
dmarcPolicystring or nullThe DMARC p= tag — none, quarantine, or reject — or null if there's no DMARC record to read one from.
dkimRecordFoundbooleantrue if a DKIM record turned up under one of the common selectors this actor checks (see FAQ — this is not proof of absence when false).
dkimSelectorstring or nullWhich selector matched (e.g. google, selector1), or null if none did.
dkimRecordstring or nullThe raw DKIM record at the matched selector. null if none matched.
dkimSelectorsCheckedarray of stringsThe exact selectors this row checked, so you can see what was and wasn't tried.
scrapedAtstring (ISO 8601)Timestamp the row was produced.

columns in the input lets you pick a subset of these if you only want a few fields back.

Price

$4 per 1,000 email addresses, plus a $0.005 start fee. Misses (found:false) are never charged.

That's $0.004 per found row at the FREE tier, dropping to $0.0024 on the GOLD tier. 1,000 email addresses through this actor: ~$4 if every one resolves to a domain that accepts mail, less for any that don't — a domain with no mail route at all is never billed. The same 1,000 rows through a credit-based enrichment platform: $80–$400. This actor isn't doing the same job as those platforms (see vs. alternatives below) — it's one narrow, cheap check, not a full verification pass.

How to use

  1. In the Apify Console. Open the actor page and click Start — the emails field is already pre-filled with a working example. Results land in the run's dataset as soon as each item is found.
  2. Via the API. Call it directly with a POST request — no Console needed once you have an API token:
    curl "https://api.apify.com/v2/acts/accountable_eel~email-deliverability-check/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
    -X POST \
    -H "Content-Type: application/json" \
    -d '{"emails":["press@apify.com"]}'
  3. On a schedule. Save this actor as an Apify Task with the input you want, then add a Schedule (hourly, daily, weekly) so it runs on its own — no server of your own required.
  1. Paste a list of email addresses into the emails field, one per line — or pass an array via the API.
  2. Turn on testRun the first time to check just the first 5 addresses before committing to a full list.
  3. Run it. Each address becomes one row: a mail-route check, a disposable/role/provider read, and an always-false smtpVerified flag so nothing downstream mistakes this for mailbox verification.
  4. Filter the output on riskLevel, isDisposableDomain, or isRoleAddress to decide what to drop from an outreach list, or feed emailProvider into a tech-stack signal.
  5. Turn on onlyFound if you only want rows that actually resolved — misses stay free either way, this just keeps them out of your dataset.

Input

{
"emails": [
"press@apify.com"
]
}

One email address per line. Accepted formats: name@example.com.

{
"emails": ["press@apify.com"],
"testRun": false,
"onlyFound": false,
"maxConcurrency": 5
}

emails is a list of addresses to check — one per line, e.g. name@example.com. Turn on testRun to check the first 5 before running the full list. onlyFound hides rows with no result (still free either way). includeKeywords / excludeKeywords filter by keyword, maxResults caps how many hits you pay for, and columns picks which fields come back.

Sample output

queryfoundstatusriskLevelriskReasonshasMxRecordmxHostsemailProviderisDisposableDomainisRoleAddresssmtpVerifiedhasSpfspfRecordhasDmarcdmarcRecorddmarcPolicydkimRecordFounddkimSelectordkimRecorddkimSelectorsCheckeddomainscrapedAt
press@apify.comtrueOKmedium["role-based address, not an individual"]true["aspmx.l.google.com","alt1.aspmx.l.google.com","alt2.aspmx.l.google.com","aspmx2.googlemail.com","aspmx3.googlemail.com"]Google Workspacefalsetruefalsetruev=spf1 a mx include:_spf.google.com include:mailgun.org include:amazonses.com -alltruev=DMARC1; p=reject; sp=reject; pct=100; rua=mailto:dmarc-reports@apify.com; ri=604800rejecttruegooglev=DKIM1;k=rsa;p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAh4GKb+ez/Nt/lchriJp1DM99haF3+gy3DN9R9n4O/9b1OBNYOQGCQ55rq18XM9YSFKmmOnEM9gT+d6i0CVfNPJJ2gV5C5if/owNUmf289GBkMbDo8z/7r/J+nMx3JGzQt1KRfqUb1J0pOU91Or61azqiTjeVkLijAOSqOcrRwhF8CUUmTDsk3u0ni/X8o5Vi4KIsY5prArYVfz3RK8eJzJKTEh5yAb//Bsl29nFnzDnxbjmBXrtd2EQB/Zr4Ec0lhXan+EOWM2X+/ZmbzvzjdrDQsKpkay37MrNTuTbuo7JFTr5FclwVOcthP8ig3/SdHRV+yBSbgbgcvkrFG5NqOwIDAQAB["google","selector1","selector2","k1","default","mail","s1"]apify.com2026-08-25T22:55:29.183Z

For example:

{
"query": "press@apify.com",
"found": true,
"status": "OK",
"email": "press@apify.com",
"domain": "apify.com",
"hasMxRecord": true,
"mxHosts": ["aspmx.l.google.com"],
"emailProvider": "Google Workspace",
"isDisposableDomain": false,
"isRoleAddress": true,
"riskLevel": "medium",
"riskReasons": ["role-based address, not an individual"],
"smtpVerified": false,
"scrapedAt": "2026-08-21T10:15:00.000Z"
}

A row with "found": false means the domain has no MX or A record at all and can't receive mail — these rows are never charged. smtpVerified is always false; this actor does not and cannot confirm an individual mailbox exists.

Use it from Clay, n8n, Make, or an AI agent

This actor runs synchronously over plain HTTP — call it directly from a script, a workflow tool, or an AI agent, no Apify Console needed once you have an API token.

curl "https://api.apify.com/v2/acts/accountable_eel~email-deliverability-check/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
-X POST \
-H "Content-Type: application/json" \
-d '{"emails":["press@apify.com"]}'

n8n. Add an HTTP Request node: Method POST, URL https://api.apify.com/v2/acts/accountable_eel~email-deliverability-check/run-sync-get-dataset-items?token=<YOUR_TOKEN>, Body Content Type JSON, JSON Body {"emails":["press@apify.com"]} (swap in an expression from an earlier node for a real value).

Clay. Add an "HTTP API" column: Method POST, URL https://api.apify.com/v2/acts/accountable_eel~email-deliverability-check/run-sync-get-dataset-items?token=<YOUR_TOKEN>, Body {"emails":["{{email address}}"]}, mapping the row's email address into the emails array.

MCP. In Claude, Cursor, or any MCP client with the Apify MCP server, ask for "Email Deliverability Check API | Apify" — the agent will find and run this actor.

Tips

  • Run riskLevel: "high" addresses (disposable domains) through a separate suppression list before a cold-outreach send — they're the addresses most likely to hurt sender reputation.
  • Don't treat isRoleAddress: true as a reason to drop a row outright — a role address still receives mail, it's just not a named person. Route it differently instead of discarding it.
  • Use emailProvider as a cheap tech-stack signal: a company on Google Workspace vs. Microsoft 365 tells you something about the rest of its stack before you spend a lookup on tech-stack-lookup.
  • Set maxConcurrency down if you're running this against a very large list and want to keep a lower profile against Cloudflare's DNS-over-HTTPS resolver, though it's a public endpoint built for this kind of volume.
  • Combine this with a real SMTP verifier: use this actor first to drop domains that can't receive mail at all, for free, then send only the survivors to a verifier that charges per check.
  • Use dmarcPolicy: "reject" or "quarantine" as a signal the domain actively enforces sender authentication — useful context when you're deciding how much to trust an outbound-looking reply-to on that domain. hasSpf/hasDmarc both false is the opposite signal: nothing stops someone from spoofing a "from" address on that domain.
  • Don't read dkimRecordFound: false as "this domain has no DKIM" — it means none of the common selectors this actor checks matched. See the FAQ for why DKIM can't be checked exhaustively.

vs. alternatives

What it costsWhat you getTrade-off
This actor (email-deliverability-check)$0.004 per found row (FREE tier, less on paid tiers), $0.005 actor start, nothing for a missOne row per email address: mail-route check (MX/A record), disposable-domain and role-address flags, and provider fingerprintNot mailbox-level verification — smtpVerified is always false. Use it to drop domains that can't receive mail at all before you pay a verifier for the rest.
ZeroBounce (and other verifiers)$0.004–$0.008 per emailReal mailbox-level verification — SMTP probes, catch-all detection, an actual deliverability scoreThis does not verify mailboxes and never claims to. Use it to drop domains that can't receive mail at all before you pay a verifier for the rest.
Clay$0.08–$0.40 per enriched row in credits, on top of a seatA whole enrichment workspace — waterfalls across dozens of providers, plus the table and the sequencing around itIf you want one place that does everything and you're not counting rows, that's Clay. This is one column, priced per column, callable from Clay via its HTTP step.
Doing it yourselfYour time + a DNS-over-HTTPS client, a disposable-domain list you keep current, and role-address heuristics you write and maintainThe same dataThis actor absorbs the blocklist refresh, the A-record fallback, and the retry/rate-limit handling — DIY means re-fetching and re-checking all of that yourself.

Prices for third-party tools are their published list prices as of August 2026 and are not tracked here — check the vendor before relying on the comparison.

FAQ

Is this the same as email verification? No. Email verification (ZeroBounce, NeverBounce, and similar tools) opens an SMTP connection and sends a RCPT TO command to check whether a specific mailbox accepts mail — that's the only way to actually confirm a mailbox exists. Cloud runtimes, including Apify's, block outbound SMTP (port 25) to prevent spam abuse, so no actor running here can do that. This actor checks whether the domain has a working mail route, whether it's a disposable/temp-mail domain, and whether the address looks role-based — useful, cheaper, and honestly narrower than mailbox verification. smtpVerified is always false so nothing downstream mistakes one for the other.

What counts as a miss, and am I charged for it? An address whose domain has no MX record and no A record — meaning it can't receive mail at all — or an address that doesn't match a valid email format. Both come back as found: false with a status explaining why, and neither is ever billed.

Why is a domain with an A record but no MX record flagged as risk? Per RFC 5321, a domain can accept mail at its A record even with no explicit MX record, but real production mail servers almost always publish MX records — an A-record-only setup is unusual enough to flag as medium risk, even though mail delivery is technically possible.

Does it detect catch-all domains? No. Detecting a catch-all requires an actual SMTP handshake, which this actor deliberately doesn't attempt — a heuristic guess at catch-all status without that handshake would be an unverifiable signal, so it's left out entirely.

How current is the disposable-domain list? It's fetched fresh from a community-maintained, MIT-licensed blocklist (35k+ domains) at the start of every run, not bundled into the actor's code and going stale between updates.

Does this need proxies or logins? No. It queries a public DNS-over-HTTPS resolver and a public blocklist file — no proxy configuration, no credentials, nothing to authenticate.

Is this GDPR-safe to run against a list of business contacts? This actor only reads public DNS records and a public domain blocklist — it doesn't store, scrape, or expose personal data beyond the email addresses you already hold and submit yourself. You remain responsible for how you sourced and use the list.

Can I run large lists, or schedule this to run regularly? Yes. Use maxConcurrency to control request rate, testRun to sanity-check a small sample first, and Apify's built-in Scheduler to re-run the check on a recurring basis — useful for re-validating a list before each outreach send rather than assuming it's still clean.

Can an AI agent call this directly? Yes — it's built for that. Any MCP client with the Apify MCP server can find and run this actor by name ("Email Deliverability Check API | Apify"), and columns lets the agent request only the fields it needs back.

What happens with a malformed address, like a missing @? It's classified BAD_FORMAT, comes back as found: false, and isn't charged. The row's status field tells you which of the two miss reasons applied — bad format or no mail route — so you can tell a typo apart from a domain that genuinely can't receive mail.

Will this slow down or rate-limit a large list? Each lookup is a lightweight DNS query against Cloudflare's public DNS-over-HTTPS resolver, not a page load — it's built to handle batches. maxConcurrency controls how many run in parallel; lower it if you'd rather trade speed for a gentler request rate.

How do SPF, DMARC, and DKIM checks work, and why is DKIM different? SPF and DMARC each live at one fixed, discoverable DNS name — the domain itself for SPF, _dmarc.<domain> for DMARC — so hasSpf/hasDmarc are definitive: the record either exists there or it doesn't. DKIM has no discoverable location at all: its record lives at <selector>._domainkey.<domain>, and the selector is chosen by whatever sends the domain's mail, with no DNS mechanism to enumerate it. This actor checks a short list of selectors real providers actually publish by default (Google Workspace, common ESP defaults, and a few generic ones — see dkimSelectorsChecked on every row) and reports which one matched, if any. dkimRecordFound: false means none of those specific selectors resolved — it is not proof the domain has no DKIM configured under a selector this actor didn't check.

Why does a domain with MX, SPF, and DMARC all present still show riskLevel: "medium"? Authentication presence and address risk are scored independently. A role-based address (info@, sales@) bumps risk to medium regardless of how well the domain authenticates its mail — check riskReasons for the specific reason(s) behind the level on any given row.

  • ../dns-record-lookup — raw MX, A, TXT, and other DNS records for a domain, if you need more than just the mail route.
  • ../company-domain-enrichment — firmographics, tech stack, and hiring signals for the same domains, in the same row shape.
  • ../domain-rdap-lookup — registration and ownership data (registrar, creation date, nameservers) straight from the domain's RDAP record.