# Email Security Audit (SPF, DMARC, DKIM, MX) (`maged120/email-security-audit`) Actor

Audit any domain's email security in bulk: SPF, DMARC, DKIM, MX, MTA-STS and BIMI, with a 0-100 score, spoofing risk and plain-English fixes.

- **URL**: https://apify.com/maged120/email-security-audit.md
- **Developed by:** [Maged](https://apify.com/maged120) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $6.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
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?

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 Security Audit** checks any list of domains for **SPF, DMARC, DKIM, MX, MTA-STS, TLS-RPT and BIMI** in one run. Each domain gets a **0–100 score**, an **A–F grade**, a **spoofing-risk** verdict and a **plain-English list of fixes**. Find out in seconds whether someone could send email pretending to be you, your clients, or your prospects.

### What does Email Security Audit do?

For every domain you provide, the Actor reads its public DNS email configuration and grades it:

- **MX & mail provider**: where the domain receives email (Google Workspace, Microsoft 365, Zoho, Proofpoint, Mimecast and more).
- **SPF**: the record, its policy (`-all`, `~all`…), duplicate records, and the **DNS lookup count** against the hard limit of 10, a common silent failure.
- **DMARC**: policy, subdomain policy, `pct`, and where reports are sent.
- **DKIM**: signing keys found on the most common selectors (plus any selectors you add).
- **MTA-STS, TLS-RPT and BIMI**: transport encryption policy and brand-logo readiness.

On the Apify platform you also get API access, scheduling, integrations (Google Sheets, Zapier, Make, Slack, webhooks) and run monitoring, so you can re-audit a portfolio every week automatically.

### Why audit email security?

- **MSPs & security consultants**: audit every client domain in one run and hand over a prioritized fix list.
- **Cold email & deliverability**: find the SPF/DMARC/DKIM gaps that send your mail to spam, before you launch a campaign.
- **Sales prospecting**: find companies with spoofable domains (`spoofingRisk: high`), a strong opener for security, email or IT services.
- **Vendor & M\&A due diligence**: check the email hygiene of partners and acquisition targets.
- **Compliance with Google and Yahoo sender rules**: bulk senders need SPF, DKIM and DMARC; see who's compliant.

### How to audit SPF, DMARC and DKIM in bulk

1. Open the Actor and go to the **Input** tab.
2. Paste domains into **Domains**, one per line. Website URLs and email addresses work too.
3. Optionally add your own **DKIM selectors**.
4. Click **Start**.
5. Open the **Output** tab: the **Scorecard** view shows grades and fixes, and the **DNS records** view shows the raw records.

### Input

| Field | Type | Description |
|---|---|---|
| `domains` | array | Domains, website URLs or email addresses. **Required.** |
| `dkimSelectors` | array | Optional extra DKIM selectors to check, on top of the built-in common ones. |

```json
{
    "domains": ["apify.com", "github.com", "someone@example.com"],
    "dkimSelectors": ["mycompany2024"]
}
```

### Output

One row per domain. You can download the dataset in various formats such as JSON, HTML, CSV, or Excel.

```json
{
    "domain": "github.com",
    "score": 85,
    "grade": "B",
    "spoofingRisk": "medium",
    "issues": [
        "SPF ends in ~all (softfail): unauthorized mail is only marked, not rejected. Consider -all.",
        "DMARC policy is quarantine: spoofed mail goes to spam. p=reject blocks it entirely."
    ],
    "hasMx": true,
    "mxRecords": [
        {
            "priority": 0,
            "host": "github-com.mail.protection.outlook.com"
        }
    ],
    "mailProvider": "Microsoft 365",
    "spfRecord": "v=spf1 ip4:192.30.252.0/22 include:spf.protection.outlook.com include:_netblocks.google.com include:_netblocks2.google.com include:mail.zendesk.com include:_spf.salesforce.com include:servers.mcsv.net include:mktomail.com include:sendgrid.net ip4:62.253.227.114 ip4:166.78.69.169 ip4:166.78.69.170 ip4:166.78.71.131 ~all",
    "spfPolicy": "softfail",
    "spfLookupCount": 10,
    "spfRecordCount": 1,
    "dmarcRecord": "v=DMARC1; p=quarantine; sp=reject; pct=100; rua=mailto:dmarc@github.com; ruf=mailto:dmarc@github.com; fo=1",
    "dmarcPolicy": "quarantine",
    "dmarcSubdomainPolicy": "reject",
    "dmarcPct": 100,
    "dmarcReportingEmails": [
        "dmarc@github.com"
    ],
    "dkimSelectorsFound": [
        "google",
        "selector1",
        "k1",
        "k2",
        "k3",
        "s1",
        "s2",
        "smtpapi"
    ],
    "mtaStsEnabled": false,
    "mtaStsMode": null,
    "tlsRptEnabled": false,
    "bimiEnabled": false,
    "error": null,
    "checkedAt": "2026-09-25T17:23:46+00:00"
}
```

### Output data fields

| Field | Description |
|---|---|
| `score` / `grade` | 0–100 score and A–F grade (A ≥ 90, B ≥ 75, C ≥ 60, D ≥ 40). |
| `spoofingRisk` | `high` = spoofed mail gets delivered, `medium` = it goes to spam, `low` = it's rejected. |
| `issues` | What's wrong and how to fix it, most important first. |
| `mailProvider` / `mxRecords` | Detected email provider and the MX hosts. |
| `spfRecord` / `spfPolicy` / `spfLookupCount` / `spfRecordCount` | SPF record, its enforcement, DNS lookups used (limit 10), and number of SPF records (must be 1). |
| `dmarcRecord` / `dmarcPolicy` / `dmarcSubdomainPolicy` / `dmarcPct` / `dmarcReportingEmails` | DMARC configuration. |
| `dkimSelectorsFound` | DKIM selectors with a published key. |
| `mtaStsEnabled` / `mtaStsMode` / `tlsRptEnabled` / `bimiEnabled` | Transport security and brand-indicator records. |
| `error` | Why a domain couldn't be audited (e.g. it doesn't exist), otherwise `null`. |

