# Bulk Email Verifier: MX, Disposable & Typo Checker (`f0rty7even/email-verifier`) Actor

Verify a list of email addresses against DNS. Checks syntax, MX records, disposable and role accounts, detects the mail provider, and suggests a correction for mistyped domains like gmial.com. No SMTP probing, no bounces on your reputation.

- **URL**: https://apify.com/f0rty7even/email-verifier.md
- **Developed by:** [Michael Yousrie](https://apify.com/f0rty7even) (community)
- **Categories:** Lead generation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.40 / 1,000 emails

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Bulk Email Verifier: MX, Disposable and Typo Checker

Paste a list of email addresses. Get back a verdict for each one, plus the reason behind it.

Built for the job everyone actually has: a list of addresses of unknown quality, and a sending tool that will punish you for the bad ones. This tells you which rows will bounce, which are throwaway inboxes, which are shared role accounts, and which are one character away from being correct.

**$2 per 1,000 addresses.** No SMTP probing, so nothing here can damage your sending reputation.

***

### What you get for every address

| Field | Example | Notes |
|---|---|---|
| `deliverability` | `valid` | `valid`, `risky`, `invalid` or `unknown` |
| `reason` | `mx_record_present` | Why that verdict, in one machine-readable token |
| `isAcceptable` | `true` | One boolean: worth sending to or not |
| `hasMxRecord` | `true` | Whether the domain can receive mail at all |
| `mxProvider` | `Google Workspace` | Who runs their mail, from the MX records |
| `mxHosts` | `["aspmx.l.google.com"]` | The records themselves |
| `isDisposable` | `false` | Checked against 8,201 bundled throwaway domains |
| `isRoleAccount` | `true` | `info@`, `sales@`, `noreply@` and around 60 more |
| `isFreeProvider` | `false` | Gmail, Outlook, Yahoo and 70 others |
| `suggestedEmail` | `jane@gmail.com` | The correction, when the domain looks mistyped |
| `didYouMean` | `true` | Whether a correction was found |
| `hasValidSyntax` | `true` | RFC-shaped, before any lookup |

Export as JSON, JSONL, CSV or Excel, or pull it from the API.

***

### The four verdicts

| Verdict | What it means | What to do |
|---|---|---|
| `valid` | The domain has MX records and is not a throwaway | Send |
| `risky` | Deliverable, but a free mailbox, a disposable domain, or a domain with no MX and only an A record | Send with care, or segment it |
| `invalid` | Malformed, or the domain cannot receive mail at all | Remove |
| `unknown` | DNS did not answer in time | Re-run those rows. Never treated as valid |

`isAcceptable` collapses that into one boolean for filtering, and it answers the stricter question: is this worth sending to. It is false for `invalid`, false for `unknown`, false for disposable inboxes nobody reads, and **false for any address carrying a typo suggestion**, because a typo-squat domain like `gmial.com` really does have MX records. That is precisely what makes it a trap rather than a bounce.

***

### Catching the typo, not just the bounce

`jane@gmial.com` fails an MX check on most tools and gets reported as invalid. True, and useless: there is a real person one character away.

This checks the domain against the large mailbox providers and suggests a correction when it is a single edit or a swapped pair of letters away. Around 40 of the most common misspellings are named outright.

It stays quiet otherwise. Aggressively "correcting" a small company domain into Gmail is a much worse failure than saying nothing, so `gmbh.de`, `mail.co.uk` and `email.agency` are all left exactly as they are.

***

### What this does not do, and why

**There is no SMTP handshake.** Every "99% accurate" verifier works by opening a connection to the recipient's mail server and asking whether a mailbox exists. Done from shared infrastructure at any volume, that gets the source IPs onto blocklists, is rate limited into uselessness, and is treated by the receiving side as address harvesting.

So this tool proves what DNS can prove: the address is well formed, the domain exists, the domain can receive mail, and the domain is not a known throwaway. It does not prove that one specific mailbox exists behind a working domain.

That distinction matters, because in practice most of a bad list is dead domains, typos and throwaways, and all three are caught here. If you need mailbox-level confirmation on top, run this first to remove the obvious failures cheaply, then send the survivors to a paid SMTP verifier at ten times the price.

`unknown` is a real outcome and is never quietly upgraded to `valid`.

***

### Common uses

**Cleaning a list before an email campaign.** Filter on `isAcceptable` and your bounce rate drops before you ever hit send, which protects the domain reputation that decides whether the rest of your mail reaches the inbox.

**Validating signups.** Run new addresses through and use `suggestedEmail` to ask "did you mean jane@gmail.com?" instead of silently losing the account.

**Segmenting an outreach list.** `isRoleAccount` separates `info@` shared inboxes from named people, and `isFreeProvider` separates consumers from businesses. Those two usually want different messages.

**Firmographic enrichment.** `mxProvider` tells you whether a company runs Google Workspace, Microsoft 365, Zoho or something self-hosted. For anyone selling into an email or security stack, that is a qualifying signal on its own.

**De-risking a purchased list.** `isDisposable` plus `invalid` gives you a fast quality score on a list somebody sold you, before you load it anywhere.

***

### Pricing

**$0.002 per address, so $2 per 1,000.** One charge per address that produced a verdict.

Duplicates are removed before anything is charged, so the same address in your file three times costs you once. Blank and malformed rows are dropped at parse time.

For comparison, SMTP-based verifiers run around $8 per 1,000 at low volume. They do a different, deeper check. This one is for the pass that removes the obvious failures cheaply.

***

### Speed

Around 20 addresses at a time by default, and DNS answers are cached per domain for the whole run. A list of 10,000 addresses across 2,000 domains costs 2,000 lookups, not 10,000, so large files finish far faster than the row count suggests.

***

### Output example

```json
{
  "email": "jane@gmial.com",
  "localPart": "jane",
  "domain": "gmial.com",
  "deliverability": "invalid",
  "reason": "domain_cannot_receive_mail",
  "isAcceptable": false,
  "hasValidSyntax": true,
  "hasMxRecord": false,
  "mxHosts": [],
  "mxProvider": null,
  "isDisposable": false,
  "isRoleAccount": false,
  "isFreeProvider": false,
  "suggestedEmail": "jane@gmail.com",
  "didYouMean": true
}
```

***

### Frequently asked questions

**How do I check if an email address is valid without sending an email?**
Run it through here. DNS confirms the domain exists and can receive mail, and the syntax and disposable checks catch the rest. Nothing is sent to the address.

**Will this stop my emails bouncing?**
It removes the causes of most hard bounces: dead domains, malformed addresses and typo'd domains. It cannot tell you that a particular mailbox at a live domain was deleted last week, because nothing except sending can, short of an SMTP probe.

**Does it detect disposable and temporary email addresses?**
Yes, against a bundled list of 8,201 throwaway domains including Mailinator, Guerrilla Mail and 10 Minute Mail.

**Can it tell me if an address is a role account like info@ or sales@?**
Yes, `isRoleAccount`, matched against about 60 shared-inbox prefixes in several languages.

**What does `unknown` mean?**
DNS did not answer for that domain in time. It is not a verdict of good or bad. Re-run those rows.

**How is this different from ZeroBounce or NeverBounce?**
They perform an SMTP handshake and charge roughly $8 per 1,000 for it. This is a DNS-only pass at $2 per 1,000 that removes the obvious failures. Many people use both: this one first, theirs on what survives.

**Can I verify one address at a time through the API?**
Yes. The Actor takes one address as happily as a hundred thousand, and the API returns the verdict as JSON.

***

### Works well with

- [Website Lead Extractor](https://apify.com/f0rty7even/website-lead-extractor): turn company websites into a lead list of emails, phones and postal addresses, then verify them here
- [LLM-Ready Web Extractor](https://apify.com/f0rty7even/llm-web-extractor): any URL to clean Markdown or JSON
- [SEO Audit and Site Health Checker](https://apify.com/f0rty7even/seo-auditor): on-page SEO issues and a health score per page

***

### Notes

Only DNS is queried. No mail is sent, no mailbox is probed, and no address is stored or shared.

# Actor input Schema

## `emails` (type: `array`):

The addresses to check. Paste them one per line, comma separated, or drop in a whole spreadsheet column. Mail-header form like Jane Doe <jane@northwind.co> is understood too.

## `deduplicate` (type: `boolean`):

Verify each unique address once, ignoring case. Leave this on unless you need the output to line up row for row with your input file.

## `maxEmails` (type: `integer`):

Hard stop after this many addresses, as a safety net on large lists. Leave empty to verify everything you supplied.

## `maxConcurrency` (type: `integer`):

How many addresses to check at once. The default is fast enough for tens of thousands of rows and gentle on the DNS resolvers.

## Actor input object example

```json
{
  "emails": [
    "sales@northwind.co",
    "jane.doe@gmail.com"
  ],
  "deduplicate": true,
  "maxConcurrency": 20
}
```

# Actor output Schema

## `verifiedEmails` (type: `string`):

One row per address. Export as JSON, JSONL, CSV or Excel.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "emails": [
        "hello@apify.com",
        "jane@gmial.com",
        "x@mailinator.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("f0rty7even/email-verifier").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "emails": [
        "hello@apify.com",
        "jane@gmial.com",
        "x@mailinator.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("f0rty7even/email-verifier").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "emails": [
    "hello@apify.com",
    "jane@gmial.com",
    "x@mailinator.com"
  ]
}' |
apify call f0rty7even/email-verifier --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,f0rty7even/email-verifier"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/GKUjlP4jsxMohiAcd/builds/1N08ownEkkj7uzvIY/openapi.json
