Email Validator: Bulk Email Verification, MX, Disposable Check avatar

Email Validator: Bulk Email Verification, MX, Disposable Check

Pricing

$1.00 / 1,000 emails

Go to Apify Store
Email Validator: Bulk Email Verification, MX, Disposable Check

Email Validator: Bulk Email Verification, MX, Disposable Check

Returns a valid, risky or invalid verdict for each e-mail address, with syntax check, MX records, disposable domain and role account flags and typo suggestions (gmial.com to gmail.com). No SMTP probing, no mail sent.

Pricing

$1.00 / 1,000 emails

Rating

0.0

(0)

Developer

Viktor Wiberg

Viktor Wiberg

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

19 days ago

Last modified

Security

Limited permissions

Share

Bulk email verification for marketing, sign-up and lead lists. This email verifier checks a list of e-mail addresses and gives each one a verdict: valid, risky or invalid, with the reason in plain words. The actor checks the syntax, looks up the domain's MX records in DNS, flags disposable (throwaway) domains and role accounts such as info@ and support@, and suggests a fix for common domain typos such as gmial.com or hotmail.con. Each row also tells which mail service hosts the domain (Google Workspace, Microsoft 365, Zoho and others, read from the MX records) and whether it is a free mailbox provider such as Gmail or Hotmail, which is useful for lead enrichment and for separating company addresses from private ones.

No mail is sent and no connection is made to the recipient's mail server (no SMTP probing). That makes the actor fast, cheap and safe for your sending reputation, and it means it cannot tell whether a single mailbox exists. See "Good to know".

Use it to clean a list before a newsletter or campaign, to check sign-ups from a web form, or to validate the e-mail column from a lead scraper before it goes into your CRM. Addresses can be pasted, read from another Apify dataset or read from a CSV or text file at a public URL, and duplicates are checked and charged once.

Example from a real run

This is the input and the output of a run on the Apify platform on 11 October 2026 (run OhFbVjOP8wvNX4uxn). The addresses are examples, not real people. Nothing in the output is edited.

Input:

{
"emails": [
"kontakt@nightwave.se",
"firstname.lastname@outlook.com",
"Jane Doe <Jane.Doe@Gmial.com>",
"someone@hotmail.con",
"test@mailinator.com",
"info@example.com",
"name@nonexistent-domain-zzqx.se",
"not-an-address"
]
}

Output (four of the eight rows):

[
{
"email": "firstname.lastname@outlook.com",
"normalized": "firstname.lastname@outlook.com",
"isValidSyntax": true,
"domain": "outlook.com",
"hasMx": true,
"mxHosts": [
"outlook-com.olc.protection.outlook.com"
],
"isDisposable": false,
"isRoleAccount": false,
"suggestion": null,
"status": "valid",
"reason": "Valid syntax and the domain accepts e-mail (MX found).",
"mxProvider": "Microsoft 365",
"freeProvider": true,
"duplicateCount": 1
},
{
"email": "Jane Doe <Jane.Doe@Gmial.com>",
"normalized": "jane.doe@gmial.com",
"isValidSyntax": true,
"domain": "gmial.com",
"hasMx": false,
"mxHosts": [],
"isDisposable": true,
"isRoleAccount": false,
"suggestion": "jane.doe@gmail.com",
"status": "risky",
"reason": "Disposable (throwaway) e-mail domain; possible typo, did you mean jane.doe@gmail.com; no MX record, mail would go to the domain's A/AAAA host.",
"mxProvider": null,
"freeProvider": false,
"duplicateCount": 1
},
{
"email": "someone@hotmail.con",
"normalized": "someone@hotmail.con",
"isValidSyntax": true,
"domain": "hotmail.con",
"hasMx": false,
"mxHosts": [],
"isDisposable": false,
"isRoleAccount": false,
"suggestion": "someone@hotmail.com",
"status": "invalid",
"reason": "The domain does not exist. Did you mean someone@hotmail.com?",
"mxProvider": null,
"freeProvider": false,
"duplicateCount": 1
},
{
"email": "info@example.com",
"normalized": "info@example.com",
"isValidSyntax": true,
"domain": "example.com",
"hasMx": false,
"mxHosts": [],
"isDisposable": false,
"isRoleAccount": true,
"suggestion": null,
"status": "invalid",
"reason": "The domain publishes a null MX record: it accepts no e-mail.",
"mxProvider": null,
"freeProvider": false,
"duplicateCount": 1
}
]

