# Email List Precheck: Syntax, MX & Disposable Check (`offerastudio/email-list-precheck`) Actor

Cheap email list hygiene before real verification: syntax, MX records, disposable domains, role accounts, free providers, typo suggestions and duplicates, up to 100,000 addresses. No SMTP probing, never claims a mailbox exists. Optional exact check with your own key.

- **URL**: https://apify.com/offerastudio/email-list-precheck.md
- **Developed by:** [Offera Studio](https://apify.com/offerastudio) (community)
- **Categories:** Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.20 / 1,000 email pre-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

### What does Email List Precheck do?

**Email List Precheck** is a fast, cheap clean-up step for email lists. It removes the addresses that are **clearly bad** before you pay for a real verification or send a campaign. It checks, for up to **100,000 addresses** per run:

- ✍️ **Syntax** (practical RFC 5322) and **normalisation**: trimmed, domain in lower case, internationalised domains turned into punycode.
- 📬 **Mail server**: does the domain have MX records (or an A/AAAA record, which counts as an implicit MX)? Looked up once per domain through DNS-over-HTTPS. A domain that does not exist, or says it takes no mail ("null MX"), is **invalid**.
- 🗑️ **Disposable domains** (a bundled open list of 9,000+ domains), **role accounts** (`info@`, `sales@`, `admin@`, `noreply@` ...), **free webmail providers**, and **typo suggestions** (`gmial.com` → `gmail.com`, `hotmial.com`, `.con` → `.com`).
- ♻️ **Duplicates** within your list (free).

### ⚠️ What this Actor does NOT do

**It never talks to the mailbox.** Outbound port 25 (SMTP) is closed on Apify, so there is **no SMTP probing**, and the Actor **never claims a mailbox exists**. Without a key its best verdict is `unknown` ("passed the pre-checks, mailbox not verified"). It is a pre-check that removes bad addresses so that you pay a verification service only for addresses worth verifying. Only if you give your **own MillionVerifier or ZeroBounce key** do addresses get an exact `valid` / `invalid` / `catch-all` / `unknown` from that provider.

### Verdicts

| Verdict | Meaning |
| --- | --- |
| `invalid` | Cannot receive mail: bad syntax, the domain does not exist, no mail server, or a null MX. |
| `risky` | Can receive mail, but is a disposable domain, a role account (can be switched off), or has a suspected typo. |
| `unknown` | Nothing against it. **The mailbox itself was not verified.** |
| `valid`, `catch-all` | **Only with your own provider key**: the provider's answer, with its raw status in `providerStatus`. |

### Who is it for?

- **Email marketers and sales teams**: shrink a list by removing typos, dead domains and throw-away addresses before sending or before paying for a verifier.
- **Lead generation and data teams**: flag role accounts and free-mail addresses in B2B lists.
- **Developers**: clean a signup export; add the exact provider check only for the addresses that pass.

### How to use it

1. Paste addresses into **Emails**, one per line (commas, semicolons and `Name <address>` are understood).
2. Optional: switch **Mark duplicates** or **Role accounts count as risky** off.
3. Optional: choose **MillionVerifier** or **ZeroBounce** and paste **your own API key** (stored encrypted, never logged or put in the results). Addresses that pass the pre-check are then verified with your account, and the provider's answer becomes the verdict.
4. Click **Start**. The **Results** tab shows the verdict and reasons per address.

### Input example

```json
{
    "emails": ["maria.garcia@gmail.com", "john.smith@gmial.com", "info@example-company.com", "Name <someone@example.org>"],
    "dedupe": true,
    "includeRoleAccounts": true,
    "byokProvider": "none"
}
```

### Output example

Real results from a run on 7 October 2026 (no key):

```json
[
    { "type": "email", "email": "maria.garcia@gmail.com", "normalized": "maria.garcia@gmail.com", "verdict": "unknown", "reasons": [], "domain": "gmail.com", "mx": true, "mxHosts": ["gmail-smtp-in.l.google.com", "alt1.gmail-smtp-in.l.google.com", "alt2.gmail-smtp-in.l.google.com"], "disposable": false, "role": false, "freeProvider": true, "suggestion": null, "provider": null, "providerStatus": null },
    { "type": "email", "email": "john.smith@gmial.com", "normalized": "john.smith@gmial.com", "verdict": "risky", "reasons": ["dns-unavailable", "disposable-domain", "typo-suspected"], "domain": "gmial.com", "mx": null, "disposable": true, "suggestion": "john.smith@gmail.com" },
    { "type": "email", "email": "test.user@mailinator.com", "verdict": "risky", "reasons": ["disposable-domain"], "disposable": true, "mx": true },
    { "type": "email", "email": "info@wikipedia.org", "verdict": "risky", "reasons": ["role-account"], "role": true, "mx": true },
    { "type": "email", "email": "someone@zq7x-no-such-domain-4f9a1c3e8b.com", "verdict": "invalid", "reasons": ["domain-not-found"], "mx": false },
    { "type": "email", "email": "not-an-email", "normalized": null, "verdict": "invalid", "reasons": ["syntax:missing-at-sign"] },
    { "type": "email", "email": "alex@example.com", "verdict": "invalid", "reasons": ["null-mx"], "mx": false },
    { "type": "duplicate", "email": "Maria.Garcia@Gmail.com", "duplicateOf": "maria.garcia@gmail.com", "reasons": ["duplicate"] }
]
```

(Rows shortened here; every email row has all fields.) With your own key a row also has `provider` (`millionverifier` or `zerobounce`), `providerStatus` (the provider's own text, e.g. `ok`, `catch_all`, `valid`) and `providerDetail`, and the `verdict` is the provider's answer.

#### Reason codes

`syntax:<problem>` (missing-at-sign, multiple-at-signs, contains-spaces, invalid-local-characters, misplaced-dot-in-local-part, invalid-domain, invalid-tld ...), `domain-not-found`, `no-mx-records`, `null-mx`, `dns-unavailable` (DNS did not answer: the verdict is not changed by it), `disposable-domain`, `role-account`, `typo-suspected`, `provider-error` (your provider could not check this address: the pre-check verdict stays).

### How much does it cost?

Pay per event:

| Event | Price | When |
| --- | --- | --- |
| `email-prechecked` | **$0.0002** per address | every address that is pre-checked (valid or not) |
| `email-verified-byok` | **$0.0005** per address | only when **your** provider returned a result for the address |

1,000 addresses pre-checked cost $0.20. **Free**: duplicate rows and error rows. Your provider charges its own price to your account with them, on top. Only addresses that pass the pre-check are sent, which saves your credits: invalid addresses, disposable domains and suspected typos are never sent.

### Limitations

- **No mailbox verification without your own key**, by design (see above).
- **Role accounts and free providers are flags, not errors**: `info@` can be a real, monitored mailbox. Switch the verdict effect off with **Role accounts count as risky**.
- **Typo suggestions** cover the big providers and common TLD slips; an unusual typo of a company domain is not caught. A suggestion is a hint, not a correction.
- **The disposable list** (CC0, 9,000+ domains) misses new throw-away services and may list a few domains that are not disposable any more; it is refreshed with `scripts/refresh-disposable.mjs` before releases.
- **DNS** answers can be wrong for a moment (`dns-unavailable`): re-run those addresses.
- **Quoted local parts** (`"john smith"@example.com`), comments and IP-address domains are rare and are reported as syntax problems.
- Local parts are kept as written (they are case-sensitive in theory); duplicates are found ignoring case.

### FAQ

#### Why is the best verdict "unknown" and never "valid"?

Because without asking the mail server (SMTP), nobody can know a mailbox exists, and port 25 is closed on Apify. "Valid" would be a guess. With your provider key you get the provider's real answer.

#### Which provider should I use?

Either works the same here: the Actor sends the address and shows the answer. Check their prices and accuracy for your lists. The key is yours: set it in the secret field; it is never written to results or logs.

#### What happens to addresses my provider cannot check?

The row keeps its pre-check verdict and gets the reason `provider-error`; you are not charged the verification event. If the key is rejected or the credits run out, the Actor stops using the provider for the rest of the run and adds one free error row.

#### Does it use a proxy?

No.

### More tools from the same developer

All pay-per-result, no proxy or login needed, built and maintained by the same developer:

**Website audits**

- [Website Accessibility Checker: WCAG 2.2 & EAA](https://apify.com/offerastudio/website-accessibility-audit): accessibility issues with fixes, SEO basics and security headers.
- [Cookie & Tracker Audit: GDPR Consent Checker](https://apify.com/offerastudio/cookie-tracker-audit): cookies and tracking tags that load before consent.
- [AI Crawler Access Checker: robots.txt & llms.txt](https://apify.com/offerastudio/ai-crawler-access-audit): which AI crawlers a site allows, plus llms.txt.
- [Structured Data Validator: Schema & Rich Results](https://apify.com/offerastudio/structured-data-validator): JSON-LD and Microdata checked against Google's rich result rules.
- [Website Change Monitor: Diffs, Prices & Alerts](https://apify.com/offerastudio/website-change-monitor): get a row only when a page changes, with a clean diff.
- [Policy Change Monitor: Privacy & Terms Tracker](https://apify.com/offerastudio/policy-change-monitor): privacy policy and terms changes, classified clause by clause.
- [SaaS Pricing Monitor: Track Competitor Plans](https://apify.com/offerastudio/saas-pricing-monitor): competitor pricing plans as structured data, with price-change diffs.
- [Sitemap Change Monitor: New & Removed URLs](https://apify.com/offerastudio/sitemap-change-monitor): new, removed and changed URLs from a site's sitemaps.
- [Site SEO Crawler: Broken Links & On-Page Audit](https://apify.com/offerastudio/site-seo-crawler-audit): site-wide crawl for broken links, redirects and on-page SEO issues.
- [Website Tech Stack Detector: Bulk Lead Filters](https://apify.com/offerastudio/website-tech-stack-detector): technologies used by websites, with filters for lead lists.
- [Domain Availability & Expiry Checker (RDAP)](https://apify.com/offerastudio/domain-whois-availability): domain availability, registrar and expiry dates from RDAP.
- [Status Page SLA Monitor: Uptime & Incidents](https://apify.com/offerastudio/status-page-sla-monitor): SaaS vendor uptime, incidents and a monthly SLA table from public status pages.

**Company data and compliance**

- [Company Contact Finder: Emails, Phones & Socials](https://apify.com/offerastudio/company-contact-finder): contact details published on company websites.
- [UK New Companies Feed: Companies House Daily](https://apify.com/offerastudio/uk-new-companies-feed): newly incorporated UK companies with sector filters.
- [EU VAT Number Validator: Bulk VIES Checker](https://apify.com/offerastudio/eu-vat-number-validator): bulk VAT checks with name, address and consultation number.
- [LEI Corporate Tree: GLEIF Parents & Subsidiaries](https://apify.com/offerastudio/gleif-lei-corporate-tree): LEI lookup with parents, subsidiaries and a KYC summary.
- [UK Company Distress Watch: Insolvency Alerts](https://apify.com/offerastudio/uk-company-distress-watch): administrations, liquidations and winding-up petitions from The Gazette.
- [IBAN Validator: Bulk Check & Bank Lookup](https://apify.com/offerastudio/iban-bank-validator): IBAN format and checksum, plus bank name and BIC where open data exists.
- [Sanctions Screening: OFAC, EU, UN & UK Lists](https://apify.com/offerastudio/sanctions-screening): names screened against official sanctions lists, with match scores.
- [OSHA & EPA Violation Monitor: Fines by Company](https://apify.com/offerastudio/osha-epa-violation-monitor): US OSHA and EPA enforcement cases and penalties by company.
- [UK Company Officer Changes: Director & PSC Alerts](https://apify.com/offerastudio/uk-company-officer-changes): director, owner, address and status changes for a watchlist of UK companies.
- [FDA Warning Letters Monitor: By Company & Subject](https://apify.com/offerastudio/fda-warning-letters-monitor): FDA warning letters by company and subject, with cited regulations.
- [Supplier Risk Report: Sanctions, VAT & Insolvency](https://apify.com/offerastudio/supplier-risk-report): one risk row per supplier from eight official registers, with changes since last run.
- [Brand Impersonation Domain Monitor: Look-alikes](https://apify.com/offerastudio/brand-impersonation-domain-monitor): look-alike domains and certificates that imitate your brand, with a risk score.

**Media and AI**

- [Audio & Video Transcriber: Podcasts, SRT, Speakers](https://apify.com/offerastudio/audio-video-transcriber): audio, video, podcasts and social links to text, SRT and VTT.
- [Podcast Mention Alerts: Brand Mentions by Second](https://apify.com/offerastudio/podcast-mention-alerts): where your brand is said in new podcast episodes, with the exact second.
- [News Brand Mentions Monitor: New Articles Only](https://apify.com/offerastudio/news-brand-mentions-monitor): new news articles about your brand, people or topics.
- [YouTube Channel Monitor: New Videos & Growth](https://apify.com/offerastudio/youtube-channel-monitor): new videos and view growth of the channels you watch.

**Market signals**

- [US WARN Layoff Notices: 12 States Daily Feed](https://apify.com/offerastudio/us-warn-layoff-notices): layoff and plant closure notices from official state sources.
- [US Product Recalls Monitor: FDA & CPSC Feed](https://apify.com/offerastudio/us-product-recalls-monitor): FDA and CPSC recalls in one feed, with severity.
- [EU Tenders Feed: TED Public Procurement Alerts](https://apify.com/offerastudio/eu-tender-feed): EU public tenders from TED with CPV, country and value filters.
- [Liquor License Openings: New Bars & Stores (US)](https://apify.com/offerastudio/liquor-license-openings): new US liquor licences from official state open data.
- [Clinical Trials Change Monitor: Status & Updates](https://apify.com/offerastudio/clinicaltrials-change-monitor): status, enrollment and results changes on ClinicalTrials.gov studies.
- [Career Site Jobs Monitor: ATS Jobs & New Roles](https://apify.com/offerastudio/career-site-jobs-monitor): open roles from company career sites, with new and closed roles since the last run.
- [App Reviews Monitor: App Store & Google Play](https://apify.com/offerastudio/app-store-reviews-monitor): app reviews from both stores, only new ones in monitor mode.
- [US Federal Contracts Feed: SAM.gov & USAspending](https://apify.com/offerastudio/us-federal-contracts-feed): SAM.gov contract opportunities with the buyer's award history.
- [Grants.gov Opportunities: US Federal Grants Feed](https://apify.com/offerastudio/grants-gov-opportunities): US federal grant opportunities by keyword, eligibility and agency.
- [Federal Register Monitor: US Rules & Notices Feed](https://apify.com/offerastudio/federal-register-monitor): new US rules, proposed rules and notices by agency or topic.
- [B2B Sales Trigger Feed: Hiring + Tech Leads](https://apify.com/offerastudio/b2b-sales-trigger-feed): companies hiring for a role and using (or not using) a technology, with contacts.
- [Local Business Leads: OpenStreetMap, No Website](https://apify.com/offerastudio/local-business-leads-osm): local businesses by city and category, including those with no website.
- [Solana Token Pair Monitor: New & Trending Pairs](https://apify.com/offerastudio/solana-token-pair-monitor): new and trending Solana pairs with liquidity, volume and safety flags.

### Feedback

Missing a typo pattern or a role name, or a disposable domain that is wrongly listed? Open an issue on the **Issues** tab.

# Changelog

This Actor's version history is a separate document: https://apify.com/offerastudio/email-list-precheck/changelog.md

# Actor input Schema

## `emails` (type: `array`):

Addresses, one per line (commas, semicolons and "Name <address>" are understood). Up to 100,000.

## `dedupe` (type: `boolean`):

The same address again (ignoring case) gets a free duplicate row instead of being checked twice.

## `includeRoleAccounts` (type: `boolean`):

info@, sales@, admin@, noreply@ ... make the verdict "risky". Switch off if role addresses are fine for you: they are still flagged (role: true) but do not change the verdict.

## `byokProvider` (type: `string`):

Addresses that pass the pre-check are sent to this provider with YOUR API key, and its answer becomes the verdict. The provider charges your account with them. Without a key the Actor never says "valid".

## `millionVerifierApiKey` (type: `string`):

Only used when MillionVerifier is chosen (or the only key given). Stored encrypted by Apify, never written to logs or results.

## `zeroBounceApiKey` (type: `string`):

Only used when ZeroBounce is chosen (or the only key given). Stored encrypted by Apify, never written to logs or results.

## Actor input object example

```json
{
  "emails": [
    "maria.garcia@gmail.com",
    "john.smith@gmial.com",
    "test.user@mailinator.com",
    "info@wikipedia.org",
    "someone@zq7x-no-such-domain-4f9a1c3e8b.com",
    "not-an-email",
    "alex@example.com",
    "Maria.Garcia@Gmail.com"
  ],
  "dedupe": true,
  "includeRoleAccounts": true,
  "byokProvider": "none"
}
```

# Actor output Schema

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

No description

## `clean` (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 = {
    "emails": [
        "maria.garcia@gmail.com",
        "john.smith@gmial.com",
        "test.user@mailinator.com",
        "info@wikipedia.org",
        "someone@zq7x-no-such-domain-4f9a1c3e8b.com",
        "not-an-email",
        "alex@example.com",
        "Maria.Garcia@Gmail.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("offerastudio/email-list-precheck").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 = { "emails": [
        "maria.garcia@gmail.com",
        "john.smith@gmial.com",
        "test.user@mailinator.com",
        "info@wikipedia.org",
        "someone@zq7x-no-such-domain-4f9a1c3e8b.com",
        "not-an-email",
        "alex@example.com",
        "Maria.Garcia@Gmail.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("offerastudio/email-list-precheck").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 '{
  "emails": [
    "maria.garcia@gmail.com",
    "john.smith@gmial.com",
    "test.user@mailinator.com",
    "info@wikipedia.org",
    "someone@zq7x-no-such-domain-4f9a1c3e8b.com",
    "not-an-email",
    "alex@example.com",
    "Maria.Garcia@Gmail.com"
  ]
}' |
apify call offerastudio/email-list-precheck --silent --output-dataset

```

## MCP server setup

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

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/p3YCiP9wi7W1Ss3gJ/builds/o7qnJ2BPe1o5bhfuf/openapi.json
