Bulk Email Verifier & Validator – Mailbox-Level SMTP Check avatar

Bulk Email Verifier & Validator – Mailbox-Level SMTP Check

Pricing

from $0.72 / 1,000 results

Go to Apify Store
Bulk Email Verifier & Validator – Mailbox-Level SMTP Check

Bulk Email Verifier & Validator – Mailbox-Level SMTP Check

Bulk email verifier and email validator for lead lists: syntax, MX, disposable and catch-all detection, role and free-provider flags, and a live mailbox check that never sends a message. A verdict, reason and 0-100 score for every address, up to 50,000 addresses per run.

Pricing

from $0.72 / 1,000 results

Rating

0.0

(0)

Developer

Locomint

Locomint

Maintained by Community

Actor stats

0

Bookmarked

5

Total users

4

Monthly active users

5 days ago

Last modified

Share

This bulk email verifier checks every address on a list without sending a message: syntax, mail server, disposable and free-provider lists, role mailboxes, catch-all domains and a live mailbox check. Each address comes back with a verdict, a reason and a 0-100 score, and a run takes up to 50,000 addresses.

What it does

Every address goes through the same checks, and the first one that settles it decides the verdict:

  1. Syntax. The address is trimmed, lowercased and parsed: one @, a valid local part, real domain labels and an alphabetic top-level domain. A failure is invalid with reason bad_syntax.
  2. Disposable services. The domain, and every parent domain, is checked against a list of 152 throwaway-mail domains. Throwaway services invent new domain names but keep their mail servers, so the domain's mail servers are also compared with those of six services (temp-mail.org, temp-mail.io, disposablemail.com, Mailinator, YOPmail and Guerrilla Mail). A match is disposable, and disposable_service names the service when the mail server gave it away.
  3. Mail server. The domain's MX records are looked up; with no MX record the A or AAAA record is used, as sending servers do. A domain that publishes a null MX, or no records at all, is undeliverable with reason no_mail_server.
  4. Flags. free_provider marks 92 consumer mail domains such as Gmail, Outlook and Yahoo. role_account marks 62 shared-mailbox prefixes such as info, sales, support and billing. Neither flag changes the verdict; a role address scores slightly lower.
  5. Catch-all test. Once per domain per run, the mail server is asked about an address that cannot exist (zz- followed by 14 random letters). A server that accepts it accepts everything, so every address on that domain is risky with reason catch_all_domain.
  6. Live mailbox check. The recipient's mail server is asked whether the mailbox exists, and its reply code decides the verdict.

How the mailbox check works without sending mail

The check is an ordinary SMTP conversation that stops before a message exists. The verifier connects to the domain's mail server on port 25, sends EHLO locomint.io, MAIL FROM:<verify@locomint.io> and RCPT TO:<the address>, reads the reply, and sends QUIT. It never sends DATA, the command that carries a message, so nothing is written to anyone's inbox. If the first mail server in the MX list does not answer, the second is tried.

Reply to RCPT TOstatusreason
2xxdeliverablemailbox_exists
550, 551, 553, or 554 with 5.1.1undeliverablemailbox_not_found
Any other 5xxundeliverablerejected_<code>, for example rejected_554
4xx (greylisting, temporary failure)unknowntemporary_<code>, for example temporary_451
No replyunknownno_smtp_answer
No connection to the serverunknownmail_server_unreachable
The verification server could not run the checkunknownprobe_error

No more than two connections are open to one mail provider at a time during a run, whatever the parallelism setting. Apify blocks outbound port 25, so on this platform the conversation runs through Locomint's own verification server: the actor sends it the mail-server name and the address, and gets back the reply code and message.

Verdicts and scores

statusreasonscoreWhat to do with it
deliverablemailbox_exists95, or 85 for a role addressKeep.
validdomain_accepts_mail70, or 65 for a role addressThe domain takes mail but the mailbox was not asked, because the live check was off or unavailable.
riskycatch_all_domain65The server accepts every address, so this one cannot be confirmed. Send in small volumes, or leave it out of cold campaigns.
unknowntemporary_<code>, no_smtp_answer, mail_server_unreachable, probe_error50 to 55Run these addresses again later.
undeliverablemailbox_not_found, rejected_<code>, no_mail_server0 to 5Remove.
disposabledisposable_domain5Remove from sales lists; refuse at signup.
invalidbad_syntax0Fix the typo or remove.

The score is a fixed value per outcome, as in the table, not a probability. Sort or filter on it when you want one number; read status and reason when you want to know why.

Who it is for

  • Cold-email teams cleaning a list before it goes into a sending tool. Hard bounces count against the sending domain, so remove undeliverable and disposable addresses first.
  • Lead-list cleaning. Lists built from websites, directories or a data vendor carry dead mailboxes, typos and throwaway signups. Keep deliverable, remove undeliverable, invalid and disposable, and decide per campaign what to do with risky.
  • CRM hygiene. Export contacts that have not been mailed for months, verify them, and mark the undeliverable ones in the CRM by joining on email.
  • Signup-form checks. Call it from your backend to refuse invalid and disposable addresses and flag free_provider ones on B2B trials. A run has its own start-up time, so check after the form is submitted rather than making the visitor wait.

How to use it

In the Apify Console:

  1. Paste addresses into Email addresses, one per line, up to 50,000. Exact duplicates are removed before anything is checked.
  2. Leave Live mailbox check on. Turned off, every address that passes the domain checks comes back valid rather than deliverable or undeliverable.
  3. Start the run. The Results view shows email, status, reason, score, role, free provider, catch-all and mail server. Filter on status or score and export CSV, Excel or JSON.

From the API, this call starts a run, waits for it and returns the rows:

