Bulk Email Verifier & Validator: MX, Disposable, $0.40/1k avatar

Bulk Email Verifier & Validator: MX, Disposable, $0.40/1k

Pricing

from $0.28 / 1,000 email validateds

Go to Apify Store
Bulk Email Verifier & Validator: MX, Disposable, $0.40/1k

Bulk Email Verifier & Validator: MX, Disposable, $0.40/1k

Bulk email verifier for lead lists: syntax, MX, disposable, role and typo flags, $0.40 per 1,000. No SMTP probing, no catch-all detection. Click Start: 5 prefilled emails run as is.

Pricing

from $0.28 / 1,000 email validateds

Rating

0.0

(0)

Developer

Penny Data

Penny Data

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

11 days ago

Last modified

Security

Limited permissions

Share

Email Validator: Syntax, MX, Disposable & Typo Check (Bulk, $0.40/1k)

Sample output

Real output from a run on 5 emails (syntax, MX, disposable and role checks, no SMTP):

inputvalidstatusscoreriskTypeMX records
bad@@examplefalseinvalid_syntax0invalid0
info@apify.comtruedeliverable_domain70role5
sales@stripe.comtruedeliverable_domain70role5
jane.doe@gmail.comtruedeliverable_domain85free5
test@mailinator.comfalsedisposable20disposable2

Try it: paste this into the Input tab and click Start.

{"emails": ["jane.doe@gmail.com", "info@apify.com", "test@mailinator.com", "bad@@example", "sales@stripe.com"]}

Try it in Apify Console: the form opens pre-filled with 5 sample addresses, so one click on Start gives you a result table. A new Apify account includes free monthly credit.

What you get from one click (default input)

Input: john.smith@gmail.com, founder@stripe.com, temp123@mailinator.com, jane.doe@gmial.com, not-an-email. Output rows (from a local code run of the validator, live DNS):

inputvalidstatusscoreriskTypehasMxdidYouMean
john.smith@gmail.comtruedeliverable_domain85freetrue
founder@stripe.comtruedeliverable_domain100nonetrue
temp123@mailinator.comfalsedisposable20disposabletrue
jane.doe@gmial.comfalsedisposable20disposablefalsejane.doe@gmail.com
not-an-emailfalseinvalid_syntax0invalidfalse

Email verifier and bulk email checker to validate an email list in one run: paste addresses, give a CSV or Google Sheets URL, or pass another Actor's dataset, and get one row per unique email with syntax, MX/DNS, disposable-domain, role-account and free-provider flags plus typo suggestions. It never opens an SMTP connection, so there are no blocked mail ports or per-mailbox timeouts, and it does not claim a mailbox exists. You pay only for rows that were checked; DNS failures are free.

Track record, stated plainly: a young Actor (12 runs so far, 2 users). The only 2 failed runs were on early builds on 2026-10-16; later builds, including the default-input run, succeed. Inputs saved with the field emailList, emails, email or csvFile run unchanged.

Free to try: a new Apify account includes free monthly platform credit, enough to validate a few dozen emails before you pay anything. No hidden minimums.

Features

  • Per-row status and run summary: every output row has rowStatus (ok, invalid or error) and rowReason, and each run saves a RUN_SUMMARY record in the key-value store with counts per status and rows billed. error rows (DNS failures) are never billed.

How to use Bulk Email Validator

  1. Open the Actor and paste addresses into emails, or set csvUrl to a public CSV or a Google Sheets link (shared as "Anyone with the link can view"; /edit links are converted to CSV export automatically, and the email column is auto-detected).
  2. Click Start. Duplicates are removed (case-insensitive) and validated once.
  3. Open the Output tab: the Human summary link (OUTPUT.md in the key-value store) shows valid / risky / invalid counts and the first 10 rows as a table. Or download JSON/CSV/Excel. The SUMMARY record shows counts by status.
  4. Re-run rows with status unknown (DNS failure) later; they were not charged.

Lead-list dedupe mode

