MX vs SMTP Validation: When Accuracy Is Worth the Latency
Two Checks, Very Different Guarantees
Your validation pipeline runs an MX lookup. The domain has mail servers. You mark the address as valid and move on.
Six hours later, 12% of your batch bounces.
The MX record proved the domain accepts mail. It said nothing about the mailbox. That gap between “domain exists” and “recipient exists” is the difference between MX validation and SMTP verification, and it’s wider than most developers assume. This post puts numbers on it.
What MX Validation Actually Proves
An MX lookup queries DNS for the mail exchange records of a domain. If records exist, some server somewhere is configured to accept mail for that domain. If no MX records exist, the spec (RFC 5321, Section 5.1) falls back to A/AAAA records, but in practice, no MX usually means no mail service.
Here’s what that looks like at the protocol level:
dig MX gmail.com +short
# 5 gmail-smtp-in.l.google.com.
# 10 alt1.gmail-smtp-in.l.google.com.
# 20 alt2.gmail-smtp-in.l.google.com.
Records returned. Domain can receive mail. Done.
What MX validation catches: nonexistent domains, typo’d domains (gmial.com, gogle.com), parked domains with no mail infrastructure. What it misses: whether [email protected] or [email protected] actually exists as a mailbox. Both queries return the same MX records because the lookup never touches the mail server itself.
That’s a big miss. A domain can have perfectly healthy MX records while half the addresses you’re trying to reach don’t exist.
What SMTP Verification Adds
SMTP verification goes further. It opens a TCP connection to the mail server, walks through the SMTP handshake, and asks the server directly whether it’ll accept mail for a specific recipient. Then it disconnects before sending any actual message.
The conversation looks like this:
C: [connect to port 25 of MX host]
S: 220 mx.example.com ESMTP ready
C: EHLO verify.truemail.io
S: 250-mx.example.com Hello
C: MAIL FROM:<[email protected]>
S: 250 OK
C: RCPT TO:<[email protected]>
S: 250 OK <-- mailbox exists
C: RCPT TO:<[email protected]>
S: 550 5.1.1 User unknown <-- mailbox doesn't exist
C: QUIT
S: 221 Bye
Four commands. EHLO identifies the verifier. MAIL FROM sets a sender envelope. RCPT TO asks the question: will you accept mail for this recipient? The server’s response code tells you the answer. A 250 means yes. A 550 means the mailbox doesn’t exist (RFC 5321, Section 4.2.2). The connection closes before DATA, so no message is ever sent.
That RCPT TO response is the signal MX validation can’t provide. It’s the difference between checking if someone’s building has a mailroom and checking if they have a mailbox in it.
The Latency Gap
Here’s where the trade-off gets concrete.
MX lookup: one DNS query, maybe two if the first nameserver is slow. Typical round-trip: 20-120ms uncached, under 10ms cached. It’s fast because you’re querying DNS infrastructure, not connecting to a remote mail server.
SMTP verification: TCP connection setup, TLS negotiation (if the server supports STARTTLS), four SMTP commands, server processing time on each. Typical round-trip: 500-3,000ms. Some servers respond in 600ms. Others take 2-3 seconds, especially if they run anti-spam checks on the RCPT TO before responding.
That’s a 10-25x latency multiplier. On a single address, barely noticeable. On a signup form where your user is waiting? It’s the difference between a snappy experience and a loading spinner.
On a batch of 10,000 addresses? MX-only validation finishes in under a minute with modest concurrency. Full SMTP verification takes 15-45 minutes depending on server response times and rate limiting.
The Accuracy Gap
Latency is the cost. Accuracy is the payoff.
MX-only validation catches dead domains and typos. It confirms the mail infrastructure exists. But it can’t distinguish a real mailbox from a fabricated one on an active domain. In production benchmarks across mixed B2B and B2C lists, MX-only validation catches roughly 80-85% of truly undeliverable addresses. The remaining 15-20% are addresses on valid domains that will bounce at the mailbox level.
Full SMTP verification adds the RCPT TO check. The server tells you whether the specific recipient exists. Across cooperative domains (non-catch-all, non-greylisting), this pushes accuracy to 95-99% on that subset. But real-world lists aren’t that clean. Hunter.io’s 2026 benchmark tested 15 verification APIs against 3,000 real business addresses. The top-performing provider correctly classified about 71% overall. The rest scored lower. The gap between marketing claims (“99% accuracy”) and independent testing is wide.
Why so low? Gmail returns 250 OK for every RCPT TO, whether the mailbox exists or not. It’s functionally a catch-all. Any list heavy on Gmail addresses tanks verification accuracy because SMTP alone can’t distinguish real from fake. Providers that score higher use proprietary signals beyond the SMTP handshake: historical bounce data, pattern analysis, and engagement heuristics.
The gap between 85% and 95%+ sounds modest in percentage terms. In practice, it’s the difference between a 15% bounce rate and a sub-2% bounce rate. Google’s bulk sender guidelines cap spam complaint rates at 0.3% (as reported in Postmaster Tools). High bounce rates contribute to that signal. Exceed the threshold and you’re looking at throttling, spam folder placement, or outright rejection.
Fifteen percent bounces won’t just hurt deliverability. It’ll wreck it.
Where SMTP Verification Gets Complicated
SMTP verification isn’t a clean binary signal. Several server behaviors muddy the results.
Catch-All Domains
Some servers return 250 OK for every RCPT TO, regardless of whether the mailbox exists. These catch-all domains represent 15-28% of B2B domains. Your SMTP check succeeds, but the address might still bounce after delivery.
Against a catch-all domain, SMTP verification provides zero additional signal over MX validation. Both tell you the server accepts mail. Neither tells you the mailbox is real.
Greylisting
Greylisting servers return a 450 temporary rejection to first-time senders. The server stores the triplet (sending IP, sender address, recipient address) and expects a retry after a delay. Common implementations like Postgrey default to 5 minutes; RFC 5321 recommends clients wait at least 30 minutes before retrying. Legitimate mail servers retry automatically. Spammers usually don’t.
For verification, this means your first RCPT TO attempt gets a 450. You either wait and retry (adding minutes of latency) or mark the address as unknown. Neither option is great for real-time validation.
Rate Limiting
Major providers throttle verification traffic aggressively. Microsoft 365 caps SMTP authenticated submission at 3 concurrent connections per mailbox and 30 messages per minute. Gmail allows 15 simultaneous connections per IP and detects verification patterns, returning 250 OK for every address regardless of existence. If you’re hammering a provider with thousands of RCPT TO queries, expect 421 responses (service not available, try again later) that force backoff.
False Positives From Temporary States
A mailbox that’s full returns 452. A server under maintenance returns 421. These are temporary conditions, not proof the address is invalid. Treating them as permanent failures means you’ll reject addresses that would’ve been fine an hour later.
When MX-Only Is Enough
Not every use case needs SMTP-level accuracy. MX validation wins when speed matters more than precision.
Real-time signup forms. Your user is staring at a form field. Sub-100ms MX validation catches the obvious typos (@gmial.com, @yaho.com) without making them wait. Queue the SMTP check for background processing after signup.
Initial list filtering. You just imported 100,000 contacts from a CSV. Running MX-only as a first pass eliminates dead domains in minutes. Then you can run SMTP verification on the survivors, saving time and API calls.
Low-stakes transactional email. Sending a marketing newsletter to a list you’ve already cleaned? MX validation on new additions keeps the worst garbage out without the overhead of full SMTP checks.
High-volume, low-value flows. Notification emails, activity digests, weekly summaries. If a few bounce, the cost is low. MX validation provides enough filtering without the latency tax.
When SMTP Verification Is Worth It
The latency cost pays for itself when accuracy directly impacts revenue or reputation.
Batch list cleaning. Nobody’s waiting. Run full SMTP verification on your entire database overnight. The 500-3,000ms per address is irrelevant when spread across a worker pool with no user-facing latency constraint.
High-value transactions. E-commerce order confirmation, account recovery, payment receipts. A bounced email here means a lost customer. The extra second of verification time is invisible in a checkout flow that already takes 5-10 seconds.
Cold outreach campaigns. Sending to purchased or scraped lists? Bounce rates will destroy your sending domain if you skip SMTP verification. Every address needs the full check before it enters your send queue. The email validation API guide covers the integration architecture for this.
Compliance-sensitive flows. Financial services, healthcare, legal communications. A bounced email isn’t just inconvenient. It’s a compliance gap. Full verification is table stakes.
The Hybrid Architecture
Most production systems don’t choose one or the other. They run both.
The pattern: MX validation in the synchronous request path for speed, SMTP verification as an asynchronous background job for accuracy. Your user gets instant feedback on typos. Your system gets full verification before the first email sends.
# Real-time: MX-only check at signup (20-120ms)
class RegistrationsController < ApplicationController
def create
quick = MailCop.validate(params[:email], checks: [:syntax, :mx], timeout: 1)
if quick.status == "invalid"
render json: { error: "That email domain doesn't exist" }, status: 422
return
end
@user = User.create!(email: params[:email], email_status: "pending")
SmtpVerificationJob.perform_later(@user.id)
head :created
end
end
# Background: full SMTP verification (500-3000ms, no user waiting)
class SmtpVerificationJob < ApplicationJob
queue_as :default
def perform(user_id)
user = User.find(user_id)
result = MailCop.validate(user.email, checks: [:syntax, :mx, :smtp], timeout: 10)
user.update!(email_status: result.status)
if result.status == "deliverable"
UserMailer.email_confirmation(user).deliver_later
end
end
end
# Python equivalent - FastAPI with background task
from fastapi import FastAPI, BackgroundTasks, HTTPException
import truemail
app = FastAPI()
@app.post("/register")
async def register(payload: SignupRequest, bg: BackgroundTasks):
# Synchronous MX check - fast
quick = truemail.validate(payload.email, checks=["syntax", "mx"], timeout=1)
if quick.status == "invalid":
raise HTTPException(status_code=422, detail="Invalid email domain")
user = await User.create(email=payload.email, email_status="pending")
bg.add_task(verify_smtp, user.id)
return {"id": user.id}
def verify_smtp(user_id: int):
user = User.get_sync(user_id)
# Full SMTP check - slow but thorough (runs in thread pool)
result = truemail.validate(user.email, checks=["syntax", "mx", "smtp"], timeout=10)
user.update_sync(email_status=result.status)
The hybrid approach gives you sub-200ms signup response times with full SMTP-level accuracy on the backend. Your users don’t wait. Your database stays clean. Best of both layers.
Benchmark Summary
Here’s the comparison distilled to the numbers that matter.
| Metric | MX-Only | Full SMTP | Hybrid |
|---|---|---|---|
| Latency per address | 20-120ms | 500-3,000ms | 20-120ms sync + async |
| Accuracy (cooperative domains) | ~80-85% | 95-99% | 95-99% |
| Accuracy (real-world mixed lists) | ~80-85% | 60-75% overall | 60-75% + heuristics |
| Catch-all detection | No | Detects, can’t resolve | Detects, can’t resolve |
| Greylisting handling | N/A | Requires retry logic | Retry in background |
| User-facing delay | Minimal | Noticeable | Minimal |
| Best for | Real-time filtering | Batch cleaning | Production systems |
The right answer for most teams? Run both. MX for speed when the user is waiting. SMTP for accuracy when they’re not.
If you’re building an email validation API integration, start with the hybrid pattern. It handles the 90% case. Add specialized catch-all scoring and greylisting retry logic as your volume grows and the edge cases start to bite.
What the Numbers Don’t Show
The accuracy numbers above assume cooperative domains that give honest RCPT TO responses. Catch-all domains (including Gmail’s consumer service) return 250 OK for everything, so SMTP verification provides no signal at all on those addresses. With 15-25% of typical B2B lists sitting on catch-all domains, and consumer lists skewing heavily toward Gmail, pure SMTP accuracy drops fast. Greylisting adds unpredictable latency that can push individual verifications past 30 seconds if retries are involved.
Your actual performance depends on the mix of domains in your list, the mail servers those domains use, and how aggressively those servers throttle verification traffic. A list heavy on Microsoft 365 and Google Workspace domains will behave differently than one full of self-hosted Postfix servers. Providers that score highest in independent benchmarks layer proprietary heuristics on top of SMTP: bounce history, engagement signals, pattern matching. The SMTP handshake is the foundation, not the ceiling.
Test against your own data. The benchmarks tell you what’s possible. Your list tells you what’s real.