# Email Verification API - Bulk Validation and Email Finder (`nabeelbaghoor/email-verification-api`) Actor

Verify email addresses in bulk with SMTP, MX and catch-all checks, get the verdict and the reason code behind it, append the name, gender and location on the address, find a named person's work address, and detect the email pattern a company uses. Pay per result. Bring your own API key.

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

## Pricing

$10.00 / 1,000 results

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Email Verification API - Bulk Validation and Email Finder

Verify a list of email addresses for deliverability, get both the verdict and the reason code behind it, append the name, gender and location sitting on each address, find a named person's work address at a company, and detect the address pattern a company uses without needing any name at all. One flat row per address, person or domain.

### What this actor does

- **Validates in bulk, not one at a time.** Addresses are sent to the provider's bulk endpoint in batches of up to 100, so a ten thousand address list is a hundred requests rather than ten thousand. Batch results are matched back to your input by address, not by position, so an address the provider refuses never shifts the rest of the list onto the wrong rows.
- **Returns the reason, not just the verdict.** Every row carries the verdict and the reason code under it, which is what separates a temporary greylist or an unresponsive mail server from a mailbox that genuinely does not exist. Twenty six reason codes are exposed as a filter.
- **Appends the identity behind the address.** Validation returns the first name, last name, gender, city, region, postcode and country the provider holds for the address, along with domain age, the SMTP provider, the MX record, the catch-all flag and the free mailbox flag.
- **Finds a named person's work address.** Give the finder a list of names and a list of companies, by domain or by company name, and it pairs them up, returning the address with a confidence band of high, medium or low.
- **Detects a company's email pattern.** Domain search returns the pattern a company uses, such as first dot last, with a confidence band and every runner-up pattern the provider considered. No name needed.
- **Answers the question of who is still active.** The activity route returns how recently an address was seen engaging with email, which is how you retire a list without guessing.
- **Runs against the region you need.** The default, United States and European Union deployments are all selectable, so a request can be kept inside a region when your data protection policy requires it.
- **Keeps the key out of every log line.** This provider accepts the key only as a request parameter, never as a header, so the actor makes sure the real URL is never written to a log.
- **Never charges for a miss.** Only rows carrying a resolved result are billed.

### Input

| Field | What it does |
| --- | --- |
| `mode` | Validate, email finder, domain search or activity. |
| `emails` | Addresses to validate or check activity for. |
| `ipAddresses` | Optional signup IPs, in the same order, to add geography. |
| `domains` | Company domains for the finder and domain search. |
| `companyNames` | Company names, for when you have the employer but not the domain. |
| `fullNames` | Names to find addresses for. Paired with each company. |
| `statuses` | Keep only these verdicts. |
| `subStatuses` | Keep only these reason codes. |
| `excludeFreeEmail` | Drop free consumer mailboxes. |
| `requireMxRecord` | Keep only domains that can receive mail at all. |
| `region` | Default, United States or European Union endpoint. |
| `batchSize` | Addresses per bulk validation request, up to 100. |
| `requestsPerMinute` | Pace the run under your plan's rate limit. |
| `skipNotFound` | Leave unresolved inputs out of the dataset. |
| `maxResults` | Hard cap on rows, and therefore on spend and run time. |
| `apiKey` | Your own API key. Stored as a secret. |

### Example output

```json
{
  "found": true,
  "mode": "validate",
  "query": "jane.doe@example.com",
  "email": "jane.doe@example.com",
  "status": "valid",
  "subStatus": null,
  "account": "jane.doe",
  "domain": "example.com",
  "didYouMean": null,
  "domainAgeDays": 9092,
  "freeEmail": false,
  "mxFound": true,
  "mxRecord": "mx.example.com",
  "smtpProvider": "example",
  "catchAllDomain": false,
  "firstName": "Jane",
  "lastName": "Doe",
  "fullName": "Jane Doe",
  "gender": "female",
  "city": "San Francisco",
  "region": "California",
  "zipCode": "94105",
  "country": "United States",
  "activeInDays": 30,
  "activeFirstSeen": "2019-03-14",
  "processedAt": "2026-08-14 09:12:41.113",
  "error": null,
  "raw": { }
}
```

