Email Validator for Agents
This MCP server validates email addresses for syntax and deliverability risk, with a free offline syntax checker and a paid DNS-based validator.
Run
validate_emailson 1–10,000 addresses via the Fairquery Apify Actor to getvalid/risky/invalid/unknownverdicts with reason codes.Check RFC-style syntax, normalize addresses, parse
Name <addr>forms, and lowercase domains locally with freecheck_email_syntax.Perform DNS-over-HTTPS MX/A lookups to detect domain existence, missing/null MX, implicit MX, and no mail server.
Flag disposable domains, role accounts, free webmail providers, and common domain typos with
did_you_meansuggestions.Report SPF/DMARC presence, DMARC policy, mail provider, MX records, source URL, and checked timestamp.
Tune behavior with
checkDns,checkSpfDmarc,allowDisposable,allowRoleAccounts,allowFreeProviders, andmaxEmails.Return
{count, items}rows, including machine-readable error rows; duplicates are skipped and DNS lookup failures are retryable.Use the paid validator read-only/idempotent with
APIFY_TOKEN; use the syntax checker free, locally, without a token.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Email Validator for Agentscheck these emails before I import: jane@acme.com, bob@gmial.com"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Email Validator for Agents (MX, Disposable, Typo)
Fairquery Apify Actor that validates email addresses without sending any email or probing SMTP servers: syntax, DNS/MX, null MX, disposable-domain and role-account detection, free-provider flag, typo suggestions ("gmial.com" → "gmail.com"), mail provider, and SPF/DMARC. Each address gets a clear valid / risky / invalid / unknown verdict with machine-readable reason codes.
When to use this Actor (LLM / tool selection)
Use it when an agent needs to:
Clean a lead / CRM / signup list before outreach or import
Decide whether an address can receive mail (domain exists, has MX, no null MX)
Flag disposable/temporary inboxes, role addresses (info@, sales@) or free webmail on B2B forms
Suggest a fix for a mistyped domain
See which mail provider (Google Workspace, Microsoft 365, …) and DMARC policy a domain uses
Do not use it to confirm a specific mailbox exists — that requires SMTP probing, which this Actor deliberately avoids (privacy, IP reputation and ToS reasons). valid means "well-formed, deliverable domain, no risk flags", not "mailbox confirmed".
Related MCP server: inboxvalid-mcp
How it works
Check | Source |
Syntax | RFC 5321/5322 pragmatic subset, IDN domains → punycode |
MX / A / AAAA / TXT | DNS-over-HTTPS |
Disposable domains | Bundled CC0 list from |
Role / free provider / typo | Built-in lists + edit-distance against popular providers |
Input
Field | Type | Default | Description |
|
| 6 sample addresses | Addresses; entries may be comma/semicolon/newline lists or |
|
|
| MX/A lookups (turn off for syntax-only) |
|
|
| Report SPF/DMARC presence and DMARC policy |
|
|
| If |
|
|
| If |
|
|
| If |
|
|
| Safety cap per run |
{ "emails": ["jane@acme.com", "info@apify.com", "bob@gmial.com"], "allowFreeProviders": false }Output
Every row has schema_version (1.0.0), type (email | error), source_url (the DoH MX query URL), checked_at.
{
"type": "email", "input": "someone@gmial.com", "email": "someone@gmial.com", "domain": "gmial.com",
"verdict": "risky", "reasons": ["DISPOSABLE_DOMAIN", "POSSIBLE_TYPO", "IMPLICIT_MX_ONLY"],
"syntax_valid": true, "is_disposable": true, "is_role_account": false, "is_free_provider": false,
"did_you_mean": "someone@gmail.com", "domain_exists": true, "has_mx": false, "null_mx": false,
"implicit_mx": true, "mx_records": [], "mail_provider": null, "has_spf": false, "has_dmarc": false, "dmarc_policy": null,
"source_url": "https://cloudflare-dns.com/dns-query?name=gmial.com&type=MX"
}Reason codes: INVALID_SYNTAX, DOMAIN_NOT_FOUND, NULL_MX, NO_MAIL_SERVER (→ invalid); DISPOSABLE_DOMAIN, ROLE_ACCOUNT, FREE_PROVIDER, POSSIBLE_TYPO, IMPLICIT_MX_ONLY (→ risky depending on the allow* flags); DNS_NOT_CHECKED (→ unknown).
Error rows (machine-readable, never charged)
{ "type": "error", "code": "DNS_LOOKUP_FAILED", "message": "DoH MX acme.com -> HTTP 503", "retryable": true, "input": "jane@acme.com", "domain": "acme.com" }Codes: INPUT_EMPTY, MAX_EMAILS_EXCEEDED, DNS_LOOKUP_FAILED. Duplicate addresses (case-insensitive) are skipped and counted in the summary.
Run summary
Key-value store record RUN_SUMMARY: emails checked, duplicates skipped, verdict counts, domains checked, DNS request count, echoed input.
Pricing
Pay per event: email-checked per email row. Error rows are never charged. See the Store pricing tab.
Memory / runtime
Default 256 MB. No browser, no proxy. ~1,000 emails across a few hundred domains finish in well under a minute.
MCP / Apify tools
Call from agents via Apify MCP (https://mcp.apify.com, authenticated with your Apify token), Actor fairquery/email-validator-mx-disposable:
{ "actor": "fairquery/email-validator-mx-disposable", "input": { "emails": ["jane@acme.com"] } }Read dataset items (type == "email") and the RUN_SUMMARY record. A standalone stdio MCP server lives in the GitHub repo under mcp/.
Local stdio MCP server
This repo ships a stdio MCP server (TypeScript, @modelcontextprotocol/sdk) under mcp/ exposing validate_emails (runs this Actor through the Apify API) and the free offline check_email_syntax. initialize and tools/list work without a token; tool calls require APIFY_TOKEN (billed per the Store pricing).
cd mcp && npm install && npm run build
node scripts/smoke-test.mjs # initialize + tools/list, no token
APIFY_TOKEN=... node scripts/smoke-test.mjs --call # real tool call{ "mcpServers": { "fairquery-email": { "command": "node", "args": ["/path/to/email-validator-mx-disposable/mcp/dist/index.js"], "env": { "APIFY_TOKEN": "<your Apify token>" } } } }Docker: docker build -t fairquery-email-mcp . (the repo-root Dockerfile builds this MCP server and is what Glama uses; the Apify Actor image is built from .actor/Dockerfile). glama.json lists fairquery as maintainer.
Links
Apify Store: https://apify.com/fairquery/email-validator-mx-disposable
License: MIT
Local development
npm install
npx apify run # uses input defaults, or storage/key_value_stores/default/INPUT.json
npm testKits & templates
Optional guides from Fairquery for wiring this Actor into agents and automations (the Actor works fine without them):
AI Agent Data Toolkit Quick-Start (PDF): MCP setup for Claude Desktop and Cursor, API calls, recipes, cost estimates.
n8n + Zapier Workflow Template Pack: 10 importable n8n workflows for the four Fairquery Actors, plus Zapier setup guides.
Agent Prompt Pack for Research & Lead Ops: 69 prompts for company research, lead cleaning, SEO and security reviews.
Agent Starter Kit: 10 copy-paste MCP + n8n recipes ($5): 10 copy-paste MCP + n8n recipes, with ready-made Claude/Cursor configs and 3 starter workflows.
Disclaimer
DNS-based validation cannot guarantee a mailbox exists or accepts mail. Use results to reduce bounces, not as proof of deliverability. Comply with anti-spam law (CAN-SPAM, GDPR/ePrivacy) when emailing.
Available Tools
2 toolscheck_email_syntaxCheck email syntax offline (free)ARead-onlyIdempotent
WHAT: Check whether strings are syntactically valid email addresses and normalize them (extracts "Name ", lowercases the domain), entirely locally. WHEN TO USE: fast pre-filtering or parsing before calling validate_emails, or when only the format matters. WHEN NOT TO USE: it does not check that the domain exists, has MX records, is disposable, a role account or a typo - use validate_emails (paid) for deliverability. COST: free; pure local function, no network, no APIFY_TOKEN, deterministic. RETURNS: {count, items}: one "email_syntax" row per input with input, email (normalized), syntax_valid, local_part, domain, reason (null or INVALID_SYNTAX). EXAMPLE: {"emails":["Jane jane@Example.com"]} -> email "jane@example.com", syntax_valid true, domain "example.com".
| Name | Required | Description | Default |
|---|---|---|---|
| emails | Yes | Required. 1-10000 strings to check; each may be a bare address or "Name <addr>" form. Example: ["Jane <jane@Example.com>","not-an-email"] |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | Yes | Number of rows returned |
| items | Yes | Result rows; each has a "type" field (data rows or machine-readable "error" rows) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, non-destructive and closed-world, so the bar is lower, yet the description adds substantial value: cost is free, execution is pure local with no network and no APIFY_TOKEN, results are deterministic, and it discloses the normalization behavior (extracting 'Name <addr>', lowercasing the domain). That goes well beyond the structured hints.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The WHAT/WHEN TO USE/WHEN NOT TO USE/COST/RETURNS/EXAMPLE structure is tightly front-loaded, with the purpose and routing condition in the first two blocks and no filler sentences. Every section carries distinct information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter, read-only, local tool the description covers purpose, exclusions, cost, determinism, normalization semantics and the return shape, even though an output schema exists. An agent has everything needed to call it correctly and interpret results.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the schema already documents the emails array, its 1-10000 bounds and the 'Name <addr>' form, so the baseline is 3. The description adds real semantic detail by explaining what normalization is applied to each input and the per-item reason value, which is more than the schema conveys.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a precise verb+resource (check syntactic validity of email strings) plus the scope ('entirely locally') and even names the normalization side effect. It explicitly contrasts itself with the validate_emails sibling, so an agent can distinguish them without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The WHEN TO USE / WHEN NOT TO USE blocks are explicit: use for fast pre-filtering or parsing before validate_emails, and do not use when domain existence, MX, disposable/role detection or typo checks are needed. It names the exact alternative and the condition that selects it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
validate_emailsValidate email addresses (syntax, MX, disposable, typo)ARead-onlyIdempotent
WHAT: Validate email addresses for deliverability risk: RFC-style syntax, domain existence and MX records (DNS-over-HTTPS), null MX, disposable/temporary inbox domains, role accounts (info@, sales@), free webmail providers, common domain typos with a "did you mean" suggestion, and optional SPF/DMARC presence and policy. WHEN TO USE: cleaning signup or lead lists, checking an address before sending, flagging throwaway or typo signups. WHEN NOT TO USE: for a quick offline format check or parsing "Name " strings use check_email_syntax (free). Does NOT send email or do SMTP mailbox probing, so it cannot confirm that a specific mailbox exists. BEHAVIOR: read-only; runs the Fairquery Apify Actor fairquery/email-validator-mx-disposable via the Apify API (DNS lookups via Cloudflare DoH). Requires APIFY_TOKEN. Duplicates (case-insensitive) are skipped. Typical run 3-30 s. COST: paid (billed to your Apify account, pay-per-event): $0.00005 per run + $0.002 per email row with a verdict; error rows are free. 100 emails ~ $0.20. RETURNS: {count, items}. email rows: input, email, domain, verdict (valid | risky | invalid | unknown), reasons[] (INVALID_SYNTAX, DOMAIN_NOT_FOUND, NULL_MX, NO_MAIL_SERVER -> invalid; DISPOSABLE_DOMAIN, ROLE_ACCOUNT, FREE_PROVIDER, POSSIBLE_TYPO, IMPLICIT_MX_ONLY -> risky depending on allow* flags; DNS_NOT_CHECKED -> unknown), syntax_valid, is_disposable, is_role_account, is_free_provider, did_you_mean, domain_exists, has_mx, mx_records, mail_provider, has_spf, has_dmarc, dmarc_policy, source_url, checked_at. error rows: code (INPUT_EMPTY, MAX_EMAILS_EXCEEDED, DNS_LOOKUP_FAILED), message, retryable. EXAMPLE: {"emails":["someone@gmial.com"]} -> verdict "risky", reasons ["POSSIBLE_TYPO"], did_you_mean "someone@gmail.com".
| Name | Required | Description | Default |
|---|---|---|---|
| emails | Yes | Required. 1-10000 email addresses to validate. Entries may also be comma/semicolon/newline-separated lists or "Name <addr>" forms. Example: ["john.doe@gmail.com","someone@gmial.com"] | |
| checkDns | No | Look up MX/A records to confirm the domain can receive mail (default true). false = syntax/list checks only, verdict may be "unknown". | |
| maxEmails | No | Safety cap on unique emails per run (1-100000, default 10000); extras produce a MAX_EMAILS_EXCEEDED error row | |
| checkSpfDmarc | No | Also report SPF and DMARC presence and DMARC policy per domain (default true) | |
| allowDisposable | No | Default false (disposable domains are "risky"). Set true to not penalize disposable domains. | |
| allowRoleAccounts | No | Default true. If false, role addresses (info@, sales@, support@...) get verdict "risky". | |
| allowFreeProviders | No | Default true. If false, free webmail (gmail.com, outlook.com...) gets "risky" - useful for B2B lead lists. |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | Yes | Number of rows returned |
| items | Yes | Result rows; each has a "type" field (data rows or machine-readable "error" rows) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only, idempotent, non-destructive, open-world. The description adds significant context beyond annotations: it explains the Apify Actor dependency, the APIFY_TOKEN requirement, duplicate skipping, typical run time (3-30s), and crucially the full cost model ($0.00005/run + $0.002/row). The only gap is not detailing the exact error row semantics, though these are partially listed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the WHAT, WHEN TO USE, and BEHAVIOR sections, making it easy to parse. However, the RETURNS section is quite verbose, listing all possible fields and their values, which duplicates information likely available in the output schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (external API, cost, multiple verdicts, error handling), the description provides a complete picture. It covers purpose, usage, behavior, cost, return values, and an example, leaving no major gaps for an agent to call it correctly. With an output schema present, the RETURNS detail is somewhat redundant but not harmful.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already documents all seven parameters in detail. The description provides minimal additional parameter meaning beyond what the schema already specifies, particularly for the allow* flags. Baseline 3 is appropriate when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The WHAT line states a specific verb (validate) and resource (email addresses) and enumerates the exact dimensions checked (syntax, MX, disposable, typo, role accounts, SPF/DMARC). It explicitly names the sibling check_email_syntax and distinguishes itself via the 'WHEN NOT TO USE' line.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit WHEN TO USE scenarios (cleaning lists, checking before sending, flagging signups) and an explicit WHEN NOT TO USE with the named alternative check_email_syntax. It also clarifies what it cannot do (no SMTP mailbox probing).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
2 tool updates
v1.0.1- Added
check_email_syntax - Changed
validate_emails9 fields changed- changed
Input schema / properties / allowDisposable / descriptionPrevious value: -"If true, disposable domains are not risky"New value: +"Default false (disposable domains are \"risky\"). Set true to not penalize disposable domains." - changed
Input schema / properties / allowFreeProviders / descriptionPrevious value: -"If false, free webmail becomes risky"New value: +"Default true. If false, free webmail (gmail.com, outlook.com...) gets \"risky\" - useful for B2B lead lists." - changed
Input schema / properties / allowRoleAccounts / descriptionPrevious value: -"If false, info@/sales@ etc. become risky"New value: +"Default true. If false, role addresses (info@, sales@, support@...) get verdict \"risky\"." - changed
Input schema / properties / checkDns / descriptionPrevious value: -"MX/A lookups (default true)"New value: +"Look up MX/A records to confirm the domain can receive mail (default true). false = syntax/list checks only, verdict may be \"unknown\"." - changed
Input schema / properties / checkSpfDmarc / descriptionPrevious value: -"Report SPF/DMARC (default true)"New value: +"Also report SPF and DMARC presence and DMARC policy per domain (default true)" - changed
Input schema / properties / emails / descriptionPrevious value: -"Email addresses to validate"New value: +"Required. 1-10000 email addresses to validate. Entries may also be comma/semicolon/newline-separated lists or \"Name <addr>\" forms. Example: [\"john.doe@gmail.com\",\"someone@gmial.com\"]" - added
Input schema / properties / emails / maxItemsAdded value: +10000 - added
Input schema / properties / maxEmails / descriptionAdded value: +"Safety cap on unique emails per run (1-100000, default 10000); extras produce a MAX_EMAILS_EXCEEDED error row" - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "count": { + "description": "Number of rows returned", + "type": "integer" + }, + "items": { + "description": "Result rows; each has a \"type\" field (data rows or machine-readable \"error\" rows)", + "items": { + "additionalProperties": {}, + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "count", + "items" + ], + "type": "object" +}
1 tool update
v0.1.0- First observed
validate_emails
TDQS
Scored across 2 tools
The two tools are clearly delineated: validate_emails does paid network/DNS deliverability checks, while check_email_syntax is a free local syntax/normalization pass. Their descriptions explicitly cross-reference each other with WHEN TO USE and WHEN NOT TO USE guidance, so an agent can reliably pick the right one.
Both names use consistent snake_case verb_noun form (validate_emails, check_email_syntax). Minor deviation: the noun phrasing differs slightly ('emails' vs 'email_syntax'), and the verbs differ (validate vs check), but the pattern remains predictable.
Two tools is on the thin side, but the server has a narrow, well-defined purpose (email validation), and each tool earns its place: a free local pre-filter and a paid deliverability check. No obviously redundant or missing sibling tool within the stated scope.
The surface covers the two core validation stages: syntax parsing/normalization and deliverability risk (MX, disposable, role, typo, SPF/DMARC). Mailbox existence (SMTP probing) is explicitly excluded, and there is no domain-only MX lookup tool, but these are minor gaps agents can work around.
Maintenance
Related MCP Connectors
Email validation for Claude and any MCP client — verdicts with evidence and bulk jobs.
Verify emails (valid/invalid/risky/unknown): MX, SMTP, catch-all, disposable. Free agent key.
Verify emails (valid/invalid/risky/unknown): MX, SMTP, catch-all, disposable. Free agent key.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceComprehensive email validation MCP server that checks syntax, MX records, disposable domains, role-based accounts, SPF/DKIM, typo suggestions, and risk scoring.-
- FlicenseAqualityBmaintenanceAn MCP server that exposes a verify_email tool for checking email syntax, disposable domains, and MX records, returning a structured validity result.1-
- FlicenseBqualityCmaintenanceAn MCP server that provides email verification, returning valid, invalid, or risky status with detailed checks and metadata. It enables verifying email addresses via a simple tool interface.3-
- FlicenseAqualityCmaintenanceAn MCP server that exposes a mock email verification tool over stdio transport, providing structured JSON results with statuses valid, invalid, or risky.1-