Email Validation Overview
Cleanmails includes a built-in email validation engine that checks addresses through multiple layers. Validation runs as a background job when you trigger it on an uploaded lead list — results appear in real-time on the leads table.
Validation Pipeline
Each email in your lead list goes through these checks (in order):
| Step | Check | What It Does |
|---|---|---|
| 1 | Syntax validation | RFC 5322 compliant regex check — catches obvious typos |
| 2 | Disposable detection | Checks against 120,000+ known disposable/throwaway domains |
| 3 | Role-based filter | Identifies generic addresses (info@, admin@, support@, etc.) |
| 4 | Free email flag | Flags Gmail, Yahoo, Outlook, and other free providers |
| 5 | DNS MX lookup | Verifies the domain has valid mail exchange servers (5s timeout) |
| 6 | A-record fallback | Falls back to DNS A record if no MX records found |
| 7 | Domain suggestion | Suggests corrections for typos (e.g., gmial.com → gmail.com) |
Validation runs as a background job in the Asynq worker's default queue with 100 concurrent goroutines. Results are written to PostgreSQL as each lead is processed — the frontend shows progress in real-time.
Scoring System
Each lead receives a score from 0–100 based on the checks above:
| Factor | Points |
|---|---|
| Valid syntax | +20 |
| Has MX records | +35 |
| Not a role account | +15 |
| Not a free email | +15 (free emails get +5) |
| Reachable assessment | +10 to +15 |
| Disposable domain | Instant invalid (score: 5) |
| No MX records | Instant invalid (score: 10) |
Score Categories
| Score Range | Status | Color | Meaning |
|---|---|---|---|
| 60–100 | Valid | Green | Safe to send — high confidence deliverable |
| 35–59 | Risky | Amber | May bounce — use with caution |
| 0–34 | Invalid | Red | Will likely bounce — do not send |
How to Validate Leads
Upload a CSV list, then trigger validation from the dashboard or via API:
# Step 1: Upload a CSV lead list
curl -X POST https://YOUR_SERVER/api/v1/workspaces/1/leads/upload \
-H "Cookie: auth_token=YOUR_JWT_TOKEN" \
-F "file=@leads.csv"
# Step 2: Trigger validation
curl -X POST https://YOUR_SERVER/api/v1/workspaces/1/leads/validate \
-H "Content-Type: application/json" \
-H "Cookie: auth_token=YOUR_JWT_TOKEN" \
-d '{"list_id": 1}'
# Step 3: Check results (updated in real-time as validation progresses)
curl https://YOUR_SERVER/api/v1/workspaces/1/leads \
-H "Cookie: auth_token=YOUR_JWT_TOKEN"You can also trigger validation directly from the lead list card in the dashboard — click the list, then hit the Validate button. A progress bar shows real-time status.
CSV Format
The uploaded CSV should include at minimum an email column. Additional supported columns:
| Column | Description |
|---|---|
email | Email address (required) |
first_name | First name (used in campaign personalization) |
last_name | Last name |
company | Company name |
job_title | Job title |
phone | Phone number |
Duplicate emails within the same workspace are automatically deduplicated via a database unique index.
Performance
| Metric | Value |
|---|---|
| Concurrency | 100 parallel goroutines per validation job |
| Disposable blocklist | 120,000+ domains |
| Score range | 0–100 per email |
| Queue priority | Default queue (weight 3) |
| Max retry | 2 attempts on failure |