# Email & Domain Auth Checker: MX, SPF, DKIM & DMARC (`apifmcpfactory/email-domain-checker`) Actor

Checks an email or domain's deliverability signals from DNS alone: MX, SPF, DKIM, DMARC, plus disposable and role-address flags. No SMTP, no mailbox ping. It reports auth-record posture, not mailbox existence. $0.005 per input checked.

- **URL**: https://apify.com/apifmcpfactory/email-domain-checker.md
- **Developed by:** [Howth Technology Factory](https://apify.com/apifmcpfactory) (community)
- **Categories:** Developer tools, Agents
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 input 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/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

Check whether an email address or domain is set up to send and receive mail properly — MX, SPF, DKIM and DMARC — using DNS alone. It reports the domain's authentication posture, which is a different and more reliable question than whether one particular mailbox exists.

### 1. Why use Email & Domain Auth Checker

Two problems get confused with each other. The first is "will mail to this address bounce". The second is "is this domain configured so its own mail reaches inboxes rather than spam folders". They have different answers and different fixes.

Mailbox-existence checks try to answer the first by opening an SMTP conversation with the receiving server. Most large providers deliberately give unreliable answers to that, and being seen probing mailboxes is itself reputationally costly.

The second question is answerable from public DNS, definitively, with no probing at all. A domain with no SPF record, or a DMARC policy set to `none`, has a measurable deliverability problem you can act on. This Actor answers that question — for your own domains, or for a list you are cleaning before import.

### 2. Key features

- **DNS only.** No SMTP conversation, no mailbox probing, nothing that could affect your sending reputation.
- **Five typed statuses** that separate "no mail records" from "DNS itself failed" — a timeout is never reported as a missing record.
- **RFC 7505 null-MX handling.** A domain that explicitly declares it accepts no mail is identified as such, not as a lookup failure.
- **SPF with policy qualifier.** Reports not just presence but the qualifier on the `all` mechanism — the difference between a strict and a permissive record.
- **DMARC with policy.** Reports `none`, `quarantine` or `reject`, which is what actually determines enforcement.
- **DKIM selector checking**, with your own selector supported.
- **Disposable and role-address flags** for throwaway domains and addresses like `info@` or `admin@`.
- **Plain-language summary** per result, alongside the structured fields.
- **Bulk checking** of a whole list in one run.

### 3. Who it's for

**For marketing and email operations.** Before a campaign, check your own sending domains and confirm SPF is strict and DMARC is enforcing rather than `none` — the two settings most often left permissive after an initial setup.

**For sales and revenue operations.** Clean a purchased or imported lead list: flag disposable domains and role addresses before they enter the CRM and depress your deliverability metrics.

**For IT and security.** Audit every domain your organisation owns, including the parked ones. A domain with no DMARC record is a spoofing opportunity whether or not it sends mail.

**For developers and AI agents.** Call it at signup: branch on `status` and `disposable` to decide whether to accept, challenge or reject a registration, without ever touching SMTP.

### 4. How to use it

1. Open the Actor and click **Try for free**.
2. Put emails or bare domains in the **Inputs** field, one per line. Both forms work.
3. Optionally set a **DKIM selector** if you know the one your provider uses.
4. Click **Start**.
5. Open the **Output** tab. Filter on `status` or `disposable` to isolate problems.

### 5. Input parameters

| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| `inputs` | array of strings | Yes | `["user@google.com","mailinator.com"]` | Emails or bare domains to check. Both forms accepted; an email is reduced to its domain for the DNS checks. |
| `dkimSelector` | string | No | — | A DKIM selector to check. DKIM has no DNS-discoverable selector directory, so without this only a handful of common selectors are tried. |

### 6. Output

```json
{
  "input": "user@example.com",
  "domain": "example.com",
  "status": "OK",
  "syntaxValid": true,
  "hasMX": true,
  "mxHosts": ["aspmx.l.google.com", "alt1.aspmx.l.google.com"],
  "disposable": false,
  "roleAddress": false,
  "spf": { "present": true, "record": "v=spf1 include:_spf.google.com ~all", "policy": "~all" },
  "dmarc": { "present": true, "record": "v=DMARC1; p=quarantine", "policy": "quarantine" },
  "dkim": { "selectorsChecked": ["google", "default", "selector1"], "found": ["google"] },
  "summary": "Accepts mail. SPF present (soft fail). DMARC quarantine. DKIM found."
}
```

Every input produces exactly one result.

### 7. Output fields

| Field | Meaning |
|---|---|
| `input` | The email or domain exactly as supplied. |
| `domain` | The domain the checks ran against. For an email, the part after the `@`. |
| `status` | Overall outcome. See below. |
| `syntaxValid` | Whether the input parsed as a valid email or domain. |
| `hasMX` | Whether the domain publishes usable MX records. |
| `mxHosts` | The MX hostnames found. |
| `disposable` | Whether the domain is a known throwaway/temporary mail provider. |
| `roleAddress` | Whether the local part is a role address (`info@`, `admin@`, `support@` and similar) rather than a person. |
| `spf.present` / `spf.record` | Whether an SPF record exists, and its raw text. |
| `spf.policy` | The qualifier on the `all` mechanism: `-all` (hard fail), `~all` (soft fail), `?all` (neutral), `+all` (passes everything — effectively no protection). |
| `dmarc.present` / `dmarc.record` | Whether a DMARC record exists, and its raw text. |
| `dmarc.policy` | `none`, `quarantine` or `reject`. `none` means monitoring only — it does not stop anything. |
| `dkim.selectorsChecked` | Which selectors were queried. |
| `dkim.found` | Which of those returned a key. |
| `summary` | A one-line plain-language reading of the result. |

#### Status values

| Status | Meaning |
|---|---|
| `OK` | The domain accepts mail and every check completed. |
| `INVALID_INPUT` | Could not be parsed as an email or domain. |
| `UNRESOLVABLE` | The domain does not exist at all (NXDOMAIN). |
| `NO_MX` | The domain resolves but publishes no usable MX — including an RFC 7505 "null MX" record, which explicitly declares that it accepts no mail. |
| `LOOKUP_ERROR` | DNS itself failed — a timeout or SERVFAIL. **Never conflated with "no records exist"**; this is the case to retry. |

### 8. How it works

Each input is parsed, and an email is reduced to its domain. MX, SPF (a TXT lookup), DMARC (a TXT lookup at `_dmarc.<domain>`) and DKIM selector records are then queried from DNS.

SPF and DMARC records are parsed rather than merely detected, so the qualifier and the policy are reported rather than a bare present/absent flag. DKIM is checked against a small set of common selectors plus any selector you supply — DNS offers no way to enumerate selectors, which is why supplying yours materially improves that field.

Inputs are processed with a concurrency of 5. A DNS failure is distinguished from an absent record throughout, which is why `LOOKUP_ERROR` exists as a separate status.

### 9. API & MCP usage

**cURL**

```bash
curl -X POST "https://api.apify.com/v2/acts/apifmcpfactory~email-domain-checker/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"inputs":["user@example.com","example.org"]}'
```

**As an Apify MCP tool.** This Actor is callable directly by AI agents such as Claude and Cursor. Usage bills through your own Apify account.

```
https://mcp.apify.com?tools=apifmcpfactory/email-domain-checker
```

Claude Desktop (`claude_desktop_config.json`):

```json
{
    "mcpServers": {
        "email-domain-checker": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com?tools=apifmcpfactory/email-domain-checker",
                "--header",
                "Authorization: Bearer YOUR_APIFY_TOKEN"
            ]
        }
    }
}
```

**As a standalone MCP server.** The same checks run as a dedicated hosted MCP server, with `check_email_domain` for one input and `bulk_check_email_domain` for up to 100. See the product page for that endpoint.

### 10. Pricing

$0.005 per email or domain checked, billed per input written to the dataset. A 1,000-address list costs $5.00.

### 11. Limits & performance

| | |
|---|---|
| Memory | 256 MB |
| Concurrency | 5 inputs in parallel |
| Lookups per input | MX, SPF, DMARC, plus one per DKIM selector |
| Throughput | Bounded by DNS response time |

### 12. Limitations

- **No SMTP verification.** This reports auth-record posture, not mailbox existence. It cannot tell you whether a specific mailbox is real, and deliberately does not try.
- **DKIM selectors cannot be enumerated.** DNS provides no directory of selectors. An empty `dkim.found` means the common selectors did not match — not that DKIM is absent. Supply your own selector for a definitive answer.
- **A valid configuration is not a guarantee of inbox placement.** Content, sending history and recipient-side filtering all matter and are outside DNS.
- **Disposable-domain lists age.** New throwaway providers appear constantly; a `false` means "not on our list".
- **Role-address detection is pattern-based** on the local part, and a real person can legitimately sit behind `sales@`.
- **DNS is a snapshot.** Records change; a result describes the moment it was taken.

### 13. FAQ

**Does this tell me if an email address exists?** No, and that is deliberate. It reports whether the *domain* is configured to accept and authenticate mail. Mailbox existence requires an SMTP probe, which large providers answer unreliably and which can harm your sending reputation.

**Does it check SPF, DKIM and DMARC?** Yes, all three, and it parses them — you get SPF's `all` qualifier and DMARC's policy, not just presence.

**What does an SPF policy of `~all` mean?** Soft fail: unauthorised senders are marked suspicious rather than rejected. `-all` is a hard fail and is stricter. `+all` passes everything and offers effectively no protection.

**My DMARC record exists but mail is still spoofed — why?** Check `dmarc.policy`. A policy of `none` is monitoring only; it reports but does not block. Enforcement requires `quarantine` or `reject`.

**Why is `dkim.found` empty when I know DKIM is set up?** DNS cannot enumerate selectors, so only common ones are tried. Supply your provider's selector in `dkimSelector`.

**What is a null MX?** An RFC 7505 record by which a domain explicitly declares it accepts no mail. It is reported as `NO_MX` — a deliberate configuration, not an error.

**What is the difference between `NO_MX` and `LOOKUP_ERROR`?** `NO_MX` means DNS answered and there are no usable mail records. `LOOKUP_ERROR` means DNS did not answer. The first is a finding; the second is a retry.

**Does it detect disposable email addresses?** Yes, against a bundled list of known throwaway providers, reported as `disposable`.

### GDPR & lawful use

Only public DNS records are queried — no mailbox is contacted, no message is sent, and nothing is stored beyond your own run's dataset. Email addresses supplied as input are reduced to their domain for every check.

### More tools from MCP Factory

- **[IBAN Validator](https://apify.com/apifmcpfactory/iban-validator)** — offline ISO 13616 IBAN checksum and structure validation.
- **[EU VAT Validator](https://apify.com/apifmcpfactory/eu-vat-validator)** — validate EU VAT numbers against the official VIES registry.
- **[Sanctions Screening](https://apify.com/apifmcpfactory/sanctions-screening)** — screen names against official OFAC, EU, UK and UN sanctions lists in bulk.

— A Howth Technology Factory tool. Official sources, nothing stored.

# Actor input Schema

## `inputs` (type: `array`):

Emails or bare domains to check, e.g. "user@example.com" or "example.com". Each entry produces exactly one result item and is billed at $0.005 — up to 1000 per run. Checks are DNS-only (MX, SPF, DKIM, DMARC, disposable/role flags) — no SMTP connection, no mailbox ping. If omitted, two demo inputs are used — always pass your own list.

## `dkimSelector` (type: `string`):

DKIM has no DNS-discoverable selector directory. Without this, a handful of common selectors (google, default, selector1, selector2, k1, dkim, mail) are probed for every input. Set this only if you know the exact selector your domain(s) use — it then replaces the default probe set for every input in this run.

## Actor input object example

```json
{
  "inputs": [
    "user@google.com",
    "mailinator.com"
  ]
}
```

# 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 = {
    "inputs": [
        "user@google.com",
        "mailinator.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("apifmcpfactory/email-domain-checker").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 = { "inputs": [
        "user@google.com",
        "mailinator.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("apifmcpfactory/email-domain-checker").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "inputs": [
    "user@google.com",
    "mailinator.com"
  ]
}' |
apify call apifmcpfactory/email-domain-checker --silent --output-dataset

```

## MCP server setup

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

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/NBrhUOTtygrfx5TnP/builds/T5O52XuJYbNKh3EXg/openapi.json
