# Email Deliverability Checker (`arched_friend/email-deliverability-checker`) Actor

Check whether a domain can actually send email that lands. SPF, DKIM, DMARC, MX and BIMI read straight from DNS, with a score and a plain language list of what is missing or misconfigured.

- **URL**: https://apify.com/arched\_friend/email-deliverability-checker.md
- **Developed by:** [Peach O](https://apify.com/arched_friend) (community)
- **Categories:** Developer tools, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

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

## Email Deliverability Checker: SPF, DKIM And DMARC For Any Domain

**Find out whether a domain can send email that actually lands, and exactly what is stopping it.**

Mail that fails authentication goes to spam or gets rejected outright, and the sender is the last to know. Gmail and Yahoo now require SPF, DKIM and DMARC from anyone sending in volume, so a missing record is not a best practice question any more. It is the difference between the inbox and nothing.

Give this a list of domains and get the full authentication setup for each one: SPF with its policy and lookup count, DKIM keys on every selector worth probing, DMARC with its policy and reporting addresses, MX with the mail platform behind it, plus BIMI and MTA-STS. Every row carries a score out of 100 and a plain list of what is wrong.

Built for deliverability consultants auditing a client list, agencies onboarding new accounts, sales teams checking a prospect's setup before pitching an email product, and anyone responsible for more domains than they can remember.

### How it works

```mermaid
flowchart LR
    A[Domains or email addresses] --> B[Read the domain]
    B --> C[MX records]
    B --> D[TXT at the apex<br/>for SPF]
    B --> E[_dmarc TXT]
    B --> F[Probe DKIM selectors]
    B --> G[BIMI and MTA-STS]
    C --> H[Parse and score]
    D --> H
    E --> H
    F --> H
    G --> H
    H --> I[(One row per domain<br/>with a score and issues)]
```

Everything comes from DNS. There is no scraping, no API key, no rate limit worth managing, and no mail is ever sent to anyone.

### What you get

One row per domain. A real row from a live run:

```json
{
  "domain": "stripe.com",
  "status": "ok",
  "score": 97,
  "issues": [],
  "acceptsEmail": true,
  "mailProvider": "Google Workspace",
  "mxHosts": ["aspmx.l.google.com", "alt1.aspmx.l.google.com"],
  "spfPresent": true,
  "spfPolicy": "softfail",
  "spfLookupCount": 3,
  "spfIncludes": ["spf1.stripe.com", "_spf.qualtrics.com"],
  "dkimFound": true,
  "dkimSelectors": ["google", "mandrill", "s1", "s2"],
  "dmarcPresent": true,
  "dmarcPolicy": "reject",
  "dmarcReporting": true,
  "dmarcReportingAddresses": ["mailto:dmarc-reports@stripe.com"],
  "bimiPresent": false,
  "mtaStsPresent": false,
  "checkedAt": "2026-09-08T09:12:04.881Z"
}
```

And a domain that needs work:

```json
{
  "domain": "example.net",
  "status": "critical",
  "score": 0,
  "issues": [
    "No SPF record, so receivers cannot tell which servers may send for this domain",
    "No DMARC record, so nothing tells receivers what to do with mail that fails authentication",
    "No DKIM key found on any common selector",
    "No MX records, so this domain cannot receive email"
  ]
}
```

### What the checks catch

Presence is the easy half. These are the failures that a simple "is there an SPF record" check reports as healthy.

| Problem | Why it matters |
| --- | --- |
| Two SPF records | Receivers treat it as a permanent error and ignore SPF completely, so publishing a second one turns protection off |
| SPF over 10 DNS lookups | The limit is in the spec. Past it, evaluation stops and the check fails no matter how correct the record reads |
| SPF ending in `+all` | Authorises the entire internet to send as the domain |
| DKIM key revoked | An empty `p=` tag means the key is withdrawn. The selector answers, so a naive check counts it as working |
| DMARC `p=none` | Monitors and blocks nothing, which is a staging post rather than protection |
| DMARC with no `rua` | No reports come back, so failures stay invisible |
| DMARC `pct` below 100 | The policy only applies to a share of mail |

### Scores and status

`score` is a number out of 100 for sorting a long list. `status` is the verdict: `ok`, `warning`, `critical`, or `error` when the domain does not resolve at all. A domain that resolves but publishes nothing is `critical`, not an error, because the answer is real and actionable.

### Example input

```json
{
  "domains": [
    "example.com",
    "sales@prospect.com",
    "https://clientsite.co.uk"
  ],
  "extraDkimSelectors": ["mycustomselector"],
  "onlyProblems": true
}
```

Email addresses are accepted directly, so a list pulled from a CRM needs no cleaning first.

### Run it from the command line

```bash
curl -X POST "https://api.apify.com/v2/acts/arched_friend~email-deliverability-checker/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "domains": ["example.com", "prospect.com"],
    "onlyProblems": true
  }'
```

### Pricing

$0.004 per domain checked, covering every record on that domain.

| | This Actor | Deliverability SaaS | Manual `dig` |
| --- | --- | --- | --- |
| 500 domains | $2 | $50 to $200 a month | A day of work |
| DKIM selector discovery | Yes, 31 selectors | Usually | One at a time |
| Revoked key detection | Yes | Rarely | Only if you read the record |
| SPF lookup limit check | Yes | Sometimes | By hand |
| Bulk lists | Paste and run | Often one domain at a time | |

### Notes and limits

- **DKIM absence cannot be proven.** DKIM has no discovery mechanism, so the only way to find a key is to guess the selector. This probes 31 selectors covering the common platforms, and you can add your own. A domain with a private selector and no match reports `dkimFound: false`, which means "none of the selectors probed answered", not "this domain has no DKIM".
- Records are read live from DNS on every run, so a change shows up as soon as it has propagated.
- Nothing here sends mail or connects to a mail server, so no prospect is ever contacted by the check itself.

### Related products

- **Email List Cleaner** for validating the addresses you are about to send to.
- **Domain & SSL Expiry Monitor** for the registration and certificate side of the same domain list.
- **Website Lead Extractor** for pulling contact details off the sites behind those domains.

# Actor input Schema

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

The domains to check, one per line. A bare domain, a full URL or an email address all work, so example.com, https://example.com and sales@example.com are all accepted.

## `extraDkimSelectors` (type: `array`):

Additional DKIM selectors to probe on top of the built in list of common ones. DKIM has no discovery mechanism, so a custom selector can only be found if you name it here.

## `onlyProblems` (type: `boolean`):

Drop every domain that passes every check and return only the rows with a warning, a critical issue or an error.

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

How many domains to look up at once. These are plain DNS queries, so this can go higher than a scraping Actor without trouble.

## `timeoutSeconds` (type: `integer`):

How long to wait for a DNS answer before giving up on that record and moving on.

## Actor input object example

```json
{
  "domains": [
    "example.com",
    "stripe.com",
    "bbc.co.uk"
  ],
  "onlyProblems": false,
  "concurrency": 5,
  "timeoutSeconds": 15
}
```

# Actor output Schema

## `domains` (type: `string`):

One row per domain, with the SPF, DKIM and DMARC setup, the mail provider, a score out of 100 and every issue found.

## `runSummary` (type: `string`):

Adoption counts for SPF, DKIM and DMARC, how many domains enforce a policy, the mail providers in use and the worst scoring domains.

# 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 = {
    "domains": [
        "example.com",
        "stripe.com",
        "bbc.co.uk"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("arched_friend/email-deliverability-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 = { "domains": [
        "example.com",
        "stripe.com",
        "bbc.co.uk",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("arched_friend/email-deliverability-checker").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 '{
  "domains": [
    "example.com",
    "stripe.com",
    "bbc.co.uk"
  ]
}' |
apify call arched_friend/email-deliverability-checker --silent --output-dataset

```

## MCP server setup

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

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/69cFU5povIge6RQWW/builds/bOjPbPddIo8H76lHs/openapi.json
