# Email Domain Validator: MX, Disposable, SPF, DMARC, Age (`4b47/domain-trust-checker`) Actor

Bulk-validate emails and domains without SMTP pinging: MX and mail provider, disposable domains, SPF/DMARC/DKIM, domain age (RDAP), parked and for-sale pages, brand lookalikes. Each entry gets a valid/risky/invalid verdict and a 0-100 trust score. $1 per 1,000.

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

## Pricing

from $1.00 / 1,000 domain or email 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 Domain Validator bulk-checks email addresses and domains** and gives each one clear verdict: **valid / risky /
invalid**, a **0-100 trust score** and the reasons behind it. The checks: **MX and mail provider, disposable
(temporary) email domains, SPF / DMARC / DKIM, domain age and registry status (RDAP), parked and for-sale domains**,
and **brand lookalikes** (typosquats, homoglyphs, `brand-login` domains).

**Try it now:** press **Start**. The prefilled input checks 6 emails and domains in a few seconds for less than one
cent. Price: **$1 per 1,000 checks**; duplicates are free. Apify's free plan ($5 of monthly credit) covers about
**4,900 checks a month**.

Everything is checked at the DNS, RDAP and homepage level. **No SMTP connections, no mailbox pinging, and no
personal-data enrichment**, so it is safe for GDPR-conscious teams and it does not get your IPs blocklisted.

### Use cases

- **Signup and lead-form fraud screening:** block disposable emails, brand-new domains and lookalike domains before
  they reach your CRM or free trial.
- **Cold-email list hygiene:** drop domains that cannot receive mail (no MX, null MX, NXDOMAIN, parked) before sending,
  to protect your sender reputation.
- **B2B lead qualification:** find out which mail provider a company uses (Google Workspace vs Microsoft 365) and how
  mature its email security is (DMARC enforcement).
- **Phishing and brand-abuse triage:** score suspicious domains from reports, abuse inboxes or URL feeds: lookalike of
  which brand, how old, parked or live.
- **Vendor and partner due diligence:** domain age, registry holds and email authentication posture at a glance.

### What it checks

| Check | Output |
| --- | --- |
| Syntax | RFC 5322 address syntax, IDN domains (münchen.de), public-suffix-aware registrable domain |
| Mail capability | MX records, **null MX** (RFC 7505), implicit-A fallback, **mail provider** (Google Workspace, Microsoft 365, Zoho, Proofpoint, Mimecast and 40+ more) |
| Email authentication | **SPF** (record, `-all`/`~all`/`+all`, includes, lookup count, errors), **DMARC** (policy, subdomain policy, pct, reporting; checks the organizational domain too), **DKIM** keys under ~25 common selectors, **MTA-STS**, **BIMI** |
| Disposable | 10,000+ temporary-mail domains (mailinator, guerrillamail, ...) and their subdomains |
| Free provider / role account | gmail.com, outlook.com, proton.me, wp.pl, ...; `info@`, `support@`, `sales@` ... |
| **Domain age** | registration date, **age in days**, expiry, registrar, **registry status** (clientHold, redemptionPeriod, ...) via RDAP |
| **Parked / for sale** | parking nameservers (Sedo, Bodis, Dan, Afternic, ...), parked landers, "domain for sale" pages, redirects to domain marketplaces |
| **Brand lookalike** | ~140 commonly phished brands: typos, homoglyphs/punycode (`pаypal` with a Cyrillic а), leetspeak (`g00gle`), brand + keyword (`paypal-login`, `dhl-tracking`), brand in a subdomain (`paypal.com.account-check.xyz`). **Defensive registrations** by the brand (MarkMonitor, CSC, ...) are recognized and not penalized. |
| Trust score | 0-100 with human-readable reasons, risk level (low/medium/high) and verdict (valid/risky/invalid/unknown) |

### How to use Email Domain Validator

1. Paste emails, domains or URLs into **Emails, domains or URLs**, one per line (pasted comma- or space-separated
   lists are split for you). Up to 100,000 per run.
