Regex-validating an email address only tells you the syntax is plausible. It says nothing about whether user@totallyfakedomain12345.com can receive mail. An MX record lookup closes that gap for basically zero extra latency.
import { resolveMx } from "node:dns/promises";
async function domainCanReceiveMail(domain) {
try {
const records = await resolveMx(domain);
return records.length > 0;
} catch {
return false;
}
}
This won't catch every typo (an MX record existing doesn't mean the specific mailbox exists — that needs an actual SMTP handshake, which is slow, unreliable, and often blocked by mail servers as spam-probing behavior). But it's a strong, cheap signal that catches a meaningful chunk of junk signups before you send a verification email into the void.
I run this as an optional flag on the email endpoint of Validate — syntax check always runs, MX check is opt-in since it adds a DNS round-trip. Sibling APIs on the same account: QR API and Currency API.
Top comments (1)
MX is the right cheap gate. Syntax alone is cosplay.
The part Id add next is disposable freshness. A domain can have perfect MX and still be a 10-minute burner. Static lists rot in days, so pair MX with a list that actually moves, plus soft score on brand-new domains instead of a hard reject.
Also allowlist Apple Hide My Email / SimpleLogin. They look weird and theyre real people.
Skipping SMTP RCPT as the main gate is the right call. Slow, often blocked, catch-alls lie. Keep confirmation email for ownership.
Curious if Validate fails open on DNS timeout or treats lookup failure as invalid.