Email Validation
Email validation checks whether an address is likely to accept mail before you send to it. Running validation before sending reduces bounces, protects your sender reputation, and saves on sending costs.
How it works
Section titled “How it works”The validation pipeline runs 8 checks on each email address:
| Check | What it does |
|---|---|
| Syntax | Verifies the email follows RFC 5322 format |
| MX | Looks up MX records to confirm the domain accepts mail |
| DNS | Resolves A/AAAA records for the domain |
| Disposable | Checks against 3,000+ known disposable email providers |
| Role | Detects role-based addresses like admin@, support@, noreply@ |
| Typo | Suggests corrections for common domain typos (e.g. gmial.com) |
| Free provider | Classifies the domain as free (Gmail, Yahoo) or corporate |
| Random | Detects randomly generated local parts using entropy analysis |
Each check returns a status: pass, fail, warn, or unknown. The results are combined into a risk score (0.0 to 1.0) and a verdict.
Verdicts
Section titled “Verdicts”| Verdict | Risk score | Meaning |
|---|---|---|
deliverable | 0.0 – 0.29 | Safe to send — all checks passed |
risky | 0.3 – 0.69 | Proceed with caution — some checks flagged issues |
undeliverable | 0.7 – 1.0 | Do not send — email is likely invalid or dangerous |
Validate a single email
Section titled “Validate a single email”POST /api/v1/emails/validate
curl -X POST https://api.relaypost.dev/v1/emails/validate \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_API_KEY" \const response = await fetch("https://api.relaypost.dev/v1/emails/validate", { method: "POST", headers: { "Content-Type": "application/json", "Authorization": "Bearer YOUR_API_KEY", },});
const { data } = await response.json();
if (data.verdict === "undeliverable") {console.log("Do not send to this address");} else if (data.verdict === "risky") {console.log("Proceed with caution:", data.checks);} else {console.log("Safe to send");}import requests
response = requests.post( "https://api.relaypost.dev/v1/emails/validate", headers={ "Content-Type": "application/json", "Authorization": "Bearer YOUR_API_KEY", },)
data = response.json()["data"]
if data["verdict"] == "undeliverable": print("Do not send to this address")elif data["verdict"] == "risky": print("Proceed with caution:", data["checks"])else: print("Safe to send")Response
Section titled “Response”{ "data": { "verdict": "deliverable", "risk_score": 0.0, "checks": { "syntax": { "status": "pass" }, "mx": { "status": "pass", "records": [{ "priority": 10, "exchange": "mx.example.com" }] }, "dns": { "status": "pass", "addresses": ["93.184.216.34"] }, "disposable": { "status": "pass" }, "role": { "status": "pass" }, "typo": { "status": "pass", "suggestions": [] }, "free_provider": { "status": "pass", "provider_type": "unknown" }, "random": { "status": "pass" } }, "suggestions": [], "timestamp": "2025-01-15T10:30:00.000Z" }}Validate a batch
Section titled “Validate a batch”POST /api/v1/emails/validate/batch
Validate up to 100 addresses in one request. Each result has the same shape as the single validation response.
curl -X POST https://api.relaypost.dev/v1/emails/validate/batch \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_API_KEY" \ -d '{ "emails": [ "invalid@", ] }'const response = await fetch( "https://api.relaypost.dev/v1/emails/validate/batch", { method: "POST", headers: { "Content-Type": "application/json", "Authorization": "Bearer YOUR_API_KEY", }, body: JSON.stringify({ }), });
const { data } = await response.json();const deliverable = data.filter((r) => r.verdict === "deliverable");console.log(`${deliverable.length} of ${data.length} are deliverable`);import requests
response = requests.post( "https://api.relaypost.dev/v1/emails/validate/batch", headers={ "Content-Type": "application/json", "Authorization": "Bearer YOUR_API_KEY", }, json={ },)
data = response.json()["data"]deliverable = [r for r in data if r["verdict"] == "deliverable"]print(f"{len(deliverable)} of {len(data)} are deliverable")Auto-validation
Section titled “Auto-validation”Instead of validating manually before each send, you can enable auto-validation. When enabled, RelayPost automatically validates every email at send time and rejects addresses that exceed your risk threshold.
Get current threshold
Section titled “Get current threshold”GET /api/v1/settings/auto-validation
curl "https://api.relaypost.dev/v1/settings/auto-validation" \ -H "Authorization: Bearer YOUR_API_KEY"Update threshold
Section titled “Update threshold”PUT /api/v1/settings/auto-validation
curl -X PUT https://api.relaypost.dev/v1/settings/auto-validation \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_API_KEY" \ -d '{ "threshold": "high" }'Threshold levels
Section titled “Threshold levels”| Value | Behavior |
|---|---|
off | No automatic validation (default) |
high | Reject only undeliverable emails (risk score > 0.7) |
medium | Reject undeliverable and risky emails (risk score > 0.3) |
Use cases
Section titled “Use cases”Clean a mailing list
Section titled “Clean a mailing list”Before importing contacts, validate them in batches to remove invalid addresses:
const response = await fetch( "https://api.relaypost.dev/v1/emails/validate/batch", { method: "POST", headers: { "Content-Type": "application/json", Authorization: "Bearer YOUR_API_KEY", }, body: JSON.stringify({ emails }), },);
const { data } = await response.json();const safe = data.filter((r) => r.verdict === "deliverable");// Import only the safe addressesValidate at signup
Section titled “Validate at signup”Check email validity during user registration to catch typos early:
const result = await fetch("https://api.relaypost.dev/v1/emails/validate", { method: "POST", headers: { "Content-Type": "application/json", Authorization: "Bearer YOUR_API_KEY", }, body: JSON.stringify({ email: userInput }),});
const { data } = await result.json();
if (data.verdict === "undeliverable") { showError("This email address appears to be invalid");} else if (data.checks.typo.suggestions.length > 0) { const suggestion = data.checks.typo.suggestions[0].suggested; showSuggestion(`Did you mean ${suggestion}?`);}