Email Validation
Validate email addresses before sending with syntax, MX, disposable domain, and role-based address checks. Available as a standalone API with free tier.
Overview
PushMail's email validation API lets you verify email addresses before adding them to your lists or sending. Every validation runs four core checks, plus a deeper mailbox verification tier that confirms the individual address actually exists — not just that its domain can receive mail.
| Check | Description |
|---|---|
| Syntax | RFC-compliant format, valid local part length (max 64 chars) and domain length (max 253 chars) |
| IDN/Punycode | Normalizes internationalized domain names to their ASCII/Punycode form before DNS and reputation checks |
| MX records | DNS lookup via Cloudflare DoH to confirm the domain can receive email. Falls back to A record per RFC 5321 |
| Disposable | Checks against a built-in list of 60+ disposable email providers (mailinator, guerrillamail, etc.) |
| Role-based | Detects generic addresses like admin@, noreply@, support@ that are typically not personal inboxes |
| Mailbox | Deep, provider-aware confirmation that the specific mailbox exists (see below) |
Together these give a triple-verified result — format → domain → mailbox — returned as a single deliverability status and a confidence level so you know not just whether an address passed, but how certain the answer is.
Results are cached (MX lookups per domain; mailbox verdicts per email, with a long TTL for stable providers) so repeated validations are fast and cheap.
Pricing
| Monthly volume | Cost per validation |
|---|---|
| First 100 / month | Free |
| Up to 20,000 | $0.005 |
| 20,001 – 250,000 | $0.003 |
| 250,001+ | $0.0015 |
One price per email — a validation costs exactly the same as a send, because every PushMail send already runs the same triple-verified check (format → domain → mailbox) before relaying, dropping confirmed-undeliverable addresses before they burn a send credit or bounce against your sender reputation. A standalone validation is simply that check without the delivery. Volume tiers are graduated and the first 100 each month are free; the allowance resets at the start of each calendar month. (Addresses we can't confirm either way — catch-all domains, consumer Gmail — are still delivered; only addresses confirmed dead are dropped.)
Single validation
curl -X POST https://pushmail.dev/api/v1/validate \
-H "Authorization: Bearer pm_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "email": "user@example.com" }'Response:
{
"data": {
"email": "user@contoso.com",
"valid": true,
"status": "deliverable",
"confidence": "verified",
"provider": "microsoft",
"method": "microsoft_getcredentialtype",
"checks": {
"syntax": true,
"mx": true,
"disposable": false,
"role": false,
"mailbox": "exists"
}
}
}status is the headline deliverability verdict; confidence tells you how strong the underlying evidence is. See Deep mailbox verification for the full field reference.
Every response also separates evidence about the exact address, its domain, and its receiving infrastructure. This avoids treating a shared domain such as gmail.com as evidence about one Gmail user:
{
"intelligence": {
"address": { "risk": "unknown", "suppression": null, "history": { "total": 0 } },
"domain": { "name": "contoso.com", "risk": "low", "history": { "total": 24 } },
"mxNetwork": {
"risk": "unknown",
"routing": {
"status": "mx",
"endpoints": [{ "priority": 10, "host": "contoso-com.mail.protection.outlook.com", "addresses": ["203.0.113.10"] }]
}
},
"mxInfrastructure": { "geography": { "status": "not_checked" } },
"decision": { "action": "allow", "mandatory": false, "mode": "advisory", "reasons": [] }
}
}Address and domain history are scoped to your organization. Decision logs store a domain-separated HMAC of the address rather than another plaintext copy.
When asynchronous enrichment is enabled, the immediate response includes a general enrichment job reference:
{
"enrichmentJob": {
"id": "9d042e16-99c2-4fe4-99d8-d4dd86a50c57",
"status": "pending",
"statusUrl": "/api/v1/validate/jobs/9d042e16-99c2-4fe4-99d8-d4dd86a50c57"
}
}Poll statusUrl with the same API key. Depending on the requested checks, a completed job can contain Spamhaus DQS domain/IP reputation, MaxMind GeoLite2 country/ASN observations, and SMTP evidence. Queue delivery is at least once, so job updates are idempotent and clients should treat the job ID as the stable identifier.
MX geography describes the apparent location of receiving infrastructure. It is not the recipient's location, nationality, or a guarantee of data residency.
Verification decision policy
Reputation is advisory by default. Retrieve or change the organization policy with:
curl https://pushmail.dev/api/v1/validation-policy \
-H "Authorization: Bearer pm_live_YOUR_KEY"
curl -X PUT https://pushmail.dev/api/v1/validation-policy \
-H "Authorization: Bearer pm_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"mode": "enforce",
"disposable": "block",
"role": "warn",
"addressRisk": "block",
"domainRisk": "warn",
"mxRisk": "warn",
"unknown": "allow",
"blockedCountries": ["KP"],
"blockedAsns": []
}'Each configurable signal accepts allow, warn, or block. In advisory mode a configured block is returned as a warning. Complaints, unsubscribes, existing suppressions, confirmed hard bounces, invalid syntax, missing mail routing, and a confirmed missing mailbox remain mandatory blocks.
Spamhaus checks require a licensed DQS key. If it or the local MaxMind databases are absent, the API reports not_configured instead of treating the target as clean.
SMTP connection safety
SMTP checks use persistent connection budgets at three levels: global, recipient domain, and MX host. Defaults permit at most 60 total connections per minute, 10 per recipient domain per hour, and 5 per MX host per minute, with a minimum five-second target interval. Temporary SMTP responses and network failures add exponential backoff with jitter. Catch-all control probes consume the same budgets. These limits survive worker restarts and may be lowered by the operator.
When validation fails, a reason field explains why:
{
"data": {
"email": "test@mailinator.com",
"valid": false,
"checks": {
"syntax": true,
"mx": true,
"disposable": true,
"role": false
},
"reason": "Disposable email address"
}
}A suggestion field appears when a common typo is detected (e.g. gmial.com suggests gmail.com).
Batch validation
Validate up to 100 emails in a single request:
curl -X POST https://pushmail.dev/api/v1/validate \
-H "Authorization: Bearer pm_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"emails": [
"alice@gmail.com",
"bob@mailinator.com",
"admin@example.com"
]
}'Response:
{
"data": {
"results": [
{ "email": "alice@gmail.com", "valid": true, "checks": { "syntax": true, "mx": true, "disposable": false, "role": false } },
{ "email": "bob@mailinator.com", "valid": false, "checks": { "syntax": true, "mx": true, "disposable": true, "role": false }, "reason": "Disposable email address" },
{ "email": "admin@example.com", "valid": true, "checks": { "syntax": true, "mx": true, "disposable": false, "role": true } }
],
"count": 3,
"cost": {
"freeUsed": 3,
"paidCount": 0,
"totalCostCents": 0
}
}
}Deep mailbox verification
The core four checks tell you the domain can receive mail. Mailbox verification goes further and confirms the specific address exists, using a provider-aware strategy — because the right way to verify a mailbox depends on who runs it.
PushMail classifies the domain by its MX records, then routes to the best method for that provider:
| Provider | Method | Result |
|---|---|---|
| Microsoft 365 / Outlook / Hotmail | GetCredentialType account lookup | verified — a true exists / not-found answer |
| Google / Yahoo / iCloud | provider lookup (rolling out) + Gravatar corroboration | best_effort — major-provider mailboxes accept all SMTP, so these can't be confirmed with certainty |
| Self-hosted / business domains | Gravatar corroboration (SMTP probe tier available on request) | best_effort or mx_only |
| Catch-all domains | detected and flagged | catch_all — the domain accepts every address, so no per-mailbox answer is possible |
The response adds five fields on top of the core checks:
{
"status": "deliverable", // deliverable | undeliverable | risky | unknown
"confidence": "verified", // verified | best_effort | mx_only | none
"provider": "microsoft", // detected MX provider
"method": "microsoft_getcredentialtype",
"checks": { "...": "...", "mailbox": "exists" } // exists | not_found | catch_all | unverifiable
}status
| Status | Meaning |
|---|---|
deliverable | Mailbox confirmed to exist — safe to send |
undeliverable | Will bounce — bad syntax, no MX, or mailbox confirmed not to exist |
risky | Sendable but uncertain — disposable, role-based, catch-all, or a mailbox we couldn't confirm |
unknown | Not enough signal to classify |
confidence
| Confidence | Meaning |
|---|---|
verified | Provider gave a definitive exists/not-found answer (e.g. Microsoft) |
best_effort | Corroborating signal only (e.g. a matching Gravatar, or an accept-all major provider) |
mx_only | Domain accepts mail but the mailbox couldn't be probed |
none | No mailbox-level signal available |
Honest by design. For accept-all providers (consumer Gmail, catch-all domains) no verifier — SMTP or otherwise — can truly confirm an individual mailbox; that's why these return
best_effort/riskyrather than a false green checkmark. Microsoft-hosted business domains do returnverified. We tell you how confident the answer is, not just pass/fail.
Freshness & caching
Mailbox verdicts are cached per email with a provider-aware TTL — up to 365 days for stable consumer-provider exists results (a Gmail address that exists today almost certainly exists a year from now), shorter for business domains and unconfirmed results. Each cached verdict carries a verifiedAt timestamp; pass maxAgeMs to force a fresh re-verify when you need a guaranteed-current answer. Because the cache is keyed on the address, an address verified once — including through our free tools — is instant (and free of provider calls) on every later lookup.
Rate limits
The validation endpoint is rate limited to 100 requests per minute per organization (same as other API endpoints). Each request can contain up to 100 emails in batch mode, so you can validate up to 10,000 emails per minute.
Error responses
| Status | Meaning |
|---|---|
401 | Missing or invalid API key |
400 | Invalid JSON or missing email/emails field |
402 | Insufficient credits for paid validations |
429 | Rate limit exceeded |
Sender legitimacy check
Email validation asks "can I deliver to this address?". The sender check answers the opposite question: "should I trust mail claiming to come from this address?" Use it to power phishing triage, "is this email legit?" lookups, or inbound-mail screening.
curl -X POST https://pushmail.dev/api/v1/sender-check \
-H "Authorization: Bearer pm_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "email": "account-security-noreply@accountprotection.microsoft.com" }'Response:
{
"data": {
"email": "account-security-noreply@accountprotection.microsoft.com",
"verdict": "verified",
"organization": "Microsoft",
"checks": {
"knownSender": true,
"knownDomain": true,
"lookalike": false,
"punycode": false,
"mx": true,
"spf": true,
"dmarc": "reject",
"disposable": false,
"domainAgeDays": 10403
},
"notes": "Microsoft account security alerts (sign-in notifications, unusual activity, security info changes)",
"explanation": "This is a documented official sender address used by Microsoft. Mail from this address is legitimate if it also passes SPF/DKIM authentication — check the email's headers to confirm it wasn't spoofed."
}
}Verdicts
| Verdict | Meaning |
|---|---|
verified | Exact match against our database of documented official sender addresses |
trusted_domain | The domain belongs to a known organization, but the specific address isn't in our database |
suspicious | Impersonation signals detected: lookalike/typosquat domain, punycode, no mail servers, or disposable domain |
unknown | No impersonation signals, but not a documented sender either — verify through official channels |
Checks
| Check | Description |
|---|---|
knownSender | Exact address match in the known-senders database (Microsoft, Google, Apple, PayPal, Amazon, banks, and more) |
knownDomain | The sending domain matches a known organization |
lookalike | Typosquat/homoglyph detection against commonly impersonated brands (paypa1.com, micros0ft.com, paypal-security.net). When true, lookalikeOf names the imitated domain |
punycode | Domain uses punycode (xn--) labels, often used to disguise lookalike characters |
mx / spf | The domain's mail infrastructure (MX records, SPF policy) |
dmarc | The domain's DMARC enforcement policy (reject, quarantine, none, or null if not published). Subdomains inherit the parent policy |
disposable | The domain is a throwaway email provider |
domainAgeDays | Days since domain registration (via RDAP). Very young domains are a phishing signal |
Batch mode
Like /validate, the sender check accepts { "emails": [...] } with up to 100 addresses per request.
Pricing
Sender checks share the same free tier and credit pool as email validation: the first 100 checks+validations per month are free, then billed at the same per-email volume tiers (from $0.005, dropping with volume).
Note on spoofing: a
verifiedverdict means the address is a documented official sender. It cannot tell you whether a specific email you received was actually sent from that address or spoofed — that requires checking the email'sAuthentication-Resultsheaders (SPF/DKIM/DMARC alignment).
Sending
PushMail sends emails via 10 supported providers. Use our managed infrastructure or bring your own API key for full control over your sending domain and reputation.
Email Providers
PushMail supports 10 email providers via BYOK (Bring Your Own Key). Connect your own SendGrid, SES, Postmark, Mailgun, or any supported provider to send through your own infrastructure.