# Email List Checker: Syntax, MX & Disposable Domains (`santamaria-automations/email-verifier`) Actor

Check email lists in bulk for bad syntax, missing MX records, disposable domains and role addresses (info@, sales@). Adds a catch-all heuristic and a 0-100 score per address. No mailbox-level check: it does not confirm an address exists. Pay per email.

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

## Pricing

from $2.00 / 1,000 email checkeds

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

## Email List Checker: Syntax, MX, Disposable and Role Addresses

Check a list of email addresses in bulk for bad syntax, missing MX records, disposable-mail domains and role addresses such as `info@` or `sales@`. Each address gets a status (`ok`, `risky`, `invalid`), a catch-all guess and a 0-100 score you can sort a CRM export by. Use it to clean a list before outreach and to flag the addresses that need a second look.

**This actor does not do a mailbox-level SMTP check.** It never contacts the recipient's mail server, so it cannot tell you whether a particular mailbox exists or whether a message will be delivered. It is a syntax, MX, disposable-domain, role-address and catch-all-heuristic checker.

### What you can do with it

- Drop addresses with broken syntax or domains that have no MX records before you send.
- Flag disposable-mail domains in sign-up lists and lead exports.
- Separate role addresses (`info@`, `support@`) from personal ones.
- Spot domains whose mail host looks like shared web hosting, where catch-all setups are common.
- Join results back to your own records with a `company_id` that is echoed on every row.

### What each check does

| Check | Meaning |
|-------|---------|
| Syntax | Pattern check with extra rules: one `@`, no `..`, no leading or trailing dot in the local part, length limits, a top-level domain of 2 or more letters. |
| MX records | The domain's DNS MX records. `mx_ok` is true when at least one MX host is returned. A "null MX" (a single `.`) counts as none. |
| MX provider | Name derived from the MX host: `google_workspace`, `microsoft_365`, `zoho`, `mailgun`, `sendgrid`, `amazon_ses`, `ionos`, `yandex`, `mail_ru`, `mimecast`, `proofpoint`, `fastmail`, `yahoo`, or `other`. |
| Disposable | The domain, or a parent domain, is on the bundled list of disposable-mail services. |
| Role address | The part before the `@` is exactly one of: info, contact, hello, sales, support, admin, hr, jobs, careers, noreply, no-reply, team, office, kontakt, marketing, billing, webmaster, postmaster, abuse. |
| Catch-all (heuristic) | A guess from the MX host name, never a test. Hosts of known mail providers give `unknown`. Hosts that look like shared web hosting give `likely`. The value is never `no`. |

How the checks combine into `status`:

- `invalid`: bad syntax, no MX records, or a disposable domain.
- `risky`: a role address, or a `likely` catch-all.
- `ok`: none of the checks flagged the address. This does not mean the mailbox exists.

### Input

| Field | Type | Description | Default |
|-------|------|-------------|---------|
| `emails` | string\[] | Email addresses to check. A single string, or several separated by commas or new lines, also works. | five sample addresses when both fields are missing |
| `companies` | object\[] | Entries of `{ "company_id": "...", "emails": [...] }`. The `company_id` is echoed on every output row. | none |

Both fields can be used together. Addresses are trimmed and de-duplicated (same company and same address, ignoring case). An explicit empty list checks nothing and charges nothing.

Flat list:

```json
{
  "emails": ["jane.doe@gmail.com", "info@apify.com", "throwaway@mailinator.com"]
}
```

With a `company_id` for join-back:

```json
{
  "companies": [
    { "company_id": "acme-42", "emails": ["ceo@apify.com", "info@apify.com"] }
  ]
}
```

### Output

One row per address, in input order. Fields:

| Field | Description |
|-------|-------------|
| `company_id` | Echoed from `companies`. Left out when the address came from `emails`. |
| `email` | The address as checked (trimmed). |
| `status` | `ok`, `risky` or `invalid` (see above). |
| `syntax_ok` | True when the address passes the syntax check. |
| `mx_ok` | True when the domain has at least one MX record. |
| `mx_provider` | Provider name derived from the MX host. Left out when `mx_ok` is false. |
| `disposable` | True when the domain is on the disposable list. |
| `role_account` | True when the local part is a role name. |
| `catch_all` | `likely` or `unknown`. A heuristic from the MX host name. |
| `catch_all_method` | Always `heuristic`: the mail server is not contacted. |
| `score` | 0-100 for sorting a list, not a probability of delivery. `invalid` is 0 to 15, `risky` 40 to 55, `ok` 85 to 95. |
| `checked_at` | ISO 8601 timestamp of the check. |