2. Leave the checks on (domain age, homepage check, DKIM probe) or turn off the ones you don't need for more speed.
3. Press **Start**. Each unique entry becomes one dataset item.
4. Filter the **Overview** view by `verdict` or `trustScore` and export to CSV or Excel, or read it with the API.

### Input

```json
{
  "items": [
    "jane.doe@gmail.com",
    "info@stripe.com",
    "test@mailinator.com",
    "netfllx.com",
    "binance-login.com",
    "https://login.paypal.com.account-check.xyz/"
  ],
  "checkRegistration": true,
  "checkWebsite": true,
  "checkDkim": true
}
```

Advanced options: custom DKIM selectors, DNS servers, concurrency.

### Output

One item per entry. A real example (shortened):

```json
{
  "input": "binance-login.com",
  "inputType": "domain",
  "valid": true,
  "verdict": "risky",
  "riskLevel": "medium",
  "trustScore": 40,
  "reasons": [
    "Domain does not receive email",
    "Looks like binance.com: brand name plus \"login\" (high confidence) (-55)",
    "Registered less than a year ago (314 days) (-5)"
  ],
  "domain": "binance-login.com",
  "flags": { "disposable": false, "freeProvider": false, "roleAccount": false, "lookalike": true, "parked": false, "forSale": false, "newlyRegistered": false, "acceptsMail": false },
  "lookalike": { "brand": "Binance", "brandDomain": "binance.com", "technique": "brand-plus-keyword", "confidence": "high" },
  "mail": { "acceptsMail": "no", "mx": [], "nullMx": false },
  "emailAuth": { "spf": { "present": false }, "dmarc": { "present": false }, "dkim": { "selectorsFound": [] }, "mtaSts": false, "bimi": false },
  "registration": { "registrar": "Hosting Concepts B.V. d/b/a Registrar.eu", "registeredAt": "2025-12-23T08:10:05.000Z", "ageDays": 314, "daysToExpiry": 415 },
  "checkedAt": "2026-11-02T20:04:51.000Z"
}
```

For an email you also get `email` (normalized) and `flags.roleAccount`. The dataset has three views: **Overview**
(verdict, score, flags, provider, age), **Email authentication** and **Registration and website**.

#### Verdicts

- **valid**: the domain exists, can receive mail and nothing risky was found (score ≥ 70).
- **risky**: disposable, a brand lookalike, parked, very new, or a low score.
- **invalid**: bad syntax, the domain does not exist (NXDOMAIN), or (for emails) the domain cannot receive mail.
- **unknown**: DNS lookups failed, so the result is incomplete. Retry later.

### How much does it cost to validate emails?

| Event | Price | Example |
| --- | --- | --- |
| Email or domain checked (one unique entry) | **$0.001** | 1,000 checks = **$1** |
| Actor start (per run) | $0.002 | |
| Duplicate entries | free | |

Everything is included: DNS, email authentication, RDAP age, homepage check, lookalike detection and score. Platform
usage is included. Set a **maximum cost per run** and the actor stops when it is reached.

### What this actor does not do

- **No SMTP mailbox verification.** It never connects to mail servers, so it cannot tell whether
  `jane.doe@company.com` exists as a mailbox. Use it as a domain-level filter (the cheap, safe first pass), not as a
  replacement for a mailbox verifier.
- **No personal data enrichment.** It never looks up who owns an address or a domain. Registrant contacts in RDAP are
  not read. Email addresses are processed in memory only for the domain check, are returned only in your own dataset,
  and are never written to the run log.
- No guarantees about intent: a lookalike can be a fan site, and a young domain can be a legitimate startup. The
  `reasons` field says exactly why a score was lowered.

### FAQ

#### Why is domain age missing for some domains?

Some country registries (.eu, .es, .it, .ru, .cn, .jp, ...) have no public RDAP service, and .de publishes no creation
date. Everything else still works for those domains.

#### Is DKIM "not found" bad?

Not necessarily. DKIM selectors are free-form, so only the ~25 common ones are probed. A found key proves DKIM is set
up; a missing one proves nothing and does not lower the score.