The other rows: kontakt@nightwave.se was risky (role account, mxProvider Other because its MX hosts belong to a web host that is not on the provider list), test@mailinator.com was risky (disposable domain and role account), name@nonexistent-domain-zzqx.se was invalid (the domain does not exist) and not-an-address was invalid (missing @).

Input

FieldTypeDefaultDescription
emailsarrayfour examplesAddresses to check. Name <address> and mailto: links are accepted, and a pasted string with one address per line or separated by commas also works. Duplicates are checked and charged once.
datasetIdstringnoneAlso check the addresses in another Apify dataset, for example the output of a lead or contact scraper.
fileUrlstringnoneAlso check the addresses in a CSV or text file at a public URL, for example an export from a CRM or newsletter tool. See "Reading a file".
emailFieldstringemailField in the dataset, or column in the CSV file, that holds the address. A dataset field with a list of addresses also works.
onlyNewbooleanfalseCheck and charge only addresses that earlier runs have not checked. See "Monitoring and scheduling".

All sources are combined into one list before the check. Up to 100 000 unique addresses per run. A run with empty input checks four example addresses, which is handy for trying the actor from an AI agent or the Apify MCP server.

Reading a file

Give fileUrl a link that answers a plain GET request without login, for example a published Google Sheets CSV, a file in public cloud storage or a raw file on GitHub.

  • Text file: one address per line. A first line that is only email is treated as a header.
  • CSV: a header row with a column named email (also e-mail, mail, email address, or the name you give in emailField, upper or lower case). Comma, semicolon and tab separated files work, and quoted fields such as "Doe, Jane" are read correctly. A file with several columns and none of those names stops the run with a message that says so.
  • Gzip: .gz files are unpacked.
  • Up to 50 000 data rows and 50 MB per file. Rows after that are skipped, and the log says how many the file had.
{
"fileUrl": "https://example.com/exports/contacts.csv",
"emailField": "email"
}

Output

One row per unique address, in the order given.

FieldDescription
emailThe address exactly as you sent it
normalizedCleaned address: trimmed, without display name or mailto:, in lower case, with an international domain in its ASCII (punycode) form. null when the syntax is invalid
isValidSyntaxWhether the address follows the syntax of RFC 5321 and 5322 (dot-atom or quoted local part, UTF-8 local parts as in RFC 6531)
domainThe domain part, in ASCII form
hasMxtrue when the domain has MX records, false when it has none, null when the lookup failed or the syntax was invalid
mxHostsThe MX hosts, sorted by priority, at most five
mxProviderThe mail service behind the MX hosts: Google Workspace (also Gmail), Microsoft 365 (also Outlook.com and Hotmail), Zoho, Proton, Yahoo, iCloud, Mimecast, Proofpoint or Other. null when the domain has no MX hosts. When a filtering gateway such as Mimecast or Proofpoint is in front of the mailbox, the gateway is what is shown
freeProvidertrue when the domain is a free consumer mailbox provider (gmail.com, outlook.com, hotmail.*, live.*, yahoo.*, icloud.com, proton.me, gmx.*, mail.ru, yandex.* and others), so the address most likely belongs to a private person rather than a company
isDisposableThe domain, or a parent domain, is on the open list of disposable e-mail domains
isRoleAccountThe local part is a role address such as info, admin, support, sales, noreply, kontakt or kundtjanst (English and Nordic names, +tags ignored)
suggestionThe address with the likely intended domain when the domain looks like a typo of a large mailbox provider, for example gmial.com to gmail.com
statusvalid, risky or invalid
reasonWhy, in one sentence
duplicateCountHow many times the address occurred in the input, counted after normalization (Anna@Example.com and anna@example.com are the same address). The address is checked and charged once

