# Fake Email Checker: Reduce fake signups (`apizilla/email-checker`) Actor

Check emails in bulk: syntax, disposable or temporary domains (3 merged lists), MX records, role accounts, free providers and typos like gmial.com. Get a verdict (valid, risky, invalid, disposable) and a 0-100 score for each email.

- **URL**: https://apify.com/apizilla/email-checker.md
- **Developed by:** [APIzilla](https://apify.com/apizilla) (community)
- **Categories:** Lead generation, Developer tools
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.50 / 1,000 emails

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

### What does Email Checker do?

Email Checker tells you if an email address is **real and usable**, or **fake, mistyped or disposable**. Paste a list of emails or give it a CSV file, and it checks each one in seconds:

- **Syntax**: is it a well-formed email?
- **Disposable email detection**: is it a temporary or throwaway address (Mailinator, YOPmail, 10 Minute Mail and thousands more)? Three maintained lists are merged, and you see which list matched.
- **Domain and MX check**: does the domain exist, and does it have a mail server?
- **Role accounts**: info@, support@, sales@, noreply@ ...
- **Free providers**: Gmail, Outlook, Yahoo, GMX, web.de and about 31,000 more.
- **Typos**: gmial.com, gmail.con, hotmial.com ... with a "did you mean" fix.

Every email gets a **verdict** (`valid`, `risky`, `invalid` or `disposable`), a **score from 0 to 100** and a **reason in plain English**.

### Why use Email Checker?

- **Clean sign-up forms and lead lists.** Remove fake and throwaway emails before they reach your CRM or newsletter.
- **Fewer bounces.** Domains with no mail server and broken addresses are flagged as `invalid`.
- **Fix typos.** `didYouMean` gives you the corrected email, so you can save a real lead instead of losing it.
- **Fast and cheap.** No browser and no third-party API. One DNS lookup per domain, cached. 256 MB of memory is enough for 100,000+ emails.
- **Honest results.** It does not pretend to test the mailbox. See [What it does not check](#what-it-does-not-check).
- **Pay per email.** Duplicates are free.

Typical users: SaaS sign-up forms, marketers cleaning lists, sales teams checking scraped leads, fraud and trust teams.

You also get everything the Apify platform offers: API access, schedules, webhooks and integrations (Google Sheets, Make, Zapier, n8n).

### What does Email Checker check?

| Field | What it is |
| --- | --- |
| `email` | The email as you gave it (trimmed) |
| `normalized` | Same email with the domain in lower case |
| `canonicalEmail` | The real mailbox: `John.Doe+news@Gmail.com` becomes `johndoe@gmail.com` |
| `domain` | Domain of the email |
| `verdict` | `valid`, `risky`, `invalid` or `disposable` |
| `score` | 0 to 100 |
| `reason` | Why, in plain English |
| `isValidSyntax`, `syntaxError` | Is the email well formed, and if not, what is wrong |
| `isDisposable`, `disposableSources` | Temporary email, and which lists matched |
| `hasMx`, `mxRecords`, `dnsStatus` | Mail servers of the domain (up to 3) and the DNS result |
| `isRoleAccount` | Team or function mailbox (info@, support@ ...) |
| `isFreeProvider` | Free webmail (Gmail, Outlook, Yahoo, GMX ...) |
| `didYouMean` | Suggested fix for a typo in the domain |
| `isAllowlisted` | The domain is on your allow list |

#### Verdicts and scores

| Verdict | Score | Meaning |
| --- | --- | --- |
| `valid` | 70 to 95 | Good syntax, the domain has a mail server, not disposable |
| `risky` | 20 to 69 | Role account, typo with a working domain, no MX (only an A record), or the DNS lookup failed |
| `invalid` | 0 | Bad syntax, the domain does not exist, has no mail server, or refuses email (null MX) |
| `disposable` | 0 to 10 | Temporary or throwaway email service |

The best score is 95, not 100, because a domain check cannot prove that the mailbox itself exists.

#### Disposable email lists

| Source | What it is |
| --- | --- |
| `fakefilter` | [FakeFilter](https://github.com/7c/fakefilter), updated daily |
| `disposable-email-domains` | The [community list](https://github.com/disposable-email-domains/disposable-email-domains) used by PyPI and many sign-up forms |
| `mailchecker` | [MailChecker](https://github.com/FGRibreau/mailchecker), the biggest list (about 56,000 domains) |
| `mx-host` | The domain is not on any list, but its mail server belongs to a known disposable service. Catches new throwaway domains |
| `denylist` | Your own deny list |

Subdomains count too: `x.mailinator.com` is disposable. Big providers such as Gmail or Outlook are never marked disposable. Want fewer false alarms? Set **Lists that must agree** to 2.

### How to check emails in bulk

1. Open the Actor and go to the **Input** tab.
2. Paste your **Emails**, one per line. Or add the link of a **CSV or TXT file**.
3. Optional: change the checks, add your own allow or deny list.
4. Click **Start**.
5. Download the results as CSV, Excel, JSON or HTML. Filter on `verdict` to keep only the `valid` ones.

Example input:

```json
{
    "emails": [
        "info@apify.com",
        "test@mailinator.com",
        "someone@gmial.com",
        "not-an-email",
        "hello@this-domain-does-not-exist-12345.com"
    ],
    "checkDns": true,
    "roleAccountsAreRisky": true
}
```

A Google Sheet works as a file: use **File > Share > Publish to web > CSV** and paste the link in **CSV or TXT file URLs**. The link must open without logging in: a public link, a Google Sheets CSV link, a raw GitHub or Dropbox link, or a signed Apify storage link.

### How much does it cost to check emails?

This Actor uses pay per event pricing. You pay for each unique email checked. Duplicates and empty lines are free.

| Event | When you pay | Price per 1,000 |
| --- | --- | --- |
| `email-checked` | Once per unique email in the results | $0.50 |
| `apify-actor-start` | When a run starts. One event per GB of memory, at least one | $1.00 (about $0.001 per run) |

Example: 10,000 emails cost about $5.00.

You can set a maximum cost per run. The Actor checks your budget before each batch and stops cleanly when it is reached. You never pay for an email that is not in the results.

The Pricing tab shows the exact prices.

### Input

| Field | Default | What it does |
| --- | --- | --- |
| `emails` | | Emails to check |
| `fileUrls` | | Links to CSV or TXT files |
| `checkDns` | `true` | Check the domain and its mail servers |
| `roleAccountsAreRisky` | `true` | Role accounts get the verdict `risky` |
| `disposableLists` | all 3 | Which disposable lists to use |
| `minListMatches` | `1` | How many lists must agree |
| `checkMxDisposable` | `true` | Detect disposable mail servers |
| `allowlistDomains`, `denylistDomains` | | Your own lists |
| `dedupe` | `true` | Check each email once |
| `dedupeAliases` | `false` | Also treat Gmail and Outlook aliases as duplicates |
| `maxEmails` | `0` (no limit) | Stop after this many emails |
| `dnsConcurrency`, `dnsTimeoutSecs`, `dnsServers` | `50`, `4`, default | DNS speed settings |

### Output

One item per unique email in the dataset:

```json
{
    "email": "test.user@hotmial.com",
    "normalized": "test.user@hotmial.com",
    "canonicalEmail": "test.user@hotmial.com",
    "domain": "hotmial.com",
    "verdict": "disposable",
    "score": 0,
    "reason": "Disposable email domain (disposable-email-domains, mailchecker). Looks like a typo, did you mean test.user@hotmail.com?",
    "isValidSyntax": true,
    "syntaxError": null,
    "isDisposable": true,
    "disposableSources": ["disposable-email-domains", "mailchecker"],
    "hasMx": true,
    "mxRecords": ["mail.h-email.net"],
    "dnsStatus": "ok",
    "isRoleAccount": false,
    "isFreeProvider": false,
    "didYouMean": "test.user@hotmail.com",
    "isAllowlisted": false
}
```

A summary is saved in the key-value store as `OUTPUT`: counts per verdict, role accounts, free providers, typos, matches per list, duplicates removed and charged events.

### Real-time API (Standby mode)

You can also call the Actor like an API, with no run to start each time. Once the Standby run is up, an answer takes about one DNS lookup, and domains already looked up are cached.

```
GET https://<your standby URL>/check?email=someone@example.com
GET https://<your standby URL>/check?emails=a@example.com,b@example.org
POST https://<your standby URL>/check   {"emails": ["a@example.com", "b@example.org"]}
```

Up to 100 emails per request. Add your Apify API token as `Authorization: Bearer <token>`. The Standby URL is on the **API** tab of the Actor. Each email costs one `email-checked` event.

### What it does not check

**Mailbox (SMTP) and catch-all checks are not done.** To test a mailbox, a checker has to talk to the mail server on port 25. That port is blocked for outgoing traffic on Apify, as on most clouds, to stop spam. We tested it: from an Apify run, port 25 of the Gmail and Outlook mail servers timed out, while normal HTTPS worked. Some tools get around this with their own outside servers. This Actor runs fully on Apify and does not fake that result.

So `valid` means: the address is well formed, not disposable, and its domain can receive email. It does not prove that this exact mailbox exists. For most uses (sign-up forms, lead cleaning, removing fake emails) this is the part that matters, and it is much faster and cheaper.

### FAQ

**Is it legal to check emails?** The Actor only uses public DNS records and public lists. It does not send emails or contact the mail server. Make sure you have a lawful reason to process the emails you check (for example GDPR in the EU).

**How fast is it?** Thousands of emails per minute. Most time goes into DNS lookups, and each domain is looked up only once per run.

**A real domain is marked disposable. What can I do?** Add it to the **Allow list**, or set **Lists that must agree** to 2. Please tell us in the Issues tab, so we can report it to the list.

**Can I add my own throwaway domains?** Yes, put them in the **Deny list**.

**Something is wrong or missing?** Open an issue in the Issues tab. We read them.

# Actor input Schema

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

Emails to check, one per line. You can also paste several per line, separated by commas or semicolons. "Name <name@example.com>" works too. Duplicates are removed and not charged.

## `fileUrls` (type: `array`):

Links to CSV or TXT files with emails (any column, one or many per line). Lines without an @ are skipped. Max 100 MB per file. The link must open without logging in, for example a Google Sheet "Publish to web" CSV link or a raw GitHub or Dropbox link.

## `checkDns` (type: `boolean`):

Look up the MX records of each domain (one lookup per domain, cached). Finds domains that do not exist or cannot receive email. Turn off for a pure offline check (syntax, disposable, role, free, typo).

## `roleAccountsAreRisky` (type: `boolean`):

Role accounts like info@, support@ or sales@ are real mailboxes but are often shared or filtered. On: verdict "risky". Off: they can still be "valid" (isRoleAccount stays true).

## `disposableLists` (type: `array`):

Which lists to use. fakefilter (updated daily), disposable-email-domains (community list used by PyPI and many sites) and mailchecker (biggest, about 56,000 domains, a bit stricter).

## `minListMatches` (type: `integer`):

How many lists must contain a domain before it counts as disposable. 1 catches the most. 2 gives fewer false alarms.

## `checkMxDisposable` (type: `boolean`):

Also mark a domain as disposable when its mail server (MX) belongs to a known disposable service. Catches new throwaway domains that are not on any list yet. Needs the MX check.

## `allowlistDomains` (type: `array`):

Domains that are never marked disposable, for example your own domain or a partner. Subdomains are included.

## `denylistDomains` (type: `array`):

Domains you want marked as disposable, for example throwaway domains you have seen in your sign-ups. Subdomains are included.

## `dedupe` (type: `boolean`):

Check each email only once (not case-sensitive). Duplicates are not charged.

## `dedupeAliases` (type: `boolean`):

john.doe+news@gmail.com and johndoe@gmail.com go to the same mailbox. On: keep only the first one.

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

Stop after this many unique emails. 0 = no limit. The run also stops cleanly at your max charge.

## `dnsConcurrency` (type: `integer`):

How many domains are looked up at the same time.

## `dnsTimeoutSecs` (type: `integer`):

Per try. A failed lookup is tried again with Cloudflare and Google DNS.

## `dnsServers` (type: `array`):

Optional IP addresses of DNS servers, for example 1.1.1.1. Empty = the default resolver.

## Actor input object example

```json
{
  "emails": [
    "info@apify.com",
    "test@mailinator.com",
    "someone@gmial.com",
    "not-an-email",
    "hello@this-domain-does-not-exist-12345.com"
  ],
  "checkDns": true,
  "roleAccountsAreRisky": true,
  "disposableLists": [
    "fakefilter",
    "disposable-email-domains",
    "mailchecker"
  ],
  "minListMatches": 1,
  "checkMxDisposable": true,
  "dedupe": true,
  "dedupeAliases": false,
  "maxEmails": 0,
  "dnsConcurrency": 50,
  "dnsTimeoutSecs": 4
}
```

# Actor output Schema

## `dataset` (type: `string`):

One item per unique email

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

Counts per verdict, disposable list matches, duplicates removed and charged events

# 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": [
        "info@apify.com",
        "test@mailinator.com",
        "someone@gmial.com",
        "not-an-email",
        "hello@this-domain-does-not-exist-12345.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("apizilla/email-checker").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": [
        "info@apify.com",
        "test@mailinator.com",
        "someone@gmial.com",
        "not-an-email",
        "hello@this-domain-does-not-exist-12345.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("apizilla/email-checker").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": [
    "info@apify.com",
    "test@mailinator.com",
    "someone@gmial.com",
    "not-an-email",
    "hello@this-domain-does-not-exist-12345.com"
  ]
}' |
apify call apizilla/email-checker --silent --output-dataset

```

## MCP server setup

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

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/DacRf96oE9bAnybsf/builds/mNId32QVpWPoo1f7p/openapi.json