### Frequently asked questions

#### What does an email verification API actually check?

It checks whether a mailbox can receive mail, in layers. The address is checked for syntax, the domain is checked for mail exchanger records, and the mailbox itself is probed over SMTP. On top of that the provider applies its own lists to catch spam traps, known complainers, disposable providers and role addresses. Each row returns the verdict of that whole process plus the reason code that decided it, along with the domain age, the SMTP provider, the MX record, the catch-all flag and the free mailbox flag.

#### What is the difference between the verdict and the reason code?

The verdict is one of valid, invalid, catch-all, unknown, spam trap, abuse or do not mail. The reason code is the detail underneath it, and it is where the useful decisions live. Two addresses can both come back as unknown when one was greylisted and will verify fine on a retry, while the other sits behind a mail server that never responded. Filtering on the reason code lets you retry the first group and drop the second.

#### How do I clean a list so it is safe to send to?

Run validate, set the verdict filter to valid, and turn on require a valid MX record. That leaves only addresses whose mailbox was confirmed and whose domain can receive mail. Add the drop free consumer mailboxes option when the list is meant for B2B outreach. If you would rather review catch-all domains yourself than lose them, add catch-all to the verdict filter and decide per domain, since a catch-all domain accepts everything and tells you nothing about the individual mailbox.

#### Can it find an email address, not just check one?

Yes, in two ways. The email finder takes a person's full name plus their employer, either as a domain or as a company name, and returns the most likely work address with a confidence band of high, medium or low. Domain search skips the person entirely and returns the address pattern the company uses, such as first dot last, with every runner-up pattern and its own confidence, which is what you want when you have a list of names and one company.

#### What does the activity data tell me?

It returns how recently the provider last saw that address engaging with email, expressed in days. It is the cheapest way to retire an aging list: an address can be perfectly valid and still belong to someone who has not opened a message in two years, and no amount of SMTP checking will tell you that.

#### Which regional endpoint should I use?

Use the default endpoint unless you have a reason not to. Choose the United States or European Union endpoint when your account is provisioned in that region, or when a data protection obligation means the addresses you are checking must not be processed outside it. All three deployments answer the same routes and return the same fields.

#### Do I need my own API key?

Yes. This actor does not include data access. You use your own API key from ZeroBounce, which is the provider whose email validation API this actor calls, created on their dashboard. Your own plan, credit balance and terms apply. Paste the key into the `apiKey` field, where it is stored as an Apify secret. This provider accepts the key only as a request parameter and not as a header, so the actor makes sure the real request URL never reaches a log line.

#### How does this handle rate limits and spent credits?

Requests are spaced evenly across the minute so a long list does not bunch up against the limiter, and the pace is yours to set. A rate limit response is retried with backoff, because it clears on its own. A spent credit balance is treated differently: the provider reports it inside an otherwise successful response, the actor recognises it, and the run stops with what it has rather than burning retries on a balance that waiting will not refill.

#### What happens when an address or a domain returns nothing?

The row is written with `found: false` and an `error` giving the provider's own reason, and the run continues to the next input. For the finder and domain search that reason is the provider's failure code, which distinguishes a free mailbox domain from a company the provider simply has no data for. Misses are not charged for. Set `skipNotFound` to true to leave them out of the dataset entirely.

#### How much does a run cost?

Pricing is pay per result: you are charged for each address, person or domain resolved into the dataset, and never for misses, for rows dropped by the verdict filters, or for duplicates. Apify platform usage is included in the per-result price. Your own API provider's credit balance is separate and billed by them.

### Keyword map

email verification API, email validation API, bulk email verifier, email list cleaning, SMTP verification, MX record check, catch-all domain detection, disposable email detection, spam trap detection, role based email detection, email deliverability check, bounce rate reduction, email finder API, find email by name, company email pattern, domain search API, email activity data, list hygiene, B2B contact data, sales prospecting data

# Actor input Schema

