# Disposable Email Validator — Bulk Email Checker (`cleandata-tools/disposable-email-validator`) Actor

Bulk email validator and disposable email checker. Syntax, MX, disposable domains, free providers, role accounts, and typo suggestions for up to 100,000 addresses. No SMTP mailbox probing.

- **URL**: https://apify.com/cleandata-tools/disposable-email-validator.md
- **Developed by:** [CleanData Tools](https://apify.com/cleandata-tools) (community)
- **Categories:** Lead generation, Developer tools
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.49 / 1,000 email validateds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## Disposable Email Validator — bulk email checker

Bulk **email validator** and **disposable email checker** for list cleaning. Check syntax, MX mail routing, disposable domains, free email providers, role accounts, and typo suggestions for up to 100,000 addresses in one run.

Use it for **bulk email validation** before a campaign or a signup import. It is an **email verification** check of the domain and the address shape. It does not open an SMTP session and does not tell you whether a specific mailbox exists.

### What you get for each address

| Field | Meaning |
| --- | --- |
| `valid_syntax` | Practical address syntax. Quoted local-parts and IP domains are rejected. |
| `has_mx` | The domain publishes MX records, or it has no MX but an A/AAAA record (implicit MX). `true` means the domain can receive mail, not that the local part is real. |
| `mx` / `mx_hosts` | Mail exchangers and priorities. |
| `disposable` | The domain is on a disposable-email blocklist (tens of thousands of domains). |
| `free_provider` | Consumer webmail or a major residential ISP, such as Gmail. Not a reason to block. |
| `role_account` | Shared local part such as `admin`, `info`, or `noreply`. |
| `typo_suggestion` | A popular provider one edit away, such as `gmial.com` → `gmail.com`. |
| `risk` | `low`, `medium`, or `high`. |
| `reason` | Highest-severity signal. Other flags can still be true. |
| `block` | Silent-reject recommendation. True for unusable syntax, disposable domains, subdomains of disposable domains, and domains with no mail routing. False for free providers, role accounts, typos that still resolve, and DNS failures. |

Failed Worker calls are saved with `worker_error` and are **not** charged.

### Why the results are fast

Addresses are sent in batches of 50, with several batches in flight. DNS lookups for the same domain are deduped by the checker. Default memory is 256 MB, which is enough for a 100,000-address list because results are written as they finish instead of being held in memory.

### Input

| Field | Default | What to put |
| --- | --- | --- |
| Email addresses | Prefill sample of four addresses | Up to 100,000 strings. Duplicates are kept so each row gets a result. |
| Dataset or CSV URL | Empty | CSV, JSON, JSON lines, or an Apify dataset items URL. A column or field named `email` is used. Otherwise the first CSV column is used. Private Apify datasets use the token of this run. |
| Concurrent batches | 8 | 1–20 batches of 50 in flight. |
| Retries per batch | 4 | Extra attempts after a timeout, HTTP 429, or HTTP 5xx, with exponential backoff. HTTP 400 and 401 are not retried. |

Inline addresses and the file are combined, in that order, and the total still cannot exceed 100,000.

Dataset URL shape:

```text
https://api.apify.com/v2/datasets/DATASET_ID/items?format=json&clean=true&fields=email
```

Example input:

```json
{
  "emails": ["ada@gmail.com", "a@mailinator.com", "not-an-email", "info@gmial.com"],
  "concurrency": 8
}
```

### Output

The default dataset has one item per address. The **Overview** table shows the cleaning decision. **Mail routing** shows MX hosts. Sort by `index` to restore input order. A run summary is stored as the `OUTPUT` record in the key-value store.

`block: true` is still a successful check. Only a transport or Worker failure sets `worker_error`.

### Pricing

Pay per event. You pay for each address that comes back checked, not for platform compute, and not for addresses the Worker never returned.

| Event name | What it is | Price to set in Console |
| --- | --- | --- |
| `email-validated` | One address checked | **$0.00049** |
| `apify-actor-start` | Platform start event. Do not charge this from the Actor. | Leave the default **$0.00005** |

10,000 addresses are **$4.90**. 100,000 are **$49**.

That price sits under [bounceverify/bounceverify-email-verifier](https://apify.com/bounceverify/bounceverify-email-verifier) at **$0.00089 per verified email**. Bounceverify is a mailbox verifier. This Actor is a disposable email checker plus MX, syntax, free-provider, role, and typo signals, and it does not probe mailboxes. The lower price matches that smaller check. Copy the numbers from `.actor/pay_per_event.json` into the Actor's Monetization tab. The dollar amount is not hard-coded in the source.

Set the minimum run budget (`minimalMaxTotalChargeUsd`) to **$0.001** so a run can pay for the start event and at least one address. The Actor stops cleanly when your run hits its maximum charge: the last billed address is saved, and the rest are skipped rather than written for free.

### Honest limits

- **No SMTP mailbox probing.** `has_mx: true` does not mean the inbox exists. Gmail, Outlook, and most large providers accept the recipient domain and then bounce or drop unknown users. `mailbox_verification` on the checker is always false.
- A typo suggestion is a hint. Show it even when `block` is true. A typo of a provider that still has working mail routing is not, by itself, a silent reject.
- DNS failures are not treated as a block. Retry those addresses later.
- The disposable list is a snapshot of public blocklists, not a guarantee that a brand-new throwaway domain is already listed.
- One run accepts at most 100,000 addresses. Split larger files.
- A source file larger than 20 MB is refused.

### Operator setup

Set these Actor environment variables only after the checker expects a shared secret. Leave both unset until then. Set both, or neither.

| Variable | Example |
| --- | --- |
| `WORKER_AUTH_HEADER` | `X-Origin-Secret` |
| `WORKER_AUTH_VALUE` | the shared secret |

The header is sent on every checker call and is never written to the dataset or the log.

### Local run

```bash
npm install
npm test
mkdir -p storage/key_value_stores/default
printf '%s\n' '{"emails":["ada@gmail.com","a@mailinator.com","not-an-email","info@gmial.com"]}' > storage/key_value_stores/default/INPUT.json
npm start
```

`npm start` sets `ACTOR_TEST_PAY_PER_EVENT=1` and `ACTOR_USE_CHARGING_LOG_DATASET=1`. Locally, each event is priced at $1 and appended to `storage/datasets/charging_log`. That log is not created on the Apify platform. `OUTPUT.charged_events` is the number of events the run actually billed. Publish from this folder with `apify push`.

# Changelog

This Actor's version history is a separate document: https://apify.com/cleandata-tools/disposable-email-validator/changelog.md

# Actor input Schema

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

Addresses to validate, up to 100,000 per run including any loaded from Source URL. Duplicates are kept so each input row gets its own result. Empty lines are dropped.

## `sourceUrl` (type: `string`):

Optional http(s) URL of a CSV file, a JSON array, JSON lines, or an Apify dataset items URL (https://api.apify.com/v2/datasets/DATASET_ID/items?format=json\&clean=true). A column or field named email, emails, or e-mail is used. Otherwise the first CSV column is used. Private Apify datasets use this run's token. Combined with Email addresses, still capped at 100,000.

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

How many batches of 50 addresses to send at once. Higher is faster and uses the same 256 MB.

## `maxRetries` (type: `integer`):

Extra attempts after a timeout, HTTP 429, or HTTP 5xx, with exponential backoff. HTTP 400 and 401 are not retried. Failed addresses are saved with worker_error and are not charged.

## Actor input object example

```json
{
  "emails": [
    "ada@gmail.com",
    "a@mailinator.com",
    "not-an-email",
    "info@gmial.com"
  ],
  "sourceUrl": "https://api.apify.com/v2/datasets/DATASET_ID/items?format=json&clean=true&fields=email",
  "concurrency": 8,
  "maxRetries": 4
}
```

# Actor output Schema

## `results` (type: `string`):

One dataset item per address, with syntax, MX, disposable, free-provider, role, typo, risk, and block.

## `summary` (type: `string`):

Counts of validated, failed, skipped, disposable, and blocked addresses.

# 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": [
        "ada@gmail.com",
        "a@mailinator.com",
        "not-an-email",
        "info@gmial.com"
    ],
    "concurrency": 8
};

// Run the Actor and wait for it to finish
const run = await client.actor("cleandata-tools/disposable-email-validator").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": [
        "ada@gmail.com",
        "a@mailinator.com",
        "not-an-email",
        "info@gmial.com",
    ],
    "concurrency": 8,
}

# Run the Actor and wait for it to finish
run = client.actor("cleandata-tools/disposable-email-validator").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": [
    "ada@gmail.com",
    "a@mailinator.com",
    "not-an-email",
    "info@gmial.com"
  ],
  "concurrency": 8
}' |
apify call cleandata-tools/disposable-email-validator --silent --output-dataset

```

## MCP server setup

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

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/MyvyiFBueC0k4npNp/builds/AhpH01ZGC3Iny9RhI/openapi.json