Set dedupeMode to clean a lead list in the same run, before anything is billed:

  • exact (default): same address ignoring case.
  • normalized: also collapses name+tag@x.com to name@x.com and ignores dots in Gmail/Googlemail addresses.
  • perDomain: keep only the first address per domain (one contact per company).

Dropped duplicates are never validated or charged; RUN_SUMMARY reports duplicatesDropped.

{ "emails": ["a@x.com", "A@x.com", "j.doe+news@gmail.com", "jdoe@gmail.com"], "dedupeMode": "normalized" }

Pricing

Pay per event, no subscription and no compute fees on top. Price: $0.40 per 1,000 emails (FREE tier; volume tiers are cheaper).

EventWhen it is chargedPrice
email-validatedOne email address checked (syntax, DNS/MX, disposable, role, free-provider).$0.0004

Rows with status unknown (DNS lookup error) are not billed. Every other checked row is billed, including invalid_syntax and invalid_domain. Set the run's maximum cost in the run options to cap spend: the Actor stops when that limit is reached.

Example input

{
"emails": [
"jane@gmail.com",
"info@example.com",
"bob@mailinator.com",
"x@gmial.com",
"not-an-email"
]
}

Example output

Illustrative sample of the output shape (field names from the Actor; values shown for a disposable address).

{
"input": "bob@mailinator.com",
"email": "bob@mailinator.com",
"valid": false,
"score": 20,
"riskType": "disposable",
"status": "disposable",
"reason": "disposable_domain",
"domain": "mailinator.com",
"hasMx": true,
"isDisposable": true,
"isRole": false,
"isFreeProvider": false,
"didYouMean": null
}

Rows from a local code run of the Actor's validateEmail on the default Console input (live DNS, no SMTP; wiki record dated 2026-10-24; not an Apify platform run):

inputvalidstatusscoreriskTypehasMxdidYouMean
john.smith@gmail.comtruedeliverable_domain85freetrue
founder@stripe.comtruedeliverable_domain100nonetrue
temp123@mailinator.comfalsedisposable20disposabletrue
jane.doe@gmial.comfalsedisposable20disposablefalsejane.doe@gmail.com
not-an-emailfalseinvalid_syntax0invalidfalse

Run it from a terminal and get the rows back (replace YOUR_APIFY_TOKEN):

curl -s -X POST "https://api.apify.com/v2/acts/pennydata~bulk-email-validator-no-smtp/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"emails":["john.smith@gmail.com","founder@stripe.com","temp123@mailinator.com","jane.doe@gmial.com","not-an-email"]}'

Details and limits

Cleans an email list without contacting any mail server. For every address it checks:

CheckOutput field
Syntax (RFC 5321/5322-style, length limits, IDN domains converted to punycode)status = invalid_syntax, reason
Domain DNS: MX records, A/AAAA fallback, RFC 7505 null-MXhasMx, hasARecord, mxRecords
Disposable / throwaway domain (incl. subdomains of listed domains)isDisposable
Role account (info@, admin@, support@, noreply@ ...)isRole
Free mailbox provider (Gmail, Outlook, Yahoo, iCloud, Proton ...)isFreeProvider
Typo suggestion for common providers (gmial.com, hotmial.com, outlok.com)didYouMean

Score and risk type

Every row has score (0-100) and riskType (none, free, role, disposable, invalid, unknown), computed from the offline checks above:

  • invalid (bad syntax, no mail records, null MX, likely typo with no MX) scores 0; disposable scores 20.
  • Otherwise start at 100 and subtract 30 for a role account, 15 for a free provider, 10 for an A-record-only fallback (no MX), 15 when a typo fix is suggested. riskType is the first match of role, free, else none.
  • unknown (DNS lookup failed, not billed) has score: null. The score is a heuristic ranking, not a mailbox-exists guarantee.

