# Bulk Email Verifier — MX, Disposable & Typo Check (`lergassy/bulk-email-verifier`) Actor

\[$0.70/1K e-mails] Bulk email verifier for lead lists: syntax, live MX lookup, throwaway and role addresses, typo fixes, duplicate spellings, 0-100 score. Paste a list, a CSV or Google Sheet link, or another Actor's dataset. Domain-level check, no mail sent, no run fee.

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

## Pricing

from $0.49 / 1,000 e-mail checkeds

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/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

**Bulk Email Verifier** cleans a list of e-mail addresses before you send to it. Paste the addresses, link a CSV file or a Google Sheet, or point it at the dataset of another Actor, and every address comes back as **deliverable**, **risky**, **undeliverable** or **unknown** — with the reason, a 0–100 score, the mail host, **disposable**, **role** and **free-mailbox** flags, a **typo suggestion** (`gmial.com` → `gmail.com`) and a pointer when two spellings are the same mailbox. No API key, no login, no e-mail is ever sent. $0.70 per 1,000 addresses, no fee per run.

> This Actor is a focused entry point for the query "bulk email verifier". It runs the e-mail half of the same engine as **[Email Verifier & Phone Validator](https://apify.com/lergassy/email-phone-verifier)**, at the same price per row. Need phone numbers checked in the same run, or a company website found from a name? Use that one.

### What does Bulk Email Verifier check?

| Check | What you get | Why it matters |
|---|---|---|
| **Syntax** | `undeliverable` / `syntax` for malformed strings | Pasted junk never reaches your sending tool |
| **Domain exists** | `undeliverable` / `domain_not_found` | A domain that does not resolve is a guaranteed hard bounce |
| **Mail servers (live MX lookup)** | `deliverable` when the domain publishes mail servers, `domain_accepts_no_mail` when it does not | A domain with a working website but no mail server bounces every message |
| **Throwaway domains** | `emailIsDisposable`, from a list of about 8,700 services | Sign-up spam and burner addresses out of your CRM |
| **Role accounts** | `emailIsRole` for `info@`, `sales@`, `support@` … | Deliverable, but nobody's personal inbox |
| **Free mailboxes** | `emailIsFree` for Gmail, Yahoo, Outlook … | A B2B lead on a free mailbox is usually a sole trader |
| **Mail host** | `emailProvider` (google, microsoft, zoho, proofpoint, mimecast …) and `emailMxHost` | Tells you what filtering your message will face |
| **Typos** | `emailSuggestion` when the domain is one or two letters off a big provider | `sales@gmial.com` becomes a fixable contact instead of a bounce |
| **Duplicate spellings** | `emailNormalized` and `emailDuplicateOf` (`john.doe+news@gmail.com` = `johndoe@gmail.com`) | One person, one send |
| **Score** | `emailScore` 0–100 | Sort or cut a list at a threshold without reading five flags |

### What it does not do — read this before you buy

**It does not probe individual mailboxes.** Confirming that one specific mailbox exists needs an SMTP conversation on port 25, and Apify's cloud blocks outbound port 25. So `deliverable` here means *the address is well formed and its domain accepts mail* — not that a person is behind it. A made-up address on a real domain (`nobody-here-123@gmail.com`) comes back `deliverable`. Every row says this in `checkLevel: "domain_mx"`.

What that means in practice:

- It removes bounces caused by bad syntax, dead or mistyped domains, domains without mail servers and throwaway services, and it removes duplicate sends.
- It does **not** catch an old employee's mailbox on a live company domain, and it does not detect catch-all domains. If your list is old B2B data where people change jobs, a mailbox-level (SMTP) verifier will catch more — at a higher price per address.
- We have not measured the bounce rate of lists cleaned with this Actor, so we do not promise one. Judge it on your own first send.

Where port 25 is open, mailbox probes are not a guarantee either: Gmail and Microsoft 365 often accept any recipient at that stage and bounce later.

### How to verify a list of e-mails in bulk

1. Open the **Input** tab.
2. Paste addresses into **📧 E-mail addresses**, one per line — or give a public link in **📄 Or a link to a list** (a CSV or TXT file, or a Google Sheet shared as "anyone with the link can view"), or pick a dataset in **🔗 Or a dataset from another Actor**.
3. Optional: choose **🎯 Keep only** — for example **Clean list** returns only deliverable addresses with one spelling per mailbox, **Problems only** returns what to delete.
4. Press **Start**. One DNS answer per domain is reused for every address on it; in our test a list of 10,000 addresses on 2,500 domains finished in under a minute.
5. Export as CSV, JSON or Excel, or read the dataset through the API.

An empty API call works too: with no input the Actor checks an eight-address example list that shows every verdict once.

### ⬇️ Input

```json
{
  "emails": ["owner@acme.com", "info@gmail.com", "hello@mailinator.com", "sales@gmial.com"],
  "keep": "all"
}
```

From a file or a sheet:

```json
{
  "fileUrl": "https://docs.google.com/spreadsheets/d/<sheet-id>/edit#gid=0",
  "keep": "clean"
}
```

Every address found anywhere in the file is checked; the other columns of the file are not copied. To keep your own ids, pass objects through the API — extra fields ride along to the output row:

```json
{
  "emails": [{ "email": "jane@acme.com", "crmId": "A-1042" }]
}
```

After a lead scraper:

```json
{
  "inputDatasetId": "aBcD1234efGh5678",
  "emailField": "email, emails, contactEmail",
  "keep": "clean"
}
```

A field that holds a list of addresses (as many contact scrapers write it) is expanded, one row per address.

`keep` values: `all`, `clean`, `deliverable_email`, `person_email`, `business_email`, `unique`, `problems`.

### ⬆️ Output

One row per address.

```json
{
  "email": "sales@gmial.com",
  "type": "email",
  "emailStatus": "risky",
  "emailReason": "disposable_domain",
  "emailDomain": "gmial.com",
  "emailProvider": null,
  "emailMxHost": null,
  "emailIsRole": true,
  "emailIsFree": false,
  "emailIsDisposable": true,
  "emailSuggestion": "gmail.com",
  "emailNormalized": "sales@gmial.com",
  "emailHasTag": false,
  "emailScore": 5,
  "checkLevel": "domain_mx",
  "checkedAt": "2026-10-06T02:06:04.729Z"
}
```

| Verdict | Meaning | What to do |
|---|---|---|
| `deliverable` | Well formed, domain publishes mail servers, not a throwaway service | Keep |
| `risky` | Throwaway domain, likely typo, or the domain has no MX record and relies on its A record | Fix the typo or drop |
| `undeliverable` | Bad syntax, domain does not exist, or domain accepts no mail | Drop |
| `unknown` | The domain's name servers did not answer in time (retried once). In our 10,000-address test this was about 2% of rows, all on domains whose own DNS was broken | Re-run later — do not treat as bad |

Views in the Output tab: **Verified e-mails**, **Problems only**, **Duplicates**. A run summary (counts per verdict) is saved as `SUMMARY` in the key-value store.

### How much does it cost?

Pay per event: **$0.0007 per e-mail checked ($0.70 per 1,000)**, cheaper on Bronze, Silver and Gold Store plans. No fee per run, no proxy charge. Only the rows that come back are billed: with **🎯 Keep only** set to *Clean list*, the addresses filtered out cost nothing. Exact repeats in your input are removed before checking, and a file or dataset with no addresses costs nothing. The **Apify Free plan** ($5 monthly credit) covers about 7,000 addresses a month.

| List | Price |
|---|---|
| 1,000 e-mails | $0.70 |
| 10,000 e-mails | $7 |
| 100,000 e-mails | $70 |

### FAQ

**Does it send e-mails?** No. Nothing is sent and no mailbox is contacted, so your sending reputation is not touched.

**Is it a ZeroBounce or NeverBounce replacement?** For domain-level cleaning — dead domains, typos, throwaways, duplicates — yes, at a fraction of the price. For mailbox-level verification, no: see *What it does not do*.

**Can I run it from Make, Zapier, n8n or my own code?** Yes — through the Apify API or the Apify integrations. Run it after any scraper by passing its dataset id.

**Can I schedule it?** Yes, with Apify Schedules, for example to clean the leads a scraper collects every night.

**Is it legal?** It looks up public DNS records and compares the address against public lists; it does not access any mailbox. You remain responsible for how you use the addresses — follow GDPR, CAN-SPAM and the rules of your sending platform.

### Related

- [Email Verifier & Phone Validator](https://apify.com/lergassy/email-phone-verifier) — the same e-mail checks plus phone numbers (US, Canada, Caribbean) and company-website lookup in one run.

# Actor input Schema

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

Addresses to verify, one per line (a line with several addresses separated by commas also works). Each one is checked for syntax, throwaway and role addresses, typos and duplicate spellings, then the domain's mail servers are looked up live. Through the API you can also pass objects such as <code>{"email": "jane@acme.com", "id": 42}</code> — extra fields are copied to the output row.

## `fileUrl` (type: `string`):

Public link to a CSV or TXT file, or a Google Sheets link shared as "anyone with the link can view". Every e-mail address found anywhere in the file is verified; other columns are not copied. Combine with the field above if you like — repeats are removed.

## `inputDatasetId` (type: `string`):

Dataset of a previous run — the lead list you just scraped, for example. The addresses are read straight from it, so you never move data by hand.

## `keep` (type: `string`):

Filter the output instead of filtering rows yourself afterwards. Only the rows that come back are billed, so filtered-out addresses cost nothing.

## `emailField` (type: `string`):

Which field of the dataset holds the address. Several names can be listed, separated by commas — the first one present wins. A field that holds a list of addresses is expanded.

## `dnsCheck` (type: `boolean`):

Ask the domain's name servers whether it accepts mail. Turning this off leaves syntax and list checks only.

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

Safety cap on how many addresses one run will check.

## `concurrency` (type: `integer`):

How many domains to look up at once.

## `dnsTimeoutMs` (type: `integer`):

How long to wait for a name server before the address is returned as unknown rather than bad. A timeout is retried once with double the budget.

## Actor input object example

```json
{
  "emails": [
    "support@apify.com",
    "hello@stripe.com",
    "john.doe+news@gmail.com",
    "johndoe@gmail.com",
    "sales@gmial.com",
    "test@mailinator.com",
    "info@nonexistentdomain-xyz-99.com"
  ],
  "keep": "all",
  "emailField": "email, emails, contactEmail, emailAddress",
  "dnsCheck": true,
  "maxEmails": 50000,
  "concurrency": 20,
  "dnsTimeoutMs": 5000
}
```

# Actor output Schema

## `emails` (type: `string`):

One row per address: verdict (deliverable, risky, undeliverable, unknown) with the reason, a 0-100 score, mail host, role/free/throwaway flags, typo suggestion, normalized mailbox and a duplicate pointer.

## `runSummary` (type: `string`):

JSON summary of the run: how many addresses were checked and how many landed in each verdict.

# 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": [
        "support@apify.com",
        "hello@stripe.com",
        "john.doe+news@gmail.com",
        "johndoe@gmail.com",
        "sales@gmial.com",
        "test@mailinator.com",
        "info@nonexistentdomain-xyz-99.com"
    ],
    "emailField": "email, emails, contactEmail, emailAddress"
};

// Run the Actor and wait for it to finish
const run = await client.actor("lergassy/bulk-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": [
        "support@apify.com",
        "hello@stripe.com",
        "john.doe+news@gmail.com",
        "johndoe@gmail.com",
        "sales@gmial.com",
        "test@mailinator.com",
        "info@nonexistentdomain-xyz-99.com",
    ],
    "emailField": "email, emails, contactEmail, emailAddress",
}

# Run the Actor and wait for it to finish
run = client.actor("lergassy/bulk-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": [
    "support@apify.com",
    "hello@stripe.com",
    "john.doe+news@gmail.com",
    "johndoe@gmail.com",
    "sales@gmial.com",
    "test@mailinator.com",
    "info@nonexistentdomain-xyz-99.com"
  ],
  "emailField": "email, emails, contactEmail, emailAddress"
}' |
apify call lergassy/bulk-email-verifier --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,lergassy/bulk-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/ZZUHsUFRRGrvWkwnp/builds/xCSuNdkSa4Qm2mPoi/openapi.json