#### Is a brand's own typo domain flagged?

No. Brands often register their own typos (`gooogle.com`, `paypa1.com`). If a lookalike is held through a
brand-protection registrar or DNS provider (MarkMonitor, CSC, Com Laude, ...), it is reported as a defensive
registration and not penalized.

#### How fast is it?

About 6-7 entries per second at the default concurrency of 10 (300 domains in 45 s with all checks on). Emails on the
same domain share one set of lookups.

#### Can I call it from my signup form or an AI agent?

Yes: the Apify API (`run-sync-get-dataset-items` returns the verdicts in one request), the JavaScript and Python
clients, Make, Zapier, n8n, or the Apify MCP server.

### Integrations and API

Export to CSV, Excel or JSON; connect Google Sheets, Make, Zapier, n8n or webhooks; schedule runs; call
the actor from the Apify API or the Apify MCP server.

### Related actors

- [Career Site Jobs Scraper](https://apify.com/4b47/career-site-jobs): who is hiring, from Greenhouse,
  Lever, Workday and more.
- [Image to Text OCR](https://apify.com/4b47/image-pdf-ocr): text from images and scanned PDFs.
- [URL to Markdown for LLM & RAG](https://apify.com/4b47/llm-ready-markdown): web pages and PDFs as clean
  Markdown.

# Actor input Schema

## `items` (type: `array`):

One per line (comma- or space-separated lists are split too), up to 100,000 per run. Duplicates are checked and charged once. Emails are checked at the domain level only: no mailbox is contacted.

## `checkRegistration` (type: `boolean`):

Look up registration date, expiry, registrar and registry status over RDAP. Some country TLDs (.eu, .es, .it, .ru, .cn, .jp) have no public RDAP: their age is left empty.

## `checkWebsite` (type: `boolean`):

Fetch each domain's homepage once (max 256 KB) to detect parked, placeholder and for-sale pages and redirects to domain marketplaces. Skipped for free mailbox providers.

## `checkDkim` (type: `boolean`):

Look for DKIM keys under ~25 common selectors (google, selector1/2 for Microsoft 365, k1 for Mailchimp, s1/s2, ...). A found key proves DKIM is set up; not finding one proves nothing.

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

Replace the built-in selector list with your own (e.g. selectors your ESP uses).

## `dnsServers` (type: `array`):

Resolver IPs. Default: Cloudflare 1.1.1.1 and Google 8.8.8.8.

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

Entries checked in parallel.

## Actor input object example

```json
{
  "items": [
    "jane.doe@gmail.com",
    "info@stripe.com",
    "test@mailinator.com",
    "support@paypa1.com",
    "apify.com",
    "https://login.paypal.com.account-check.xyz/"
  ],
  "checkRegistration": true,
  "checkWebsite": true,
  "checkDkim": true,
  "maxConcurrency": 10
}
```

# Actor output Schema

## `results` (type: `string`):

One item per unique input entry: verdict, trust score, reasons, mail, email authentication, registration and website checks.

# 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 = {
    "items": [
        "jane.doe@gmail.com",
        "info@stripe.com",
        "test@mailinator.com",
        "support@paypa1.com",
        "apify.com",
        "https://login.paypal.com.account-check.xyz/"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("4b47/domain-trust-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 = { "items": [
        "jane.doe@gmail.com",
        "info@stripe.com",
        "test@mailinator.com",
        "support@paypa1.com",
        "apify.com",
        "https://login.paypal.com.account-check.xyz/",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("4b47/domain-trust-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 '{
  "items": [
    "jane.doe@gmail.com",
    "info@stripe.com",
    "test@mailinator.com",
    "support@paypa1.com",
    "apify.com",
    "https://login.paypal.com.account-check.xyz/"
  ]
}' |
apify call 4b47/domain-trust-checker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,4b47/domain-trust-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/6KiJS6B69uvHXQt1c/builds/8rTqwfldHbv9xleFr/openapi.json