Sample row:

```json
{
  "company_id": "acme-42",
  "email": "info@apify.com",
  "status": "risky",
  "syntax_ok": true,
  "mx_ok": true,
  "mx_provider": "google_workspace",
  "disposable": false,
  "role_account": true,
  "catch_all": "unknown",
  "catch_all_method": "heuristic",
  "score": 55,
  "checked_at": "2026-10-26T10:30:00Z"
}
```

### Pricing

Pay per event:

| Event | When it is charged | Price |
|-------|--------------------|-------|
| `enrichment-start` | Once per run, after the first row has been delivered. A run that delivers nothing is not charged. | $0.001 |
| `enrichment-result` | Per checked address delivered to the dataset. | $0.002 |

1,000 addresses cost $0.001 + 1,000 x $0.002 = $2.001. If you set a maximum total charge for the run, the actor stops delivering rows when the next row would exceed it and the run ends with the status "Stopped at the max charge limit. N emails delivered."

### Use with AI agents (MCP)

Connect this actor to an MCP-compatible client such as Claude Desktop, Cursor or VS Code.

```json
{
  "mcpServers": {
    "apify": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://mcp.apify.com/?tools=santamaria-automations/email-verifier",
        "--header",
        "Authorization: Bearer <YOUR_API_TOKEN>"
      ]
    }
  }
}
```

Example prompt: "Use email-verifier to check these 200 addresses and give me the ones with status ok."

### FAQ

**Does it tell me whether a mailbox exists?** No. There is no mailbox-level SMTP check. `ok` means no check flagged the address, not that it will receive mail.

**Why is `catch_all` never `no`?** The mail server is not asked, so a catch-all setup can be suspected but not ruled out. `likely` is a guess from the MX host name.

**Why is a typo domain like `gnail.com` marked `ok`?** If the domain has MX records and is not disposable, no check flags it. Typo domains are not detected.

**Why is `example.com` `invalid`?** It publishes a null MX, which means it does not receive mail.

**Can I stop at a budget?** Yes, set a maximum total charge on the run. Rows stop at the limit and the status message says how many were delivered.

### Related actors

- [Website Email Scraper](https://apify.com/santamaria-automations/website-email-scraper): pull emails and phones from company websites
- [Website Contact Extractor](https://apify.com/santamaria-automations/website-contact-extractor): extract team members and decision-makers
- [Google Maps Scraper](https://apify.com/santamaria-automations/google-maps-scraper): find local businesses with contact details
- [GBP Completeness Audit](https://apify.com/santamaria-automations/gbp-completeness-audit): score Google Business Profiles for local SEO leads

### Support

Questions or a bad result? Open an issue from the Issues tab of this actor and include the run link.

# Actor input Schema

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

Flat list of email addresses to check. A single string, or several separated by commas or new lines, also works.

## `companies` (type: `array`):

Alternative shape. Each entry carries a company_id that is echoed on every output row, so you can join the results back to your own data.

## Actor input object example

```json
{
  "emails": [
    "jane.doe@gmail.com",
    "info@apify.com",
    "throwaway@mailinator.com",
    "not-a-real-email",
    "someone@thisdomaindoesnotexist123456.com"
  ]
}
```

# Actor output Schema

## `verifications` (type: `string`):

Dataset of verified emails

# 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": [
        "jane.doe@gmail.com",
        "info@apify.com",
        "throwaway@mailinator.com",
        "not-a-real-email",
        "someone@thisdomaindoesnotexist123456.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("santamaria-automations/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": [
        "jane.doe@gmail.com",
        "info@apify.com",
        "throwaway@mailinator.com",
        "not-a-real-email",
        "someone@thisdomaindoesnotexist123456.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("santamaria-automations/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": [
    "jane.doe@gmail.com",
    "info@apify.com",
    "throwaway@mailinator.com",
    "not-a-real-email",
    "someone@thisdomaindoesnotexist123456.com"
  ]
}' |
apify call santamaria-automations/email-verifier --silent --output-dataset

```

## MCP server setup

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