# Bulk Email Hygiene & MX Validator (`craigtechservicesllc/bulk-email-hygiene-mx-validator`) Actor

Clean and classify email lists using syntax, DNS/MX, disposable-domain, role-account, free-provider, typo, and duplicate checks without sending email.

- **URL**: https://apify.com/craigtechservicesllc/bulk-email-hygiene-mx-validator.md
- **Developed by:** [Daniel Craig](https://apify.com/craigtechservicesllc) (community)
- **Categories:** Automation, Developer tools, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.55 / 1,000 email checkeds

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?

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

## Bulk Email Hygiene & MX Validator

Clean email lists before importing them into a CRM or permission-based campaign. The Actor accepts pasted addresses, JSON items, or an Apify dataset and returns one evidence-rich row per input.

### What it checks

- deterministic email syntax and length limits
- international domain conversion to ASCII/Punycode
- MX records and the standards-compatible A/AAAA fallback
- explicit Null MX domains that accept no email
- disposable email domains
- common role accounts such as `info`, `sales`, and `support`
- common free email providers
- common provider-domain typos with a suggested correction
- duplicate addresses with the first source-row reference

### Honest boundary

This Actor **does not send email or connect to recipient mail servers**. It does not claim that a mailbox exists, that a message will reach an inbox, or that an address is safe to contact. `valid_domain` means the syntax is valid and the domain publishes mail-receiving evidence. Temporary DNS failures are `unknown`, never silently converted to invalid.

Use only email data you are authorized to process. Compliance with consent, anti-spam, privacy, suppression, and outreach rules remains the user's responsibility.

### Input

Choose exactly one source:

1. `emails`: one address per row.
2. `items`: JSON objects containing the field selected by `emailField`.
3. `datasetId`: a dataset in the current Apify account.

The Actor processes at most `maxItems` rows. Both source truncation and spending-limit truncation are explicit in the `OUTPUT` summary.

### Output statuses

- `valid_domain`: syntax passed and MX or fallback address evidence exists.
- `risky`: domain evidence exists, but the address is disposable, role-based, or contains a likely provider typo.
- `invalid`: syntax failed, the domain explicitly accepts no email, or it has neither MX nor fallback address records.
- `unknown`: the DNS answer was temporarily unavailable or timed out.

Every dataset row includes `mailboxChecked: false` and the claim boundary so downstream automations cannot mistake domain hygiene for mailbox verification.

### Pricing design

The intended Store model is pay per event with one visible `email-checked` event per emitted dataset row and a small Actor-start event. No paid third-party API is used. Platform usage should be passed through or priced with enough margin to avoid owner-funded runs.

### Privacy and security

- Input email addresses are read from the run's own Apify storage.
- No recipient is contacted and no email is sent.
- No paid verification API, tracking service, analytics endpoint, or vendor-operated remote backend receives the list.
- Logs contain only aggregate counts and settings, not individual email addresses.
- The run dataset contains the user's requested row-level results; Apify storage retention and deletion controls apply.

### Automation

After publication, Apify provides Store discovery, input UI, API/MCP access, execution, storage, metering, billing, and payout records. Ongoing work is limited to evidence-based maintenance and support.

# Actor input Schema

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

One email address per row.

## `items` (type: `array`):

Objects containing an email field. Use emailField to select a nested value.

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

Dataset in the current Apify account. Never place an API token in this field.

## `emailField` (type: `string`):

Dot path used for JSON items or dataset rows.

## `maxItems` (type: `integer`):

Hard run limit. If the source contains more rows, the summary explicitly marks truncation.

## `concurrency` (type: `integer`):

Number of domains checked concurrently. Repeated domains share one cached DNS lookup.

## `dnsTimeoutMs` (type: `integer`):

Temporary DNS failures and timeouts are returned as unknown, never silently marked invalid.

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

Checks MX first, then the RFC-compatible A/AAAA fallback when no MX exists.

## `emitUniqueOnly` (type: `boolean`):

When enabled, duplicate rows are counted in the summary but omitted from the dataset.

## Actor input object example

```json
{
  "emails": [
    "contact@example.com",
    "sales@example.org",
    "test@mailinator.com"
  ],
  "emailField": "email",
  "maxItems": 50000,
  "concurrency": 25,
  "dnsTimeoutMs": 5000,
  "checkDns": true,
  "emitUniqueOnly": false
}
```

# Actor output Schema

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

Dataset rows containing syntax, DNS/MX, risk, typo, and duplicate evidence.

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

Counts, source truncation, effective settings, and the mailbox-deliverability claim boundary.

# 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": [
        "contact@example.com",
        "sales@example.org",
        "test@mailinator.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("craigtechservicesllc/bulk-email-hygiene-mx-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": [
        "contact@example.com",
        "sales@example.org",
        "test@mailinator.com",
    ] }

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

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,craigtechservicesllc/bulk-email-hygiene-mx-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/4secjo2P9lNrKPh7e/builds/UaBAbJvb5DpcDc7F3/openapi.json
