Bulk Email Verifier & Validator – Mailbox-Level SMTP Check
Pricing
from $0.72 / 1,000 results
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
Maintained by CommunityActor stats
0
Bookmarked
5
Total users
4
Monthly active users
5 days ago
Last modified
Categories
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:
- Syntax. The address is trimmed, lowercased and parsed: one
@, a valid local part, real domain labels and an alphabetic top-level domain. A failure isinvalidwith reasonbad_syntax. - 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, anddisposable_servicenames the service when the mail server gave it away. - 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
undeliverablewith reasonno_mail_server. - Flags.
free_providermarks 92 consumer mail domains such as Gmail, Outlook and Yahoo.role_accountmarks 62 shared-mailbox prefixes such asinfo,sales,supportandbilling. Neither flag changes the verdict; a role address scores slightly lower. - 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 isriskywith reasoncatch_all_domain. - 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 TO | status | reason |
|---|---|---|
| 2xx | deliverable | mailbox_exists |
| 550, 551, 553, or 554 with 5.1.1 | undeliverable | mailbox_not_found |
| Any other 5xx | undeliverable | rejected_<code>, for example rejected_554 |
| 4xx (greylisting, temporary failure) | unknown | temporary_<code>, for example temporary_451 |
| No reply | unknown | no_smtp_answer |
| No connection to the server | unknown | mail_server_unreachable |
| The verification server could not run the check | unknown | probe_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
status | reason | score | What to do with it |
|---|---|---|---|
deliverable | mailbox_exists | 95, or 85 for a role address | Keep. |
valid | domain_accepts_mail | 70, or 65 for a role address | The domain takes mail but the mailbox was not asked, because the live check was off or unavailable. |
risky | catch_all_domain | 65 | The server accepts every address, so this one cannot be confirmed. Send in small volumes, or leave it out of cold campaigns. |
unknown | temporary_<code>, no_smtp_answer, mail_server_unreachable, probe_error | 50 to 55 | Run these addresses again later. |
undeliverable | mailbox_not_found, rejected_<code>, no_mail_server | 0 to 5 | Remove. |
disposable | disposable_domain | 5 | Remove from sales lists; refuse at signup. |
invalid | bad_syntax | 0 | Fix 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
undeliverableanddisposableaddresses first. - Lead-list cleaning. Lists built from websites, directories or a data vendor carry dead
mailboxes, typos and throwaway signups. Keep
deliverable, removeundeliverable,invalidanddisposable, and decide per campaign what to do withrisky. - CRM hygiene. Export contacts that have not been mailed for months, verify them, and mark
the
undeliverableones in the CRM by joining onemail. - Signup-form checks. Call it from your backend to refuse
invalidanddisposableaddresses and flagfree_providerones 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:
- Paste addresses into Email addresses, one per line, up to 50,000. Exact duplicates are removed before anything is checked.
- Leave Live mailbox check on. Turned off, every address that passes the domain checks
comes back
validrather thandeliverableorundeliverable. - Start the run. The Results view shows email, status, reason, score, role, free
provider, catch-all and mail server. Filter on
statusorscoreand 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}
| Field | Default | Allowed | What it does |
|---|---|---|---|
emails | required | 1 to 50,000 addresses | The list to check. Over 50,000, the first 50,000 are used. |
smtpCheck | true | true / false | Live mailbox check and catch-all test. |
concurrency | 20 | 1 to 50 | Addresses in progress at once. Never more than two connections per mail provider. |
timeoutSeconds | 10 | 3 to 30 | How 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"}
emailis what you sent andnormalizedis the trimmed, lowercased address that was checked. Join results back to your list onemail.catch_allandsmtp_codearenullwhen the mail server was not asked, for example with the live check off or the server unreachable.disposable_serviceappears 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
| Event | Price |
|---|---|
| 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.comandinfo@x.comare 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 produceunknown, and nothing is retried within a run. - Some mail servers refuse checks from servers they do not know. Those addresses come back
unknownorrejected_<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
- Google Maps Scraper & Email Extractor – Business Leads: Search terms and a city in, business records with website contacts out.
- Google Maps Scraper – Multi-City Lead Lists with Emails: Many categories across many cities in one deduplicated run.
- Google Maps Place Details Scraper – Bulk Place ID Lookup: Place IDs or place-page links in, full records out.
- Website Email Scraper – Contact Details, Socials & WhatsApp: Contact points from website URLs you supply.
- Website Content Crawler – Markdown for AI, Emails & Contacts: A whole site as Markdown, with its contact points.
- Company Enrichment API – Domain to Emails, Socials & Tech: A domain in, its contacts and technologies out.
- AI Crawler Checker – robots.txt Rules for GPTBot & ClaudeBot: Which AI crawlers a site's robots.txt allows.
- Schema Markup Validator & Generator – JSON-LD Checker: Checks and generates schema.org markup.