# DNS and Email Auth — records, SPF, DMARC, MTA-STS and DKIM (`hermeskd/dns-and-email-auth`) Actor

Check domains for DNS records (A, AAAA, CNAME, MX, NS, TXT, CAA, SOA), SPF lookup limits, DMARC policy/alignment, MTA-STS, TLS-RPT, BIMI, named DKIM selectors and DNSSEC. Return findings with severity; reporting addresses are reduced to domains.

- **URL**: https://apify.com/hermeskd/dns-and-email-auth.md
- **Developed by:** [Logan Parker](https://apify.com/hermeskd) (community)
- **Categories:** SEO tools, Developer tools, Agents
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.60 / 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.
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

Give it domains; it returns their DNS records (A, AAAA, CNAME, MX, NS, TXT, CAA, SOA) and an email-authentication assessment: SPF parsed with its DNS-lookup count against the limit of ten, DMARC policy and alignment, MTA-STS and TLS-RPT presence, BIMI, DKIM keys for selectors you name, and DNSSEC — as findings with severity. Reporting addresses in DMARC records are reported as present, by domain only.

Development validation produced actual successful public-input records using the production Dockerfile and SDK entrypoint on GitHub-hosted Linux. The smoke input, all three tasks and every defined benchmark passed their exact expectations. The independent review completed on 2026-10-19; its findings are tracked in the committed fix report. Platform costs, settlement, publication and daily tests remain unverified.

### Call it from an agent

Through Apify's MCP server (https://mcp.apify.com) use `call-actor`:

```json
{
  "actor": "hermeskd/dns-and-email-auth",
  "input": {
    "domains": [
      "apify.com"
    ]
  },
  "callOptions": {
    "maxTotalChargeUsd": 0.05,
    "timeout": 600
  },
  "waitSecs": 30
}
```

Then call `get-dataset-items` with the returned defaultDatasetId. Dedicated tool URL: https://mcp.apify.com?tools=hermeskd/dns-and-email-auth

### Input

| Field | Type | Meaning |
|---|---|---|
| `domains` | array | Domain names, not URLs or IP addresses; internationalized names use IDNA. |
| `dkimSelectors` | array | Only these selectors are queried; no selector enumeration. |

### Output

| Field | Meaning |
|---|---|
| `domain` | Normalized domain, or original invalid input. |
| `ok` | True when records were resolved and a readable assessment was produced. |
| `records` | A, AAAA, CNAME, MX, NS, TXT, CAA and SOA; report mailboxes redacted and SOA rname omitted. |
| `spf` | Static recursive SPF term assessment; macro-dependent validity null, not a sender/IP authorization verdict. |
| `dmarc` | Policy/alignment and reporting destination domains only. |
| `mtaSts` | MTA-STS TXT presence/id validation only; no HTTPS policy claim. |
| `tlsRpt` | TLS-RPT TXT presence and reporting domains only. |
| `bimi` | Default-selector BIMI TXT presence only; no logo/certificate validation. |
| `dkim` | Caller-named selector key assessments; RSA DER parsed; unsupported algorithms unassessed. |
| `dnssec` | Recursive resolver evidence, not local cryptographic validation. |
| `findings` | Authentication findings. |
| `error` | Failure, always uncharged. |

Actual production-container record from 2026-10-18T20:24:14.998485+00:00 (code `f063187693578dd7551fa2bec552281e2f0f3e33`, smoke input, SDK local storage). The saved record is unchanged; local event logs do not prove Apify settlement.

```json
{
  "domain": "apify.com",
  "ok": true,
  "records": {
    "A": [
      "3.170.42.100",
      "3.170.42.68",
      "3.170.42.109",
      "3.170.42.76"
    ],
    "AAAA": [
      "2600:9000:2870:5800:9:a03e:6540:93a1",
      "2600:9000:2870:1800:9:a03e:6540:93a1",
      "2600:9000:2870:1600:9:a03e:6540:93a1",
      "2600:9000:2870:5000:9:a03e:6540:93a1",
      "2600:9000:2870:400:9:a03e:6540:93a1",
      "2600:9000:2870:c800:9:a03e:6540:93a1",
      "2600:9000:2870:e200:9:a03e:6540:93a1",
      "2600:9000:2870:9a00:9:a03e:6540:93a1"
    ],
    "CNAME": [],
    "MX": [
      {
        "preference": 1,
        "exchange": "aspmx.l.google.com"
      },
      {
        "preference": 10,
        "exchange": "aspmx2.googlemail.com"
      },
      {
        "preference": 10,
        "exchange": "aspmx3.googlemail.com"
      },
      {
        "preference": 5,
        "exchange": "alt1.aspmx.l.google.com"
      },
      {
        "preference": 5,
        "exchange": "alt2.aspmx.l.google.com"
      }
    ],
    "NS": [
      "ns-449.awsdns-56.com.",
      "ns-839.awsdns-40.net.",
      "ns-1225.awsdns-25.org.",
      "ns-1928.awsdns-49.co.uk."
    ],
    "TXT": [
      "aisle-domain-verification-ymx7gd=j3J4hCmXHIc9R0RNQCfa8xdSf",
      "google-site-verification=R_4agUZyHorQrO5QGFa6ZB_o-uDxq82NY-EteDUpPvo",
      "google-site-verification=XU737OZxx6NvGd3NQK9MRt98qxRMjx3RByq-O0cy16I",
      "google-site-verification=ZqRh2_YSBHj2bo_KsEdu6MfmTMKJYLpDDL3oPtOrN_A",
      "google-site-verification=jrECJwBG9eeO_FUrOMhp7JY1oF8JSBxhzmLsLGvrt9s",
      "mixpanel-domain-verify=44615d9c-27f2-4587-a781-8a0a1c734e9a",
      "openai-domain-verification=dv-WTM7Nna92Owwh4sgmDOVUyyt",
      "tito-domain-verification=pbg2696rvzbax2t4dl7h5ynqm",
      "v=MCPv1; k=ed25519; p=1rDnoEigwTr+4JjG89+sLbdNnswCnLjmaeT34srW53Y=",
      "v=spf1 a mx include:_spf.google.com include:mailgun.org include:amazonses.com include:19497222.spf05.hubspotemail.net -all",
      "zapier-domain-verification-challenge=2c358aa9-fa36-419f-b21a-ca9eb6f2791d"
    ],
    "CAA": [
      "0 issue \"amazonaws.com\"",
      "0 issue \"digicert.com\"",
      "0 issue \"letsencrypt.org\"",
      "0 issuewild \"amazonaws.com\"",
      "0 issuewild \"letsencrypt.org\""
    ],
    "SOA": [
      {
        "mname": "ns-839.awsdns-40.net",
        "serial": 1,
        "refresh": 7200,
        "retry": 900,
        "expire": 1209600,
        "minimum": 86400
      }
    ]
  },
  "spf": {
    "record": "v=spf1 a mx include:_spf.google.com include:mailgun.org include:amazonses.com include:19497222.spf05.hubspotemail.net -all",
    "mechanisms": [
      "a",
      "mx",
      "include:_spf.google.com",
      "include:mailgun.org",
      "include:amazonses.com",
      "include:19497222.spf05.hubspotemail.net",
      "-all"
    ],
    "lookups": 10,
    "allQualifier": "-",
    "valid": true
  },
  "dmarc": {
    "policy": "reject",
    "subdomainPolicy": "reject",
    "pct": 100,
    "alignment": {
      "dkim": "r",
      "spf": "r"
    },
    "reportingDomains": [
      "apify.com"
    ]
  },
  "mtaSts": {
    "present": true,
    "id": "29919a352ef9476a",
    "valid": true
  },
  "tlsRpt": {
    "present": true,
    "valid": true,
    "reportingDomains": [
      "apify.com"
    ]
  },
  "bimi": {
    "present": true
  },
  "dkim": {},
  "dnssec": {
    "validated": false,
    "evidence": "recursive-resolver AD flag on NS response; no local signature validation"
  },
  "findings": []
}
```

### Events and prices

| Event | Title | Charged when | FREE / BRONZE | SILVER | GOLD / PLATINUM / DIAMOND |
|---|---|---|---|---|---|
| `domain-checked` | Domain checked | One domain resolved and assessed successfully. | $0.002 | $0.0018 | $0.0016 |

Platform usage is not passed through. Apify's automatic actor-start event remains $0.00005 per started GB (one GB or less counts once). The synthetic dataset-item event is absent. Charge limits stop further paying work; unprocessed inputs receive uncharged errors. Completed readable pending events are settled on abort.

Worked cost example: ten successful primary events cost $0.02 at list, plus actor start. Failures are not included in that count.

### Limits and run time

1–100 domains and at most 20 caller-named DKIM selectors. Queries use the configured recursive resolver with a five-second lifetime; no selector guessing. SPF reports the known recursive lookup-causing term count, stopping at eleven; it does not authenticate a sender/IP. Macro-dependent validity is null. DNSSEC validated is the resolver AD flag on the NS response, not local cryptographic validation or mere DS presence. MTA-STS is a TXT check, not an HTTPS policy check. BIMI is default-selector TXT presence only. Report mailboxes are removed even from raw TXT/CAA values, and SOA rname is omitted.

Default run timeout is 600 seconds. Typical cold platform time, costs and the smallest passing memory have not been measured for this new implementation. Memory probes are evidence to collect later; configured memories are specification defaults, not measured claims.

### Errors

| Code | Meaning |
|---|---|
| `nxdomain` | The DNS name does not exist. |
| `servfail` | The configured recursive resolver could not answer. |
| `invalid_domain` | Input is not a valid domain name. |
| `timeout` | The input did not finish within the run's time budget. |
| `invalid_input` | The run input passed the input schema but cannot be used; the message names the field. |
| `internal_error` | Unexpected failure; the message carries the error class. |
| `charge_limit_reached` | The run reached its maximum total charge; this input was not processed. |
| `robots_disallowed` | robots.txt forbids fetching the URL; no request was made to it. |
| `blocked_host` | The host is on the deny-list or resolves to a private or local address; no request was made. |
| `download_failed` | The request or connection failed within its bounded deadline. |

No failure record is charged. A run fails only when all input outcomes are Actor-side failures; caller errors and a mixture of caller/Actor failures do not fail the run.

### Sources and terms

Public DNS protocol records are queried through the configured recursive resolver under a five-second query lifetime, with no alternate resolver selected by the Actor. Queries are a few dozen per domain; use resolvers fairly. Only caller-named DKIM selectors are queried. Reporting mailbox local parts are removed from raw records and assessments; SOA rname is omitted. DNSSEC validated reports recursive-resolver AD evidence, not local cryptographic validation. BIMI is presence only; no certificate, logo or identity verification is claimed. No caller credentials, cookies, SMTP login or sending is involved. The 2026-10-18 GitHub-hosted production-container run resolved public DNS and produced the genuine record shown above. Cloud resolver access remains blocked; platform execution and settlement are unverified.

### Not affiliated

This Actor is not affiliated with Google, Apify, IANA, Verisign or other named protocol/source providers. Third-party names describe compatibility and source material.

### Related Hermes Actors

website-screenshot, lighthouse-audit, seo-page-audit, domain-availability, dns-and-email-auth, broken-links and sitemap-urls.

### Changelog

2026-10-17 (historical): initial implementation and fixture contracts; packaging and public production validation were incomplete on that date.

2026-10-18: all six production images, public smoke inputs, three tasks per Actor and defined benchmarks passed on GitHub-hosted Linux; exact code, records and image provenance are retained with the examples. These local SDK runs do not prove platform costs, settlement, publication, minimum memory, daily tests or payouts.

2026-10-19: independent-review repairs cover DNS privacy, malformed publisher URLs, empty sitemap failures, responsive assets and schema prefill, as applicable to this Actor. See the committed unit 4 fix report for measured verification and remaining platform NO-COVERAGE.

# Actor input Schema

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

Domain names, not URLs or IP addresses; internationalized names use IDNA.

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

Only these selectors are queried; no selector enumeration.

## Actor input object example

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

# 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"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("hermeskd/dns-and-email-auth").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"] }

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

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,hermeskd/dns-and-email-auth"
        }
    }
}
```

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/VPGL9n82IJNsHDsAG/builds/7jfLZA376vUY1ekC4/openapi.json
