# Email Verifier & Validator | Verifies B2B Catch-All | $0.30/1k (`cold_email_master/email-verifier-validator`) Actor

B2B catch-all domains are where other verifiers give up and mark every address risky. This one resolves the actual mailbox: real addresses return valid, fake ones invalid. Also checks RFC syntax, DNS, MX and SMTP, and flags disposable and role inboxes. $0.30 per 1,000.

- **URL**: https://apify.com/cold_email_master/email-verifier-validator.md
- **Developed by:** [indrajit guha](https://apify.com/cold_email_master) (community)
- **Categories:** Lead generation, Automation, Developer tools
- **Features:** Limited permissions
- **Stats:** 24 total users, 5 monthly users, 86.7% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.25 / 1,000 email verifieds

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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

## 📧 Email Verifier — Bulk Email Validation on Apify

**Validate thousands of email addresses per run with 99.9% accuracy — at $0.30 per 1,000 validations, the cheapest email verification on the Apify marketplace.**

> **Requires a paid Apify plan.** Free-plan runs exit straight away without verifying or charging anything. For free verification, use the [Free Email Verifier](https://apify.com/cold_email_master/free-email-verifier) — same checks, 50 addresses per run.

Powered by [Verimailx](https://api.verimailx.com) and wrapped as a plug-and-play Apify Actor. No SMTP servers to maintain, no MX lookups to debug, no proxies to manage. Just hand it a list of emails, hit Run, and get a clean, structured verdict per address in your dataset.

***

### Why Email Verifier?

| | |
|---|---|
| 🎯 **Accuracy** | 99.9% across valid, invalid, and catch-all detection |
| 💸 **Price** | $0.30 / 1,000 validations — cheapest on Apify |
| ⚡ **Throughput** | Asynchronous jobs — submit the whole list at once, no size ceiling |
| 🧹 **Clean output** | One structured record per email, ready to export as CSV or JSON |
| 🔌 **Zero infra** | No SMTP, no DNS, no proxy rotation — the Actor handles it all |
| 🔁 **B2B catch-all verified** | Resolves individual mailboxes on B2B catch-all domains instead of writing the whole domain off as risky |

***

### What you get per email

Every email you submit is checked across five dimensions:

1. **Syntax** — RFC-compliant local-part and domain structure
2. **DNS validity** — the domain actually resolves
3. **MX records** — the domain has mail servers configured to receive mail
4. **SMTP handshake** — the receiving server confirms the address exists
5. **Disposable / role-based detection, and B2B catch-all resolution** — flags throwaway inboxes and role mailboxes (info@, admin@), and verifies individual mailboxes behind B2B catch-all domains rather than discarding them

> **Running without credentials.** If `APIFY-VERIMAILX-API-KEY` isn't configured, the Actor performs **syntax checks only**, marks every record with `validationMode: "syntax-only"` and a `warning` field, returns `null` for MX / SMTP / disposable / role-based, and **charges nothing**. You are never billed for a check that wasn't performed.

Each address gets one of these verdicts:

| Verdict | Meaning |
|---|---|
| **`valid`** | Safe to send. Mailbox exists and accepts mail. |
| **`invalid`** | Will bounce. Bad syntax, no MX, or SMTP explicitly rejected. |
| **`risky`** | Disposable or role-based mailbox, or a catch-all address that could not be resolved (including consumer/B2C catch-alls, which are out of scope). Treat with caution. |
| **`unknown`** | Server timeout or ambiguous response. Retry later. |

***

### Input — four ways to hand over your list

Give the Actor addresses in whichever form you already have them. Sources can be combined; everything is merged and de-duplicated before verification.

#### A pasted list

```json
{
  "emails": ["founder@stripe.com", "sales@shopify.com", "info@example.com"]
}
```

#### A single address

```json
{ "email": "founder@stripe.com" }
```

#### A CSV or TXT file

Point the Actor at a public link — a Google Sheets CSV export, an S3 object, a Dropbox direct link. Every address in the file is picked up no matter which column it sits in, so you can upload your export untouched. Maximum 10 MB.

```json
{ "emailFileUrl": "https://example.com/leads-export.csv" }
```

#### The output of another Actor

Chain this straight onto a scraper without exporting anything in between.

```json
{ "datasetId": "aBcDeF123456", "datasetField": "email" }
```

Leave `datasetField` out and every text field on each record is scanned for addresses.

No proxy config and no schema to learn. The Actor reads the Verimailx API key from its environment — set once in the Apify console.

***

### Output

One structured record per email, pushed to the run's default dataset. Export as CSV or JSON straight from the Apify Console.

```json
{
  "email": "[email protected]",
  "overall": "valid",
  "result": "valid",
  "deliverabilityScore": 98,
  "safeToSend": true,
  "syntaxValid": true,
  "dnsValid": true,
  "mxValid": true,
  "smtpValid": true,
  "catchAll": false,
  "roleName": null,
  "disposableProvider": null,
  "validationMode": "full",
  "checkedAt": "2026-08-09T10:14:22.418Z"
}
```

#### Output fields

| Field | Type | Description |
|---|---|---|
| `email` | string | The address you submitted |
| `overall` | string | `valid` / `invalid` / `risky` / `unknown` / `error` |
| `safeToSend` | bool | True only for a clean `valid`. The one column to filter on. |
| `result` | string | Raw Verimailx verdict, passed through unchanged (`valid`, `invalid`, `disposable`, `role`, `unknown`, …) |
| `deliverabilityScore` | number | 0–100 confidence score from Verimailx |
| `syntaxValid` | bool | RFC-compliant structure |
| `dnsValid` | bool / null | Domain resolves in DNS |
| `mxValid` | bool / null | Domain has usable MX records |
| `smtpValid` | bool / null | Receiving server confirmed the address |
| `catchAll` | bool | True only for a catch-all address that could not be resolved individually (B2C catch-alls included) |
| `roleName` | string / null | The role detected, e.g. `support` — empty when not a role mailbox |
| `disposableProvider` | string / null | The throwaway provider, e.g. `temporary-mail` — empty when not disposable |
| `validationMode` | string | `full` when Verimailx was called |
| `checkedAt` | string | ISO 8601 timestamp |

***

### Pricing

#### Plan requirement

Apify pays a developer only for runs started by users on a paid plan, while every run still costs real verification credits. Rather than quietly absorb that, this Actor checks the caller's plan before doing anything: a free-plan run stops immediately, verifies nothing, charges nothing, and finishes with a status message pointing to the free edition. No addresses are consumed and no partial results are produced.

**$0.30 per 1,000 validations** — billed per email checked, not per run. Submit 47 emails, you pay for 47. Submit 12,000, you pay for 12,000.

| Volume | Cost |
|---|---:|
| 100 emails | $0.03 |
| 1,000 emails | $0.30 |
| 10,000 emails | $3.00 |
| 100,000 emails | $30.00 |

> You pay per address verified. Apify's platform fee (20%) is included in the per-email rate, and a job that fails on the verification side is refunded automatically.

#### How the price compares

| Service | Per 1,000 validations |
|---|---:|
| **Email Verifier (this Actor)** | **$0.30** |
| ZeroBounce | $1.50 – $4.00 |
| NeverBounce | $0.80 – $2.00 |
| Hunter | $1.00 |
| Snovio | $0.50 |

Competitor rates are list prices at the time of writing and change over time — check them before you switch.

***

### How to use it

#### Option 1 — Apify Console (no code)

1. Open the [Actor](https://apify.com/cold_email_master/bulk-email-verifier-validator) in your browser.
2. Paste your list, or drop in a link to your CSV.
3. Click **Start**.
4. Wait for the run to finish — the log shows live progress (see [How long a run takes](#how-long-a-run-takes)).
5. Download the results as CSV or JSON from the **Output** tab.

#### Option 2 — Apify API (sync run, single HTTP call)

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/cold_email_master~bulk-email-verifier-validator/run-sync-get-dataset-items?token=<your-token>" \
  -H "Content-Type: application/json" \
  -d '{"emails":["founder@stripe.com","sales@shopify.com"]}'
```

You'll get the verified records back in one HTTP response.

#### Option 3 — Apify API client (Node.js)

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<your-token>' });

const run = await client.actor('cold_email_master/bulk-email-verifier-validator').call({
  emailFileUrl: 'https://example.com/leads-export.csv'
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

***

### How long a run takes

Verification is **asynchronous**. The Actor submits your whole list as one job, the verification service works through it server-side, and the Actor polls until it finishes — nothing holds a connection open, so there is no request-size ceiling and no batching to think about.

Throughput depends on the list: addresses at fast, well-known providers resolve quickly, while slow or dead domains have to time out. Watch the progress line in the log:

```
INFO Job 8f1c…c92 accepted: 5000 address(es), 5000 credit(s) reserved, 20000 remaining.
INFO Verifying… 34% (1700/5000)
```

**Set the run timeout to cover the job.** Apify's default is 300 seconds. The Actor waits for a job for up to six hours, but the run's own timeout is the real limit — raise it in the run options before starting a large list.

Credits are reserved when the job is submitted and **refunded automatically if the job fails**, so a failed job costs you nothing.

***

### FAQ

**Q: Why is this cheaper than every other verification service?**
A: We don't run our own SMTP infrastructure. Verimailx handles the SMTP handshakes at scale, and we pass their cost straight through with a thin margin.

**Q: Do you actually verify addresses on catch-all domains?**
A: Yes, for **B2B** catch-all domains. A catch-all domain accepts mail for any address, which is why most verifiers give up and label the whole domain risky — leaving you to guess on every address behind it. Verimailx resolves the individual mailbox on business domains, so a real address comes back `valid` and a fake one comes back `invalid`. Consumer (B2C) catch-alls are **not** in scope, and any address that can't be resolved comes back `risky` with `catchAll` set to true — so you always know which is which rather than being handed a false positive.

**Q: Will this work for my cold outreach list?**
A: Yes. Drop your CSV in, get back a clean list. Use `overall = valid` for safe sends and `risky` for manual review.

**Q: What about GDPR / data retention?**
A: Email addresses are not stored beyond the run's default dataset lifetime (configurable in your Apify account). The Actor does not log emails to any persistent storage outside Apify.

**Q: Can I get a refund if the Actor errors?**
A: Yes. Any email that fails to validate (due to network errors, upstream API issues, etc.) is recorded as `overall: "error"` in the output and is **not billed**. You only pay for successful validations.

**Q: Does the Actor support IPv6 / IDN domains?**
A: Yes — Verimailx handles both. Submit `[email protected]` or `[email protected]` and they'll be processed normally.

**Q: How do I verify a CSV of emails?**
A: Upload the CSV somewhere with a public link — a Google Sheets CSV export or an S3 object both work — and pass that link as `emailFileUrl`. Every address in the file is picked up regardless of which column holds it, so there's no need to reshape your export first. Files up to 10 MB.

**Q: Does this Actor send any email?**
A: No. Verification stops at the SMTP handshake, which asks the receiving server whether the mailbox exists without ever delivering a message. Nobody on your list is contacted.

**Q: Can I run it on the output of a scraper?**
A: Yes — pass the scraper run's `datasetId` and the Actor reads the addresses straight out of it, no export step in between.

***

### Support

- **Issues with this Actor:** open an issue in this repository
- **Bulk pricing (100k+ emails):** contact us through Apify messaging
- **Verimailx API questions:** see [api.verimailx.com](https://api.verimailx.com)

***

### Changelog

#### 0.3.0 — Paid plan required

- Runs started by users on a free Apify plan now exit immediately with a status message pointing to the [free edition](https://apify.com/cold_email_master/free-email-verifier), instead of verifying addresses the developer is never paid for. Nothing is verified and nothing is charged, and the run finishes as **succeeded** rather than failed, because this is a pricing boundary and not an error.
- The check fails open: it treats a caller as free-plan only when the platform explicitly says so, so a missing or changed platform flag can never lock out paying customers.

#### 0.2.0 — B2B catch-all addresses are now verified

- The verification service resolves individual mailboxes behind **B2B** catch-all domains, so a real address on one now returns **`valid`** and a fake one returns **`invalid`**, instead of the whole domain being written off as `risky`. Consumer (B2C) catch-alls remain out of scope and still return `risky`; `catchAll` is true for anything that could not be resolved.
- Output field documentation corrected: the records have been flat since 0.1.x, but this README still described the old nested `mx.*`, `smtp.*` and `flags.*` shape and a `raw` column that no longer exists.
- Large jobs are no longer abandoned ~35 seconds after submission while the service is still registering them. A job that has never been seen now gets a five-minute grace window; one that disappears after being reported still fails fast.

#### 0.1.0 — Asynchronous verification

- Rewritten for the async bulk API. The Actor now submits the entire list in one request, receives a `job_id`, polls for progress, and downloads the signed results file when the job completes. **All batching, splitting and retry logic is gone** — it existed only to dodge the old 150-second gateway timeout, which no longer applies.
- Live progress is logged as the job runs.
- Credits are reserved at submission and refunded by the service if a job fails.
- `catch_all`, `disposable` and `role_based` now map to **risky**. An address behind a catch-all domain cannot be confirmed, and that is the distinction that decides whether it is safe to send to.
- Each record now carries a `raw` field holding the results-file row exactly as returned, so no column is lost.
- The `batchSize` input is removed; it no longer means anything.

#### 0.0.7 — Batch sizing and error handling

- Batches are now **20 addresses** by default, not 1,000. The verification service drops any single request idle for 150 seconds, and at ~5s per address a 1,000-address request could never complete — it returned `504 IDLE_TIMEOUT` every time. A `batchSize` input allows up to 40.
- Requests carry a 140-second client-side timeout, and a batch that times out is **split in half and retried** instead of failing outright.
- Error records now carry the same field shape as every other record. Previously they were rejected by the dataset schema, which threw mid-run and discarded every result gathered up to that point.
- A run where nothing could be verified now **fails** instead of reporting success with an empty dataset.
- Every dataset write is guarded, so one rejected record can no longer end the run.
- README run-time expectations corrected: the old "5–30 seconds per 1,000 emails" claim was wrong by three orders of magnitude.

#### 0.0.6 — Input flexibility and honest billing

- Added three new ways to supply addresses: a single `email`, a link to a CSV or TXT file (`emailFileUrl`), and an existing Apify dataset (`datasetId` / `datasetField`). Sources can be combined and are de-duplicated together.
- The Actor now charges the **Email Verified** event for each address that reaches a real verdict. Previously the event was defined but never fired, so full verifications were delivered without being billed.
- Syntax-only runs (no API key configured) and failed batches are explicitly **not charged**, and syntax-only records carry a `warning` field saying which checks were skipped.
- Empty input now fails with a message naming the four accepted input fields instead of exiting quietly.

#### 0.0.5 — Apify QA hardening

- Added `default` and `prefill` to the input schema so the Apify Store automated test always has a valid email to validate.
- When `APIFY-VERIMAILX-API-KEY` is not set, the Actor now falls back to **local syntax-only validation** instead of failing. This means the Actor produces a useful result (and passes the QA test) even without credentials.
- Output records now include a `validationMode` field (`full` or `syntax-only`) so consumers can tell which checks were actually performed.
- `mx.passed`, `smtp.passed`, and the `flags.*` fields are now nullable in the dataset schema to reflect the syntax-only path.

#### 0.0.4 — Schema release

- Added `output_schema.json` and `dataset_schema.json` for proper Apify Output tab rendering.

#### 0.0.3 — Schema fix

- Fixed `environmentVariables` shape in `actor.json` (object, not array).

#### 0.0.2 — Verimailx integration

- Replaced in-process SMTP/MX with calls to the Verimailx `/bulk-validate` API.
- Added batched processing (up to 1,000 per request) and per-batch error isolation.

#### 0.0.1 — Initial release

- Regex + DNS MX + simulated SMTP handshake.

***

**Made with care for the Apify community.** Star ⭐ this Actor if it saved you a few bucks on your cold outreach cleanup.

# Actor input Schema

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

Paste or type the addresses to verify. Duplicates are removed automatically. The whole list is submitted as one job and verified server-side.

## `email` (type: `string`):

Verify just one address. Handy for testing, or for calling the Actor once per record from an automation.

## `emailFileUrl` (type: `string`):

A public link to a .csv or .txt file containing your list — a Google Sheets CSV export, an S3 object, a Dropbox direct link. Every address in the file is picked up regardless of which column it sits in, so you can upload your export untouched. Maximum 10 MB.

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

Verify the addresses inside a dataset produced by another Actor — chain this straight onto a scraper without exporting anything in between.

## `datasetField` (type: `string`):

Which field in each dataset record contains the email address, for example "email" or "contactEmail". Leave this empty and every text field on the record is scanned instead.

## Actor input object example

```json
{
  "emails": [
    "someone@example.com"
  ],
  "email": "someone@example.com",
  "emailFileUrl": "https://example.com/my-list.csv",
  "datasetField": "email"
}
```

# Actor output Schema

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

Per-email verification results. One item per address submitted in the input.

# 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": [
        "someone@example.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("cold_email_master/email-verifier-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": ["someone@example.com"] }

# Run the Actor and wait for it to finish
run = client.actor("cold_email_master/email-verifier-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": [
    "someone@example.com"
  ]
}' |
apify call cold_email_master/email-verifier-validator --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,cold_email_master/email-verifier-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/3hdPFlUzNF2aHt1mF/builds/FAmDZ4hUo9CNc2XTP/openapi.json