### How is the score calculated?

| Area | Points |
|---|---|
| MX records present | 10 |
| SPF present, single record, strict policy, within 10 lookups | 35 |
| DMARC present, enforcing policy (reject > quarantine), reporting enabled | 35 |
| DKIM key found | 15 |
| MTA-STS, TLS-RPT, BIMI | 5 |

Domains that don't handle email but are correctly locked down (`v=spf1 -all` plus DMARC `p=reject`) aren't penalized for missing MX or DKIM.

### How many results will I get?

Exactly one row per domain. 500 domains produce 500 rows. Duplicates are removed automatically.

### Tips

- **Paste email lists directly**: addresses are reduced to their domain and deduplicated, so a 10,000-contact list audits only its unique domains.
- **Filter by `spoofingRisk`** to build a prospect list or a client remediation queue.
- **Schedule it weekly** to catch changes, such as an SPF record that silently grew past 10 lookups.
- **Add your DKIM selector** if you know it (e.g. from your email provider's setup page) to confirm DKIM exactly.

### FAQ

**Why does it say no DKIM was found when I have DKIM?** DKIM keys can only be looked up by selector name, and there's no way to list them. The most common selectors are checked automatically. If yours has a custom name, add it under **Extra DKIM selectors**.

**Does it send any email?** No. It only reads public DNS records and the public MTA-STS policy file.

**Is this legal?** Yes. Email DNS records are public by design, so that every mail server in the world can read them.

**Found a bug or need a custom feature?** Open an issue in the **Issues** tab. Custom solutions are available on request.

# Actor input Schema

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

Domains to audit, one per line. You can also paste website URLs or email addresses; the domain is extracted automatically.

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

Optional. DKIM keys can only be found by name. The most common selectors are checked automatically; add your own here (e.g. the selector in your email provider's DKIM setup).

## Actor input object example

```json
{
  "domains": [
    "apify.com",
    "google.com",
    "example.com"
  ]
}
```

# Actor output Schema

## `dataset` (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",
        "example.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("maged120/email-security-audit").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",
        "example.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("maged120/email-security-audit").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",
    "example.com"
  ]
}' |
apify call maged120/email-security-audit --silent --output-dataset

```

## MCP server setup

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

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/bCmM4HC4IWKKzR2HM/builds/7ndHlUrUU5KyOjzEi/openapi.json