Use it from Google Sheets

  1. In Google Sheets click Share, set "Anyone with the link" to Viewer, and copy the link (a File > Share > Publish to web link also works).
  2. Paste that link into csvUrl (add #gid=N for a tab other than the first). The email column is found automatically; set csvColumn to force one.
  3. Run. You get one validated row per unique address, merged with anything in emails; copy the results back into your sheet.

Read emails from another run's dataset

Set inputDatasetId to a dataset ID or name (for example a scraper's output) and emailField to the item field holding the email (default email). Results are merged with emails and csvUrl; if no row has that field the run fails with a clear message.

valid is true when the syntax is correct, the domain can receive mail (MX, or A/AAAA fallback) and it is not a disposable domain.

Validate leads from a Google Maps Scraper run

  1. Run a Google Maps scraper that outputs contact emails (for example compass/crawler-google-places with company contacts enabled) and copy the dataset ID of the run (Storage tab).
  2. Paste it into inputDatasetId here and leave emailField as email. The actor reads both the emails array and the email field of each place and validates every address.
  3. Each result row keeps the place's title, placeId, website and address when present, so you can join results back to the scrape. Keep rows where valid is true.

For phones from the same run use phone-number-validator-offline with the same dataset ID. This is checking syntax, domain and disposable/role status only, not whether a mailbox exists.

What this does NOT do (read before buying)

  • No SMTP probing. It cannot tell whether a specific mailbox (jane@company.com) exists. valid: true means "the address is well-formed and its domain accepts mail", not "the mailbox exists". Catch-all domains, full mailboxes and non-existent users on real domains pass.
  • Disposable detection is only as good as the open list (about 9 900 domains). New throwaway services are missed until the list is updated; the list in this version was fetched 2026-10-15.
  • The role and free-provider lists are short hand-curated lists, not exhaustive.
  • Typo suggestions cover about ten big providers only and are suggestions, not corrections.
  • DNS answers can change between runs (domains get new records); flags for a given domain are deterministic only while its DNS is.

Privacy

Only the emails you supply are processed. Nothing is stored beyond the run's dataset and summary (subject to your Apify retention settings). No third-party API is called; only DNS queries for the email domains are sent.

Data sources and licenses

Disposable domains: disposable-email-domains, CC0 1.0. See data/SOURCES.md.

More from PennyData

Works with: Shopify leads -> emails -> phones

Chain three PennyData actors to turn a list of store domains into checked contacts.

  1. Shopify Store Leads & Contacts takes {"domains": [{"url": "https://www.gymshark.com"}]} and returns rows with emails (array) and phones (array).
  2. This actor: copy the emails values into emails here, e.g. {"emails": ["press@gymshark.com", "support@gymshark.com"]}.
  3. Phone Number Validator (Offline) takes the phones values from step 1, e.g. {"phones": ["+44 20 7946 0958"], "defaultRegion": "US"}.

Each step is a separate run billed at its own pay-per-event price, so you only pay for the steps you use.

Switching from api-ninja/email-address-validator?

Both actors take a list of emails. This one adds CSV input and a row cap. Input mapping:

api-ninja/email-address-validatorbulk-email-validator-no-smtp
emails (array of strings)emails (array of strings), same shape
(none)csvUrl + csvColumn to read a public CSV, maxEmails to cap rows, concurrency

This actor checks syntax, MX/DNS, disposable domains, role accounts and typos without an SMTP mailbox probe, so it cannot confirm that a specific mailbox exists. If you need mailbox-level SMTP confirmation, it will not replace that. Output field names differ between the two actors, so map them from a small sample run before you switch a production job. Price here: $0.0004 per email checked ($0.40 per 1,000), see Pricing above and compare with the other actor's Pricing tab. Not affiliated with the other actor's author.

Drop-in alternative: accepts the same input fields

If you already have a saved input for another email validator, it runs here unchanged. Accepted input fields (aliases of the canonical emails): emailList, emailAddresses, emailAddress, email; CSV aliases: csvFile, csv, fileUrl. Each can be an array of strings, a newline/comma-separated string, or an array of { "email": "..." } objects. Extra keys such as timeout are ignored.

The input of fatihtahta/email-verifier-validator-pro is only emailList (read from its public schema on 2026-10-22). That actor's public Store stats on 2026-10-22: 1,199 users, and 38,010 of 50,777 runs in the last 30 days listed as failed. Your saved {"emailList": [...]} input works here with no edits. Output field names and checks differ: we do NOT do SMTP mailbox checks (syntax, MX/DNS, disposable, role, typo only), so run a small sample before switching a production job. Not affiliated with that author.

Migrating from easy-bulk-email-validator (xmiso_scrapers)?

The input is the same: { "emails": ["a@example.com", "b@example.org"] } runs here with no edits. The other actor's second input, timeout, is accepted and ignored here (there are no per-mailbox SMTP waits). Mapping below is from its public dataset view (build 0.0.14, read 2026-10-23; no runs were made on it). Their email_result and subresult values are not documented in that view, so those rows map by meaning only; run a small sample on both before switching a production job.

easy-bulk-email-validator outputHereNote
emailemail (normalised; original in input)duplicates removed before checking
email_resultvalid (true/false) and statusstatus is one of deliverable_domain, fallback_a_record, invalid_syntax, invalid_domain, disposable, unknown; rowStatus is ok, invalid or error
subresultreason (for example disposable_domain, dns_lookup_error)
email_qualityscore (0-100) and riskTypeheuristic from offline checks, not a mailbox verdict
free (Is_From_Free_Email_Provider)isFreeProvideralso isRole, isDisposable, hasMx, didYouMean

Pricing is pay per event: $0.0004 per email checked, no per-run start fee, DNS failures free (their listed price on 2026-10-21: $0.0025 per result plus $0.01 per run; check its Pricing tab, prices can change). This actor never opens an SMTP connection, so it cannot confirm that a specific mailbox exists; if you need mailbox-level confirmation it will not replace that. Not affiliated with the other actor's author.

Migrating from michael.g/email-verifier-validator?

Its published input schema (read 2026-10-21) takes emails, an array of strings, so a saved input runs here with no edits.

Field in your saved inputWhat this actor does
emails (array of strings; also accepts a newline/comma string)validated as-is

Listed price on 2026-10-21 (check each Pricing tab, prices can change): michael.g $0.001 per email, no start fee listed; this actor $0.0004 per email, no start fee.

We do NOT do SMTP mailbox checks: this actor checks syntax, MX/DNS, disposable domains, role accounts and typos, so it cannot confirm that a specific mailbox exists. Output field names differ, so check a small sample run before switching a production job. Not affiliated with the author.

Migrating from snipercoder/email-validator?

An input saved for snipercoder/email-validator runs here without edits. Accepted field names:

Field in your saved inputWhat this actor does
emails (array or newline/comma string)validated as-is
email (single string)validated as one address
csvFile (public CSV URL)read like csvUrl; uses the column whose header contains "email"

This actor checks syntax, MX/DNS, disposable domains, role accounts and typos without an SMTP mailbox probe, so it cannot confirm that a specific mailbox exists. Output field names differ, so check a small sample run before switching a production job. Rows whose DNS lookup fails are not billed. Not affiliated with the other actor's author.

FAQ

Can I verify a list of emails in bulk for free?
New Apify accounts include free monthly platform credit, so a small list costs nothing out of pocket; after that it is pay per event (see Pricing; it can change). Paste addresses into emails, or set csvUrl (and csvColumn) to a public CSV, and download one row per unique address.

{ "emails": ["jane@gmail.com", "info@example.com", "x@gmial.com"], "concurrency": 10 }

How do I check for disposable (temporary) email addresses?
Every row has isDisposable, matched against the open disposable-email-domains list (subdomains included), and valid is false with status: "disposable" for them. The list is only as current as its fetch date (2026-10-15), so brand-new throwaway services can be missed.

{ "emails": ["bob@mailinator.com", "temp123@mailinator.com"] }

Am I billed for rows that failed?
No for DNS failures: a row with status unknown (reason: dns_lookup_error) is written to the dataset but not charged, so re-run those later for free. Rows that were actually checked are charged, including addresses found invalid_syntax or invalid_domain, because the check ran. To cap spend, set the maximum cost per run in the run options; the Actor stops once that limit is reached. The SUMMARY record shows counts per status so you can compare it with your bill.

What does status unknown mean? Am I billed for it? Can I re-run it?
status: "unknown" (reason: dns_lookup_error) means the DNS lookup for the domain failed or timed out, so the Actor could not tell whether the domain accepts mail. It does not mean the address is bad. unknown rows are never billed. They are written to the dataset with no charge, so filter status = unknown and paste those addresses into a new run later. A re-run that again returns unknown is free again; if the lookup now works, the row is checked and charged as a normal row ($0.0004). The SUMMARY record shows how many rows ended up unknown.

What does it cost? Worked example.
$0.0004 per email checked (FREE tier price; volume tiers are cheaper), nothing else on top. 1,000 emails = $0.40. 25,000 emails = $10.00. Duplicates are removed before checking, so a repeated address is billed once.

How many emails per run?
maxEmails defaults to 10,000 and can be raised to 100,000 per run (the input field limit). It is a safety cap on unique addresses, not a hard product limit: extra addresses beyond it are ignored with a log warning, so raise it for bigger lists. For a CSV, set csvUrl (and csvColumn) instead of pasting.

Why no SMTP check?
SMTP probing (connecting to the mail server and asking whether the mailbox exists) gets sender IPs blocklisted, is blocked or faked by many providers (catch-all domains answer yes to everything) and is unreliable from cloud IPs. This Actor only does DNS lookups and list checks, which are fast, cheap and safe for your IP.

What does it NOT verify?
Whether a specific mailbox exists, is full, or will accept your mail. valid: true means the syntax is correct, the domain has MX (or an A/AAAA fallback) and it is not a known disposable domain. Catch-all domains, full mailboxes and non-existent users on real domains pass. Use it to clean obvious bad rows before sending, not as a guarantee of delivery.

Does it detect catch-all addresses or confirm a mailbox exists?
No. It never opens an SMTP connection, so it cannot detect catch-all domains, full mailboxes or non-existent users on real domains. valid: true means well-formed with a domain that accepts mail. That is also why it cannot get your IP blocklisted.

How do I flag role accounts, free providers and typos?
Use isRole (info@, admin@, support@ ...), isFreeProvider (Gmail, Outlook, Yahoo ...) and didYouMean (about ten big providers, e.g. gmial.com to gmail.com). Rows with unknown DNS status are not charged; re-run them later.

How do I clean a whole lead list, not just emails?
Find public business emails for store domains with Shopify Store Leads & Contacts, validate phone numbers with Phone Number Validator (Offline), and check the email domains with Bulk Domain WHOIS & DNS Lookup. You are responsible for a lawful basis (e.g. GDPR) to process the addresses you submit.

Need a custom field or a different source? Open an issue on the Actor page.

Built with AI assistance (Claude); maintained by the publisher.

Use from Claude Desktop / Cursor (MCP)

Apify's MCP server can expose this actor as a tool, so an AI agent can validate a list of emails from a plain-English prompt. Use this URL (?tools= takes a comma-separated list of actors, see the Apify MCP docs):

https://mcp.apify.com/?tools=pennydata/bulk-email-validator-no-smtp

Client config for Claude Desktop or Cursor (mcpServers format; sign in with OAuth when the client asks):

{"mcpServers": {"apify": {
"url": "https://mcp.apify.com/?tools=pennydata/bulk-email-validator-no-smtp"
}}}

Runs started by an agent are billed like any other run, at the prices above.

Other small pay-per-event Actors from the same publisher:

Feedback

If this actor saved you time, a short review on its Apify Store page helps others find it: https://apify.com/pennydata/bulk-email-validator-no-smtp