curl -X POST \
"https://api.apify.com/v2/acts/locomint~bulk-email-verifier/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"emails": ["support@apify.com", "not an email"], "smtpCheck": true}'

The synchronous endpoint waits up to 300 seconds. For a large list, start the run with POST https://api.apify.com/v2/acts/locomint~bulk-email-verifier/runs?token=YOUR_APIFY_TOKEN and read its dataset when the run finishes. The official apify-client packages for Python and JavaScript do the same in a few lines.

Input example

{
"emails": [
"support@apify.com",
"no-such-mailbox-2931@apify.com",
"someone@mailinator.com",
"not an email"
],
"smtpCheck": true,
"concurrency": 20,
"timeoutSeconds": 10
}
FieldDefaultAllowedWhat it does
emailsrequired1 to 50,000 addressesThe list to check. Over 50,000, the first 50,000 are used.
smtpChecktruetrue / falseLive mailbox check and catch-all test.
concurrency201 to 50Addresses in progress at once. Never more than two connections per mail provider.
timeoutSeconds103 to 30How long to wait for DNS and for each mail-server reply. Raise it if slow servers produce many unknown rows.

Through the API, emails also accepts a single string with addresses separated by commas, semicolons, spaces or line breaks, or a list of { "email": "..." } objects.

Output example

One row per address. This is the shape of a confirmed role mailbox:

{
"email": "Sales@Acme-Supplies.example",
"normalized": "sales@acme-supplies.example",
"status": "deliverable",
"reason": "mailbox_exists",
"score": 85,
"syntax_valid": true,
"domain": "acme-supplies.example",
"mx_found": true,
"mx_host": "mx1.acme-supplies.example",
"disposable": false,
"free_provider": false,
"role_account": true,
"catch_all": false,
"smtp_checked": true,
"smtp_code": 250,
"verified_at": "2026-09-11T10:00:00+00:00"
}
  • email is what you sent and normalized is the trimmed, lowercased address that was checked. Join results back to your list on email.
  • catch_all and smtp_code are null when the mail server was not asked, for example with the live check off or the server unreachable.
  • disposable_service appears only on disposable rows identified by their mail server.
  • An address that hits an internal error still gets a row: status: "unknown", reason: "error", score: 0, and no other fields.

Pricing

EventPrice
Address checked (one dataset row)$0.0003, which is $0.30 per 1,000. From 26 September 2026 this becomes $0.0009, which is $0.90 per 1,000
Actor start$0.00005 per GB of run memory, charged once per run

A run uses 1 GB of memory unless you change it, so the start event costs $0.00005. Worked example: a 20,000-address lead list costs 20,000 x $0.0003 = $6.00, plus that $0.00005 for the start. A 10,000-address list is $3.00, which fits inside the $5 of monthly usage Apify's free plan gives without a card. A full 50,000-address run is $15.00.

Raising the memory in the run options is the only thing that changes the start charge - 2 GB makes it $0.0001, 4 GB $0.0002 - and it will not shorten a run that spends its time waiting for DNS and mail servers to answer. Use concurrency for that instead.

You pay only these event prices; Apify compute is not billed to you separately. Every address in the list produces one row and one charge, including addresses rejected for bad syntax and ones that come back unknown. If you set a maximum cost per run, the actor stops at the limit and nothing past it is delivered or charged.

FAQ

Does it send an email to check an address?

No. The conversation with the mail server ends with RCPT TO and QUIT, and the DATA command that would carry a message is never sent. The person behind the address receives nothing.

How does catch-all detection work?

Before asking about your address, the verifier asks the same server about a random address that cannot exist, once per domain per run. If the server accepts it, its answer for any address on that domain means nothing, so every address there is reported risky with catch_all: true and no further mailbox checks are made on that domain.

What counts as disposable?

A domain on the 152-entry list, a subdomain of one, or a domain whose mail servers belong to one of six known throwaway services. The list is deliberately conservative: a real company address wrongly marked disposable is a lost lead, so servers are matched by exact address or mail host name, never by a hosting provider's whole range.

Why does an address come back unknown?

The mail server gave no decisive answer: a 4xx reply (greylisting servers refuse the first attempt from a sender they have not seen before), no reply before the timeout, or no connection at all. Nothing is retried within a run. Put the unknown rows through a second run later; greylisting servers accept a sender that comes back after a delay.

What happens if the live check is unavailable?

If the verification server cannot be reached when the run starts, the run continues with the domain-level checks and says so in the log. Addresses whose domain accepts mail then come back valid / domain_accepts_mail (score 70) instead of deliverable or undeliverable. The same happens when you turn Live mailbox check off.

Can it check addresses with non-Latin characters?

Not as typed. The syntax check accepts ASCII local parts and domain labels, so an address with other characters comes back invalid. Convert an internationalised domain to its xn-- form first and it is checked normally.

Limits

  • 50,000 addresses per run. Only exact duplicates are removed, so Info@x.com and info@x.com are two rows and two charges.
  • Mailbox-level verdicts depend on Locomint's verification server, because Apify blocks port 25. If that server is unreachable at the start of a run, the whole run is domain-level (valid), not mailbox-level.
  • Catch-all domains stay risky, since no SMTP check can confirm one mailbox on them. Greylisting and slow servers produce unknown, and nothing is retried within a run.
  • Some mail servers refuse checks from servers they do not know. Those addresses come back unknown or rejected_<code> even when the mailbox exists.
  • Disposable detection is list-based. A brand-new throwaway service on new servers passes until it is added.

Privacy: nothing is stored and no email is sent

Your list is held in memory for the length of the run, and the results are written only to the run's dataset in your Apify account. When a mailbox check goes through Locomint's verification server, that server receives the mail-server name and the one address being checked, holds the SMTP conversation, returns the reply code and does not record the address. No message is sent to any address at any point.

Other Locomint actors