Email Verifier — Bulk SMTP & MX Validation, Catch-all
Pricing
from $0.87 / 1,000 email-verifications
Email Verifier — Bulk SMTP & MX Validation, Catch-all
Verify email deliverability without sending mail. Syntax, MX lookup, SMTP probe, catch-all detection, disposable & role-account flags. Score 0-100 per email.
Pricing
from $0.87 / 1,000 email-verifications
Rating
0.0
(0)
Developer
Vitalii Bondarev
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
12 hours ago
Last modified
Categories
Share
Email Verifier — Bulk SMTP & MX Validation, Catch-all Detection
Verify email deliverability in bulk without ever sending a single message. Feed it a list of email addresses and get back a score, status, and detailed flags for each one — whether you're cleaning a B2B lead list, validating a signup form, or scrubbing a cold-outreach database before you burn your sender reputation.
What it does
The actor runs each email through six verification layers in sequence:
Layer 1 — Syntax
Validates the address against a strict RFC-compliant regex. Catches typos, missing
@ signs, double-dots, overly long local-parts, and other malformed addresses before
any network round-trip. Invalid syntax → undeliverable immediately.
Layer 2 — Disposable domain detection
Checks the email's domain against a bundled blocklist of ~300 known temporary/throwaway
mail providers: Mailinator, YOPmail, Guerrilla Mail, 10MinuteMail, Trashmail, and hundreds
more. Disposable emails are flagged with is_disposable: true. They may still be
syntactically valid and even have MX records — you decide whether to reject them.
Layer 3 — Role account detection
Identifies generic role-based addresses that are unlikely to belong to an individual:
info@, support@, admin@, noreply@, sales@, webmaster@, postmaster@,
abuse@, and ~40 more patterns. Role accounts are flagged is_role: true. They deliver
mail (often to a shared inbox), but bounce rates and engagement are typically low —
useful signal for lead scoring.
Layer 4 — MX lookup (DNS)
Queries the domain's DNS for MX records via dnspython. If no MX record exists, falls back
to an A-record check (some small domains skip MX). No MX + no A record → domain can't
receive mail → undeliverable. The highest-priority MX host is returned in mx_host.
Layer 5 — SMTP probe (no mail sent)
Connects to the top MX host on port 25 and runs:
HELO verify.example.comMAIL FROM: <verify@verify.example.com>RCPT TO: <the-email-being-checked>
The connection is closed immediately after reading the response code — no DATA command,
no message ever delivered. Response codes:
250→ mail server accepts the address →deliverable5xx→ permanent rejection →undeliverable4xx→ temporary failure / greylisting →risky
Layer 6 — Catch-all detection
After a 250 response, the actor sends a second RCPT to a randomly-generated
non-existent address on the same domain (e.g. xk7m2q9r4j@domain.com). If that
is also accepted, the domain is a catch-all — it accepts mail for any local-part
regardless of whether the mailbox exists. Catch-all addresses get is_catch_all: true
and status: risky because we can't confirm the specific mailbox exists.
Output fields
| Field | Type | Description |
|---|---|---|
email | string | Normalized (lowercased) email address |
status | string | deliverable / undeliverable / risky / unknown |
score | integer | Deliverability confidence 0–100 |
syntax_valid | boolean | Passes RFC syntax check |
is_disposable | boolean | Known throwaway/temp-mail domain |
is_role | boolean | Generic role address (info@, support@, …) |
mx_found | boolean | Domain has a working mail server |
mx_host | string | Highest-priority MX hostname |
smtp_code | integer | Raw SMTP response code (null if unreachable) |
smtp_message | string | Raw SMTP response message |
is_catch_all | boolean | Domain accepts mail for any address (null = unknown) |
checked_at | string | ISO 8601 UTC timestamp |
Status values
- deliverable — syntax OK, MX found, SMTP accepted the address, domain is not catch-all
- undeliverable — syntax invalid, no MX record, or SMTP permanently rejected the address
- risky — domain is catch-all (can't confirm the specific mailbox) OR SMTP returned 4xx (greylisting)
- unknown — SMTP unreachable (port-25 blocked or timeout) and domain is not a known big provider
Score (0–100)
| Score | Meaning |
|---|---|
| 100 | SMTP 250 + not catch-all → high confidence deliverable |
| 80 | Known provider (Gmail/Outlook/…), MX found, port-25 unreachable → heuristic |
| 60 | MX found, SMTP unreachable, unknown domain → can't confirm |
| 35–40 | Catch-all or greylisting → deliverable but risky |
| 0 | Syntax fail, no MX, or hard SMTP rejection |
Port-25 limitation (important)
Many cloud providers (AWS, GCP, Azure) block outbound TCP port 25 by default. Apify's cloud infrastructure may or may not have port-25 open depending on the instance type and region.
When port-25 is blocked, the actor handles it gracefully:
- The SMTP probe returns
smtp_code: nulland marks the connection as unreachable - For well-known providers (Gmail, Outlook, Yahoo, iCloud, Proton, etc.) the actor
falls back to a heuristic: if MX exists, status =
deliverableat score 80 - For all other domains: status =
unknownat score 60 - You can use
skipSmtp: trueto skip SMTP entirely and run MX-only mode
The syntax, disposable, role, and MX layers work correctly regardless of port-25 access.
On Apify infrastructure, port-25 availability may vary — test with skipSmtp: false
first; if you see many unknown results, the port is likely blocked on that instance.
Accuracy notes
- B2B domains: SMTP probes work well; most corporate mail servers respond reliably
- Gmail / Microsoft 365: Block SMTP probes from cloud IPs. The heuristic gives score 80
- Catch-all domains: Common in B2B (many companies accept all mail).
riskyis correct — the address format is valid but the mailbox may not exist - Greylisting: Some servers return
451on first contact and accept on retry. The actor marks theserisky(score 35); re-verify later or send anyway and watch bounce rates - False negatives: SMTP probing is not 100% reliable. Servers that accept
250may still bounce silently later. Combined with catch-all detection this is rare but possible - Rate limits: Running at high concurrency against one domain may trigger rate-limiting.
The default concurrency of 10 is conservative; reduce if you see many
risky4xx responses
Pricing
Pay-per-result: charged once per verified email (email-verification event).
You are only charged for emails that complete the verification pipeline — not for errors.
Example input
{"emails": ["cto@openai.com","noreply@github.com","throwaway@mailinator.com","test@nonexistent-xyz-domain.com","info@stripe.com"],"concurrency": 10,"smtpTimeoutSecs": 10,"skipSmtp": false}
Also accepts objects with an email key — useful when piping from a lead-gen actor:
{"emails": [{"email": "cto@openai.com", "name": "Sam Altman"},{"email": "info@stripe.com", "company": "Stripe"}]}