# DMARC Checker – SPF, DKIM & MX Record Lookup in Bulk (`rowfeed/dmarc-checker`) Actor

Check the email security of any domain or email list in bulk: MX records and mail provider, SPF with every nested DNS lookup counted, DMARC policy (inherited too), DKIM, BIMI, MTA-STS and TLS-RPT, graded A-F with plain-English issues. $0.80 per 1,000 domains.

- **URL**: https://apify.com/rowfeed/dmarc-checker.md
- **Developed by:** [Rowfeed](https://apify.com/rowfeed) (community)
- **Categories:** Developer tools, Lead generation, Automation
- **Features:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.80 / 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

## DMARC Checker – SPF, DKIM & MX Record Lookup in Bulk

Check the email security of one domain or 50,000 at once. Paste domains, website URLs or a whole list of email addresses, and for each domain you get, in plain words:

- **A grade from A to F** and a list of the issues, written so you can send them to a client or a developer.
- **DMARC**: the record, the policy (none, quarantine, reject), subdomain policy, pct, whether reports are sent, and the parent domain's policy when a subdomain has none of its own.
- **SPF**: the record, how it ends (-all, ~all, ?all, +all) and **how many DNS lookups it really costs**. Every nested include is followed and counted, the way receivers do. Over 10 means SPF fails with permerror. Includes that have no SPF record and include loops are flagged.
- **DKIM**: which selectors have a key. The selectors used by Google Workspace, Microsoft 365, Mailchimp/Mandrill, SendGrid, Zoho and others are tried, and you can add your own.
- **MX records** and the mail provider (Google Workspace, Microsoft 365, Proofpoint, Mimecast, Zoho ...), and whether the domain can receive mail at all.
- **BIMI, MTA-STS and TLS-RPT** records.

Built for cold email and lead lists (check the sender domains before you send), deliverability audits, agencies doing client reports, security reviews, and sales teams looking for companies with weak email security.

### Example output row

```json
{"domain": "nrk.no", "exists": true, "grade": "C", "verdict": "grade C: 1 issue", "can_receive_mail": true, "mail_provider": "Google Workspace",
 "spf_record": "v=spf1 mx a ip4:160.67.135.178 ... include:_spf.google.com -all", "spf_all": "-all", "spf_dns_lookups": 7,
 "dmarc_policy": "none", "dmarc_reports": true, "dkim_found": true, "dkim_selectors": ["google"], "bimi": false, "mta_sts": false,
 "issues": ["DMARC policy is p=none: spoofed mail is only reported, not blocked"]}
```

### Grades

| Grade | Meaning |
|---|---|
| A | DMARC quarantine or reject on all mail, reports on, SPF valid within 10 lookups |
| B | DMARC enforced, but SPF is weak, reports are off or pct is below 100 |
| C | DMARC p=none (monitoring only) with a good SPF |
| D | DMARC p=none with a weak SPF, or no DMARC but a good SPF |
| F | No DMARC and no usable SPF: anyone can send mail as this domain |

DKIM never lowers the grade: a key can sit under a selector nobody can guess.

### How to use

1. Click **Try for free** (or **Start**) at the top of this page to open the input form.
2. Fill in **Domains or email addresses**. Up to 50,000 domains, website URLs or email addresses (info@shop.com checks shop.com). The form comes with a working example, so you can also run it as it is.
3. Optional: adjust **Extra DKIM selectors (optional)**. Every field has a sensible default.
4. Click **Start** and wait for the run to finish.
5. Download the results as Excel, CSV or JSON from the **Output** tab, or get them through the Apify API, a schedule or an integration (Make, Zapier, Google Sheets ...).

### Pricing

Pay per event, no subscription:

- **$0.0008 per domain** checked ($0.80 per 1,000).
- $0.001 per run start.

A domain that does not exist is still a result. Domains whose DNS does not answer, and text that is not a domain, are free. Works on the free Apify plan.

### Input

| Field | What it does |
|---|---|
| `domains` | Domains, URLs or email addresses, up to 50,000. `info@shop.com` checks `shop.com`; duplicates are checked once. |
| `dkimSelectors` | Optional extra DKIM selectors, e.g. `s1` for `s1._domainkey.example.com`. |

### Good to know

- Lookups go through public DNS-over-HTTPS (Cloudflare, with Google as fallback), so you see what mail servers on the internet see.
- A subdomain without its own DMARC record gets its parent's policy, as RFC 7489 says. `dmarc_inherited_from` shows when that happens.
- The SPF count covers include, a, mx, ptr, exists and redirect, nested includes included. Macros (`%{...}`) cannot be followed without a real sender and are not counted.

### More tools from Rowfeed

- [WHOIS Lookup & DNS Checker](https://apify.com/rowfeed/domain-rdap-checker) – domain age, expiry, registrar, nameservers and SSL expiry.
- [Website Contact Finder](https://apify.com/rowfeed/website-contact-finder) – company contact pages and social profiles from a list of websites.
- [Website Technology Checker](https://apify.com/rowfeed/website-technology-checker) – which CMS, analytics and tools a website uses.
- [Google Maps Scraper](https://apify.com/rowfeed/google-maps-scraper) – local businesses with websites, to check before outreach.
- [DNS Lookup & DNS Checker](https://apify.com/rowfeed/dns-lookup) – A, MX, NS, TXT, CAA records and reverse DNS of any domain or IP list.

# Actor input Schema

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

Up to 50,000 domains, website URLs or email addresses (info@shop.com checks shop.com). Duplicates are checked once.

## `dkimSelectors` (type: `array`):

DKIM keys sit under a selector that cannot be listed. The common ones for Google, Microsoft and others are always tried; add your own here (e.g. s1 from s1.\_domainkey.example.com).

## Actor input object example

```json
{
  "domains": [
    "apify.com",
    "github.com",
    "nrk.no"
  ],
  "dkimSelectors": [
    "s1",
    "mailchimp"
  ]
}
```

# Actor output Schema

## `results` (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",
        "github.com",
        "nrk.no"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("rowfeed/dmarc-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",
        "github.com",
        "nrk.no",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("rowfeed/dmarc-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",
    "github.com",
    "nrk.no"
  ]
}' |
apify call rowfeed/dmarc-checker --silent --output-dataset

```

## MCP server setup

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