# Email Deliverability Checker — SPF, DKIM, DMARC & MX (`hoanglongteam/email-deliverability-checker`) Actor

Bulk-check domains for email deliverability and spoofing protection: MX, SPF (with 10-lookup count), DMARC policy, DKIM selectors, BIMI, MTA-STS, TLS-RPT and blocklists. One row per domain with a 0–100 score and plain-English fixes.

- **URL**: https://apify.com/hoanglongteam/email-deliverability-checker.md
- **Developed by:** [LONG HOÀNG](https://apify.com/hoanglongteam) (community)
- **Categories:** Marketing, Developer tools, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $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?

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 Deliverability Checker — SPF, DKIM, DMARC, MX, BIMI, MTA-STS

Check **hundreds of domains in one run** and get **one row per domain** with a **0–100 deliverability score**, a letter grade,
and a **plain-English list of what to fix**.

### What it checks

- **MX**: mail servers, priority, null MX (RFC 7505), A-record fallback, MX hosts that don't resolve, detected **email provider**
  (Google Workspace, Microsoft 365, Zoho, Proofpoint, Mimecast, Fastmail, Proton, Yahoo …)
- **SPF**: parses the record, **counts DNS lookups recursively against the 10-lookup limit**, void lookups, broken includes,
  multiple SPF records, `+all` / `?all` / `~all` / `-all` (follows `redirect=`), deprecated `ptr`, invalid terms
- **DMARC**: policy `p=`, `sp=`, `pct=`, alignment, whether `rua`/`ruf` reporting is set (reporting **domains** only — addresses are redacted),
  fallback to the organizational domain
- **DKIM**: tries common selectors (`default, google, selector1, selector2, k1, s1, s2, mail, dkim`) plus any you add;
  reports key type, **RSA key size** and revoked keys
- **BIMI**: record, logo URL, whether a VMC certificate is referenced
- **MTA-STS**: DNS record **and** the policy file (`mode: enforce / testing / none`); **TLS-RPT** record
- **Blocklists**: mail-server IPs checked on public IP blocklists whose terms allow automated lookups (SpamCop, PSBL)

### Who it's for

- **Cold-email & outbound teams** auditing sending domains before a campaign
- **Agencies / MSPs** auditing client portfolios for spoofing risk and Gmail/Yahoo bulk-sender requirements
- **Lead-gen**: find companies with `p=none` or no DMARC, sorted by score

### Input

```json
{ "domains": ["example.com", "https://www.shop.example.com"], "extraDkimSelectors": ["mandrill"], "checkBlocklists": true,
  "maxConcurrency": 10, "timeoutSecs": 20 }
```

URLs are reduced to the hostname, a leading `www.` is removed, duplicates are removed.
Invalid or non-existent domains are returned with `error` and **not charged**.

### Output (one item per domain)

`domain, deliverabilityScore, grade, issuesCount, issues[], emailProvider, acceptsMail, nullMx, mxRecords[],
spfRecord, spfAll, spfLookups, spfVoidLookups, spfIncludes[], spfBrokenIncludes[], spfValid,
dmarcRecord, dmarcPolicy, dmarcSubdomainPolicy, dmarcPct, dmarcHasRua, dmarcRuaDomains[], dmarcSource,
dkimFound, dkimSelectorsFound[], dkimKeys[{selector, keyType, keyBits, revoked}],
bimiRecord, bimiLogoUrl, bimiHasVmc, mtaStsRecord, mtaStsMode, tlsRptRecord, mxIps[], blocklistListings[], checkedAt`

Example issues: *"SPF needs 13 DNS lookups (limit 10) — SPF fails (permerror) at many receivers"*,
*"DMARC policy is p=none (monitor only) — spoofed mail is still delivered"*.

### How it works

Only public DNS lookups plus one HTTPS request to the public MTA-STS policy file (`mta-sts.<domain>/.well-known/mta-sts.txt`).
No browser, no proxies, no SMTP connections, no mailbox probing. About 30 domains in 10 seconds.
It reads public technical records only and **does not collect personal data**: `mailto:` addresses inside DMARC/TLS-RPT records are redacted.

### Pricing

Pay per result: one charge per domain actually checked. Invalid and non-existent domains are free.

### Limitations

- **DKIM**: selectors can't be listed via DNS. "No DKIM found" means none of the tried selectors exist — add your provider's selector
  (e.g. Google uses dated selectors like `20230601`) in *Extra DKIM selectors*.
- **Domain blocklists (Spamhaus DBL, SURBL, URIBL) are not checked** — their free tiers forbid commercial use. Only the mail-server IPs are checked, on SpamCop and PSBL.
- The score is a heuristic based on public configuration, not a guarantee of inbox placement (sender reputation and content also matter).

# Actor input Schema

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

Domains to check, e.g. example.com. URLs are accepted too (the hostname is used, a leading www. is removed). Duplicates are removed.

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

Additional DKIM selectors to try besides the built-in ones (default, google, selector1, selector2, k1, s1, s2, mail, dkim). Example: mandrill, sendgrid, zoho.

## `checkBlocklists` (type: `boolean`):

Look up the IPs of the domain's mail servers on public IP blocklists whose terms allow automated lookups (SpamCop, PSBL). Spamhaus, SURBL and URIBL are never queried because their free tiers forbid commercial use.

## `maxConcurrency` (type: `integer`):

How many domains to check in parallel.

## `timeoutSecs` (type: `integer`):

Max seconds for the DNS lookups of one domain before it is marked as timed out.

## Actor input object example

```json
{
  "domains": [
    "apify.com",
    "google.com",
    "github.com"
  ],
  "extraDkimSelectors": [],
  "checkBlocklists": false,
  "maxConcurrency": 10,
  "timeoutSecs": 20
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

# 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": [
        "apify.com",
        "google.com",
        "github.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("hoanglongteam/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": [
        "apify.com",
        "google.com",
        "github.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("hoanglongteam/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": [
    "apify.com",
    "google.com",
    "github.com"
  ]
}' |
apify call hoanglongteam/email-deliverability-checker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,hoanglongteam/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/dL2COO8gofFCcXk19/builds/tuT7ufZIZ9snKlGzV/openapi.json