## `mode` (type: `string`):

Validate checks a list of addresses for deliverability and appends the identity behind each one. Email finder works out one named person's address at a company. Domain search returns the address pattern a company uses, without needing any name. Activity returns how recently an address was seen engaging with email.

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

Email addresses, one per line. Used by validation and by the activity route. An address pasted inside a longer string, such as a mail header or a name and address pair, is extracted before the request.

## `ipAddresses` (type: `array`):

Optional IP addresses the matching address signed up from, one per line, in the same order as the addresses above. The provider uses them to add geography to the record. Leave empty when you do not have them. Validation only.

## `domains` (type: `array`):

Company domains, one per line. Used by the email finder and domain search. A pasted URL is reduced to the bare hostname and an address is reduced to the part after the at sign, so a messy list still works.

## `companyNames` (type: `array`):

Company names, one per line, for when you know who the employer is but not their domain. The provider resolves the name to a domain first. Used by the email finder and domain search, and combined with the domains above rather than replacing them.

## `fullNames` (type: `array`):

Full names to find addresses for, one per line. Each name is paired with each company above: ten names and one company is ten lookups. A middle name is understood, and the last word is treated as the surname. Email finder only.

## `statuses` (type: `array`):

Only keep addresses with these verdicts. Restricting to valid is how you turn a raw list into one that is safe to send to. Leave empty to keep every verdict. Validation only, and applied after the provider answers, so it reduces dataset noise and Apify spend rather than provider credits.

## `subStatuses` (type: `array`):

Only keep addresses whose reason code is one of these. The reason code is the detail under the verdict, and it is what separates a temporary greylist from a mailbox that genuinely does not exist. Leave empty to keep every reason. Validation only.

## `excludeFreeEmail` (type: `boolean`):

Leave out addresses on free consumer providers such as the large webmail services, keeping only company addresses. Useful when the list is meant for B2B outreach. Validation only.

## `requireMxRecord` (type: `boolean`):

Only keep addresses whose domain publishes a mail exchanger record, which means the domain can receive mail at all. A quick way to drop parked and abandoned domains. Validation only.

## `region` (type: `string`):

Which of the provider's regional deployments to call. Pick the US or EU deployment when your account or your data protection policy requires the request to stay in that region. The default deployment is correct for most accounts.

## `batchSize` (type: `integer`):

How many addresses to validate in one request against the provider's bulk endpoint. Larger batches mean far fewer requests for a big list. Validation only.

## `requestsPerMinute` (type: `integer`):

Pace the run so it stays under whatever rate your plan allows. Lower this if the provider starts returning rate limit responses; raise it to finish a long list sooner.

## `skipNotFound` (type: `boolean`):

Leave inputs the provider had nothing for out of the dataset. Off by default, because keeping the misses is what lets you see which inputs resolved and which did not. Misses are never charged for either way.

## `maxResults` (type: `integer`):

Stop after this many rows. This is the cap on both spend and run time.

## `apiKey` (type: `string`):

Your own API key for the email validation API. This provider accepts the key only as a request parameter, so the actor keeps it out of every log line instead. Required for every lookup. Stored as a secret.

## Actor input object example

```json
{
  "mode": "validate",
  "emails": [
    "jane@stripe.com"
  ],
  "statuses": [],
  "subStatuses": [],
  "excludeFreeEmail": false,
  "requireMxRecord": false,
  "region": "default",
  "batchSize": 100,
  "requestsPerMinute": 300,
  "skipNotFound": false,
  "maxResults": 100
}
```

# Actor output Schema

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

Verified addresses, found addresses and detected email patterns, one row each.

# 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@stripe.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("nabeelbaghoor/email-verification-api").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@stripe.com"] }

# Run the Actor and wait for it to finish
run = client.actor("nabeelbaghoor/email-verification-api").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@stripe.com"
  ]
}' |
apify call nabeelbaghoor/email-verification-api --silent --output-dataset

```

## MCP server setup

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

```

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/m4LHc4tOoQ6UJr5yV/builds/2VodqLeDocOLZPshO/openapi.json
