# Bulk Email Validator - MX, Disposable, Role & Typo Check (`tinyrex/bulk-email-validator`) Actor

Clean email lists in bulk: syntax, MX/DNS, null MX, disposable, role-based, free-provider and typo checks plus SPF/DMARC. $0.30 per 1,000 emails; bad syntax, duplicates and DNS errors free. No SMTP probing.

- **URL**: https://apify.com/tinyrex/bulk-email-validator.md
- **Developed by:** [TinyRex](https://apify.com/tinyrex) (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 $0.24 / 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.
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 Validator: MX, disposable, role-based and typo check

**Clean an email list before you import it into your CRM or send a campaign** — paste thousands of addresses and get `valid`, `risky`, `invalid` or `unknown` for each one, with a plain-English reason. The Actor checks syntax, whether the domain exists and accepts email (MX, null MX, A fallback), disposable/temporary providers, role inboxes (info@, sales@), free webmail and common typos (`gmial.com` → `gmail.com`), plus SPF and DMARC of the domain. **$0.30 per 1,000 emails; bad syntax, duplicates and DNS errors are free.** No API key, no login.

### What you get from the Bulk Email Validator

- **Catch dead and fake addresses fast** — domains that don't exist, domains with a null MX (they accept no mail), domains with no mail server at all, and broken syntax (`a..b@x.com`, `name@@domain`, missing TLD).
- **Flag risky addresses** — ~10,000 disposable/temporary domains (open CC0 list), typo-trap domains with a `didYouMean` fix, role/shared inboxes (`isRoleBased`) and free webmail (`isFreeProvider`) so you can split B2B from B2C leads.
- **Domain email health** — `hasSpf` and `hasDmarc` show whether the company's email is set up properly, and `mxRecords` shows who hosts it (Google Workspace, Microsoft 365, ...).

### Sample output (JSON)

```json
{
  "input": "jane@gmial.com",
  "email": "jane@gmial.com",
  "status": "risky",
  "reason": "typo-trap domain on the disposable list, did you mean jane@gmail.com?",
  "syntaxValid": true,
  "domain": "gmial.com",
  "localPart": "jane",
  "isRoleBased": false,
  "isFreeProvider": false,
  "isDisposable": true,
  "didYouMean": "jane@gmail.com",
  "domainExists": true,
  "hasMx": false,
  "mxRecords": [],
  "nullMx": false,
  "acceptsMailViaA": true,
  "hasSpf": false,
  "hasDmarc": false,
  "smtpChecked": false,
  "charged": true,
  "checkedAt": "2026-10-18T07:03:28.104Z"
}
```

A valid company address looks like `"status": "valid", "reason": "mail domain OK; role/shared inbox", "mxRecords": ["aspmx.l.google.com", ...], "hasSpf": true, "hasDmarc": true`.

Export as **CSV, Excel or JSON**, or send results to Google Sheets, Make, Zapier, n8n, webhooks or the Apify API. A `SUMMARY` record in the key-value store has run totals (valid / risky / invalid / unknown / charged).

### How to configure the Bulk Email Validator

1. Paste your **emails**, one per line (a column copied from Excel or a CRM export works).
2. Or give a **dataset ID**: the Actor collects every email from another run's output, for example [Website Contact Details Extractor](https://apify.com/tinyrex/contact-details-extractor).
3. Run. Each unique email that gets a DNS verdict is one charge.

#### Example input

```json
{
  "emails": ["hello@apify.com", "jane@gmial.com", "test@mailinator.com", "nobody@example.com"],
  "checkSpfDmarc": true,
  "maxEmails": 10000
}
```

| Setting | Default | Notes |
|---|---|---|
| emails | — | Addresses to check; duplicates removed case-insensitively (free) |
| datasetId | — | Pull every email-looking string from an Apify dataset |
| checkSpfDmarc | true | Adds `hasSpf` / `hasDmarc`; no extra charge |
| maxEmails | 10000 | Hard cap on unique emails per run (up to 100,000) |

**Status meaning**

| status | Meaning | Charged |
|---|---|---|
| `valid` | Syntax OK, domain exists and has a mail server, not disposable | yes |
| `risky` | Disposable provider, likely typo, or no MX (mail only via A record) | yes |
| `invalid` | Domain doesn't exist, null MX or no mail server | yes |
| `invalid` (bad syntax) | Fails the syntax check, no DNS lookup needed | **free** |
| `unknown` | DNS lookup failed after retries; try again later | **free** |

**Speed:** each domain is looked up once and cached, with 32 lookups in parallel.

### Common use cases

- **Before a campaign**: drop dead domains, typos and disposable signups so bounces don't hurt your sender reputation.
- **CRM and newsletter clean-up**: tag old contacts as `invalid` or `risky` and export only the `valid` ones as CSV.
- **Lead lists**: check emails found by [Website Contact Details Extractor](https://apify.com/tinyrex/contact-details-extractor) and filter role inboxes with `isRoleBased`.
- **Signup forms**: run a nightly batch on new registrations to catch fake and temporary addresses.

### Pricing

Pay per event: **$0.0003 per email checked** ($0.30 per 1,000), with Bronze/Silver/Gold discounts. Bad-syntax rows, duplicates and DNS errors (`unknown`) are free. A tiny Actor-start fee applies per run.

### What this Actor does not do

It does **not** connect to mail servers to probe individual mailboxes (no SMTP `RCPT TO` handshake). That keeps it fast, cheap and safe for your list, but it means it can't tell whether `john@company.com` exists on a domain that does accept mail. Use it as the first, cheap pass that removes dead domains, disposables and typos; send the remaining `valid` addresses to an SMTP verifier only if you need mailbox-level certainty.

### FAQ

**How do I check if an email address is valid without sending an email?** Paste it into *Emails*. The Actor checks the syntax and then asks DNS whether the domain exists and has a mail server (MX record). If either fails, the address can't receive email and comes back `invalid`.

**What is a disposable email address?** A temporary inbox from services like Mailinator or 10MinuteMail, used to grab a download or a free trial. They're flagged `isDisposable: true` and `status: risky` using the open CC0 [disposable-email-domains](https://github.com/disposable-email-domains/disposable-email-domains) list.

**Should I remove role-based emails like info@ or sales@?** For cold outreach to people, often yes; for B2B lead lists they're usually fine. That's why role addresses stay `valid` and are only flagged with `isRoleBased: true`, so you can filter them yourself.

**What does a null MX mean?** A domain can publish a "null MX" record (RFC 7505) to say it never accepts email, like `example.com`. Mail to it always bounces, so it's `invalid`.

**Is my list stored or shared?** The emails stay in your own Apify run storage. Lookups go to public DNS over HTTPS (Cloudflare 1.1.1.1, with Google Public DNS as fallback), which only sees domain names, never full addresses.

### Related actors

- [Website Contact Details Extractor](https://apify.com/tinyrex/contact-details-extractor) — company emails, phones and social links from a list of domains; feed its dataset straight into this validator.
- [Tech Stack Detector](https://apify.com/tinyrex/tech-stack-detector) — technologies used by any website.
- [UK Companies House Lookup](https://apify.com/tinyrex/uk-companies-house-lookup) — UK company profiles and officers from the official register.
- [LEI Lookup](https://apify.com/tinyrex/gleif-lei-lookup) — bulk GLEIF LEI search and validation.

# Actor input Schema

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

Email addresses to validate, one per line (paste a column from a spreadsheet or CRM export). Duplicates are removed case-insensitively and are free.

## `datasetId` (type: `string`):

ID of an Apify dataset to pull emails from, e.g. the output of Website Contact Details Extractor or any lead scraper. Every email-looking string in every item is collected.

## `checkSpfDmarc` (type: `boolean`):

Adds hasSpf and hasDmarc (a quick signal of whether the domain's email is set up properly). Two extra DNS lookups per domain, no extra charge.

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

Hard cap on unique emails checked in this run.

## Actor input object example

```json
{
  "emails": [
    "hello@apify.com",
    "jane@gmial.com",
    "test@mailinator.com",
    "nobody@example.com"
  ],
  "checkSpfDmarc": true,
  "maxEmails": 10000
}
```

# Actor output Schema

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

One row per unique email.

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

Totals for the run.

# 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",
        "test@mailinator.com",
        "nobody@example.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("tinyrex/bulk-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": [
        "hello@apify.com",
        "jane@gmial.com",
        "test@mailinator.com",
        "nobody@example.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("tinyrex/bulk-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": [
    "hello@apify.com",
    "jane@gmial.com",
    "test@mailinator.com",
    "nobody@example.com"
  ]
}' |
apify call tinyrex/bulk-email-validator --silent --output-dataset

```

## MCP server setup

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