How the status is set:

  • invalid: the syntax is wrong, the domain does not exist, the domain publishes a null MX (RFC 7505), or it has neither MX nor A/AAAA records.
  • risky: the address can receive mail, but something speaks against sending to it: a disposable domain, a likely typo, a role account, a domain without MX that would get mail on its A record, a quoted local part, an IP address as domain, or a DNS lookup that did not answer.
  • valid: correct syntax, the domain has MX records and none of the risks above apply.

Summary of the run

When the run is done, the record SUMMARY in the run's default key-value store holds the totals, and the run's status message says for example Done. 1 200 addresses, 1 050 valid. From the run above:

{
"total": 8,
"unique": 8,
"checked": 8,
"valid": 1,
"risky": 3,
"invalid": 4,
"byProvider": { "Other": 2, "Microsoft 365": 1, "None": 5 }
}

total counts every address read from all sources, unique the addresses after duplicates are removed, checked the rows delivered, and byProvider the delivered rows per mxProvider (None for rows without MX hosts).

Monitoring and scheduling

Set onlyNew to true when you run the actor again and again on a growing list, for example new sign-ups or the output of a daily scraper. The actor then remembers which addresses it has checked, in a named key-value store in your Apify account (nightwave-state-email-validator), and checks and charges only addresses it has not seen before. Only a one-way SHA-256 hash of each normalized address is stored, never the address itself. The first run checks everything.

The addresses and the dataset ID are not part of the remembered input, so the same state is used however the list grows. To start over, delete the record in the key-value store.

Example: check the e-mail column of a lead scraper's latest dataset every morning at 06:00. In Apify Console, open Schedules, create a schedule with the cron expression 0 6 * * * and add this actor with the input below.

{
"datasetId": "<the dataset ID or name>",
"emailField": "email",
"onlyNew": true
}

The same schedule through the Apify API:

curl -X POST "https://api.apify.com/v2/schedules?token=<YOUR_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"name": "daily-email-validation", "cronExpression": "0 6 * * *", "timezone": "Europe/Stockholm", "isEnabled": true, "isExclusive": true,
"actions": [{"type": "RUN_ACTOR", "actorId": "nightwave-owner~email-validator",
"runInput": {"contentType": "application/json; charset=utf-8", "body": "<the input above as a JSON string>"}}]}'

You can also start the actor from another actor's webhook, so new leads are validated as soon as the scraper finishes.

Good to know

  • No SMTP check. The actor never connects to the recipient's mail server, so it cannot tell whether anna@company.com is a real mailbox, only that company.com accepts mail. Services that probe mailboxes over SMTP can catch more dead addresses, but they are slower, are blocked or answered falsely by many providers (Gmail, Outlook and most catch-all servers), and risk getting the checking IP blacklisted. If you need mailbox-level certainty, combine this actor with a double opt-in.
  • Disposable list. About 9 200 domains from an open community list (see "Data source and license"), plus any subdomain of them. New throwaway services appear every week, so a domain that is not flagged can still be disposable.
  • Typo suggestions cover the large mailbox providers (Gmail, Outlook, Hotmail, Live, Yahoo, iCloud, AOL, Proton, GMX and the big Nordic ones). A suggestion is only made when the provider name is one or two letters off and the top-level domain is the same or an obvious typo of it, so a real domain such as live.de is never "corrected".
  • Lower case. normalized is in lower case. Strictly, the part before @ can be case-sensitive, but no large provider treats it that way.
  • DNS. Each domain is looked up once per run, with 20 lookups in parallel, a 4 second timeout and one retry. A lookup that fails gives risky with hasMx: null, never invalid.
  • Privacy. The output contains only what you sent in. The addresses are not written to the log, not stored anywhere outside your own run's dataset and not shared. With onlyNew only one-way hashes are kept. You are responsible for having a legal basis for the addresses you process (for example under GDPR).

Use cases

  • List cleaning: give the URL of an exported CSV, remove duplicates and invalid addresses before a campaign, to lower the bounce rate and protect your sender reputation.
  • Lead enrichment: see which mail service each company uses (mxProvider) and separate company addresses from free mailbox addresses (freeProvider) in a B2B lead list.
  • Validate sign-ups from a form and stop throwaway addresses from taking free trials.
  • Check the e-mail field of a lead or contact scraper's dataset before it is imported into a CRM.
  • Separate role addresses (info@, sales@) from personal ones in a B2B list.
  • Catch typing errors such as gmial.com and hotmail.con and ask the user to correct them.

FAQ

What does 1 000 addresses cost? 1 USD (0.001 USD per address, event email). Platform usage is included. A test run that checked 2 000 addresses across 315 domains took 4 seconds.

Is a valid address guaranteed to be delivered? No. It means the address is well formed and its domain accepts mail. The mailbox itself is not checked.

Can it read a CSV file? Yes. Put the file at a public URL and give it as fileUrl. The column named email is used, or the one you name in emailField.

Can it check addresses from another actor? Yes. Give datasetId and emailField, and the actor reads the addresses from that dataset.

Data source and license

The checks are the actor's own code: the syntax rules of RFC 5321, 5322 and 6531, DNS lookups of MX, A and AAAA records (RFC 5321 section 5.1 and RFC 7505), and a built-in list of role names and mailbox providers.

The disposable domain list is disposable_email_blocklist.conf from github.com/disposable-email-domains/disposable-email-domains, downloaded on 3 October 2026 (9 203 domains). Its license, read on 3 October 2026, is CC0 1.0 Universal: "You can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission." The list is bundled in the actor and updated with scripts/update-disposable-domains.sh.

Pricing

Pay per result: 0.001 USD per checked address (event email), which is 1 USD per 1 000. Duplicates in the input are checked and charged once, and with onlyNew addresses checked in earlier runs are not charged again. Platform usage is included, so you pay only per result.

Rows are delivered only after they have been charged. If you set a maximum cost per run (maxTotalChargeUsd), the run stops there and its status message says how many rows were delivered.

Contact

Built and maintained by Nightwave AB. Questions, bugs and feature requests: kontakt@nightwave.se

På svenska

Actorn kontrollerar en lista med e-postadresser och ger varje adress ett utlåtande: valid (giltig), risky (riskabel) eller invalid (ogiltig), med skälet i klartext.

  • Kontrollerna: syntax enligt RFC 5321, 5322 och 6531, MX-poster i DNS (med A/AAAA som reserv och null MX enligt RFC 7505), engångsdomäner, rollkonton (till exempel info@, kontakt@, kundtjanst@) och förslag när domänen ser ut som ett stavfel för en stor e-posttjänst (gmial.com till gmail.com).
  • Ingen e-post skickas och ingen anslutning görs till mottagarens e-postserver (ingen SMTP-sondering). Actorn kan därför inte avgöra om en enskild brevlåda finns, bara att domänen tar emot e-post.
  • Indata: en lista med adresser (emails), ett annat Apify-dataset (datasetId och emailField) och/eller en CSV- eller textfil på en offentlig adress (fileUrl, upp till 50 000 rader, även gzip). Upp till 100 000 unika adresser per körning. Dubbletter kontrolleras och debiteras en gång, och duplicateCount visar hur många gånger adressen fanns i indata.
  • Varje rad visar också vilken e-posttjänst domänen använder (mxProvider, till exempel Google Workspace eller Microsoft 365, utläst ur MX-posterna) och om domänen är en gratis e-posttjänst som Gmail eller Hotmail (freeProvider). En sammanfattning sparas som SUMMARY i körningens key-value store.
  • Med onlyNew: true kontrolleras och debiteras bara adresser som inte har kontrollerats förut. Bara en envägshash av varje adress sparas, aldrig adressen.
  • Utdata innehåller bara det du själv skickat in. Adresserna skrivs inte till loggen och sparas inte utanför din egen körnings dataset. Du ansvarar för att ha rättslig grund för de adresser du behandlar (till exempel enligt GDPR).
  • Listan över engångsdomäner kommer från disposable-email-domains på GitHub och är licensierad CC0 1.0 (fri att använda kommersiellt), hämtad 3 oktober 2026.
  • Pris: 0,001 USD per adress (1 USD per 1 000). Plattformsanvändningen ingår.
  • Kontakt: kontakt@nightwave.se