Skip to content

Email validation vs verification: what each one catches

· 6 min read · Email validation

Email validation answers "could this address work?" Email verification answers "does a real person receive mail at this address and control it?" Validation is cheap, instant and happens before you store anything. Verification needs a round trip through the recipient's inbox, and it is the only step that proves the address is real and belongs to the person typing it.

A common mistake is treating these as one thing. A team adds an "email verification API" to the form, sees fewer bounces, and stops there. Then fake accounts with perfectly deliverable addresses keep coming in, because deliverable and owned are different properties.

Five checks, two families

It helps to split the work into layers. Each one is cheaper than the next and catches a different class of bad input.

Layer Family What it asks Cost Typical latency
1. Syntax Validation Is it shaped like an address? Free, local Microseconds
2. Domain / DNS Validation Does the domain exist and accept mail? DNS queries Tens of ms
3. Classification Validation What kind of domain is it (disposable, webmail, company)? List lookup or API call ms to seconds
4. Mailbox probe Verification (weak) Does the mail server claim the mailbox exists? SMTP connection Seconds, often inconclusive
5. Ownership Verification (strong) Did the person receive and act on a message? One email plus user action Minutes

Layers 1 to 3 are validation. They only look at the address and public data about its domain. Layers 4 and 5 involve the recipient's mail system. Only layer 5 involves the recipient.

What validation catches

Syntax catches typing mistakes, not fake addresses

A syntax check rejects jane@, jane@@gmail.com and jane gmail.com. It should also enforce the length limits in RFC 5321: 64 octets for the local part and 255 for the domain. That is about all it can do. asdf@asdf.com is syntactically perfect. So is an address at a domain registered five minutes ago by someone running a signup script.

Syntax is also where teams over-engineer. A multi-kilobyte regex that tracks every corner of RFC 5322 will happily accept quoted strings and comments that no real user types, and it still won't tell you if the mailbox exists. We cover what a sensible pattern looks like in why an email regex is never enough.

DNS catches dead and mail-less domains

The next question is whether the domain can receive mail at all. That means an MX lookup, with the implicit-MX fallback to A/AAAA records that RFC 5321 section 5.1 describes, and handling of the "null MX" record (MX 0 .) that domains publish to say "we never accept mail". example.com publishes exactly that today. The details, including which DNS errors should never block a signup, are in checking MX records to see if a domain can receive email.

DNS catches typos that land on unregistered domains, and domains that were never meant to receive mail. It does not catch typos that land on registered domains. At the time of writing, gmai.com and hotmial.com both publish MX records, so a DNS check passes them.

Classification catches policy problems

A well-formed address on a domain with healthy MX records can still be one you don't want. Disposable inbox services have excellent DNS; that's their product. Classification asks what kind of domain this is: a throwaway provider, consumer webmail, a university, an ISP, a company. The answer drives policy rather than correctness. You might block disposable domains, route company domains to sales, and leave webmail alone. How to detect disposable email addresses at signup covers the list-based side of this.

This is the layer pingutil handles. One call returns the category, local-part heuristics and a verdict, and check_dns: true adds the DNS facts from layer 2:

const res = await fetch('https://pingutil.com/v1/lookup', {
  method: 'POST',
  headers: {
    authorization: `Bearer ${process.env.PINGUTIL_KEY}`,
    'content-type': 'application/json',
  },
  body: JSON.stringify({ input: email, skip_enrichment: true, check_dns: true }),
});
const data = await res.json();

if (data.verdict.is_spam) {
  // disposable domain, reputation-flagged domain, or machine-generated local part
  return reject('Please use a permanent email address.');
}
if (data.domain_signals && !data.domain_signals.domain_exists) {
  return reject('That domain does not exist. Check for a typo?');
}
// Everything else proceeds to ownership verification.

domain_signals is informational and never changes verdict, so the policy is yours. Treat a null value for domain_signals (lookup unavailable) as "unknown", never as "bad".

What verification catches

SMTP mailbox probes: a weak signal

The idea behind "verify without sending" services is to open an SMTP session with the domain's mail server, issue RCPT TO: for the address, and read the reply before disconnecting. Sometimes that works. Often it doesn't.

Catch-all domains accept every recipient, so every address looks valid. Large providers may accept at RCPT time and bounce later, or rate-limit and greylist unknown senders. The VRFY command, which was designed for this, is commonly answered with RFC 5321's code 252: "Cannot VRFY user, but will accept message and attempt delivery." And cloud platforms often block outbound port 25, so you may not be able to run the probe from your app servers at all. Cloudflare Workers, for example, block outbound TCP to port 25 by default.

The result is a three-way answer (exists, doesn't exist, can't tell) where "can't tell" is common. pingutil doesn't do SMTP probing for these reasons. If you are weighing it anyway, read why SMTP mailbox verification is unreliable and what catch-all domains mean for validation first.

Ownership: the only real verification

Send a message with a link or a short code. If the user clicks or types it back, three things are now true: the mailbox exists, it accepts your mail, and the person filling in the form can read it. No combination of layers 1 to 4 tells you the third one. That third fact is what stops someone signing up with another person's real address.

Ownership verification has costs. Some users never finish it. It delays activation. Mail can land in spam. Those are reasons to design it well (short codes, resend button, let people use the product in a limited mode while unverified), not reasons to replace it with a probe.

Where each check belongs in a signup flow

Here is the order I'd use for a typical SaaS signup:

  1. In the browser: a permissive syntax check (the HTML type="email" behaviour is fine) plus a "did you mean gmail.com?" hint for common typos. Purely for user experience.
  2. On the server, synchronously, before creating the account: syntax again, then classification and DNS. Reject clearly bad input (disposable domain, nonexistent domain, null MX). Keep this under a few hundred milliseconds, and fail open if a dependency times out.
  3. On the server, after creating an unverified account: send the confirmation email. Gate the actions that matter (sending invites, starting a trial with credits, API access) on confirmation.
  4. Later, asynchronously: use bounce and complaint feedback from your email provider to mark addresses that stopped working. This is verification you get for free from the mail you were sending anyway.

Note what's missing: an SMTP probe in the request path. If you want one, run it in the background and use its answer as a scoring signal, never as a hard gate.

Mapping bad inputs to the layer that catches them

Input Caught by
jane@gmail Syntax (no dot, single-label host)
jane@nonexistent-domain-xyz.com DNS (NXDOMAIN)
jane@example.com DNS (null MX)
x7kq2mz9@mailinator.com Classification (disposable)
ccjxx90sze@some-real-company.com Classification heuristics (randomized local part)
typo-of-real-user@gmail.com Ownership only (Gmail won't confirm mailboxes to strangers)
ceo@victim-company.com typed by someone else Ownership only

The last two rows matter most. They're the cases where the address is real and deliverable but the signup is still wrong, and no amount of validation finds them.

The short version

Validate synchronously to reject garbage and enforce policy. Verify ownership with a confirmation message before granting anything worth abusing. Treat SMTP probing as an optional, noisy signal. If you want to see what the validation layers return for a given address, paste it into the live demo or read the full field list in the API reference.

Questions people ask

Is email validation the same as email verification?
No. Validation checks that an address is well formed and that its domain can plausibly accept mail. Verification proves that a real person controls the mailbox, which in practice means they clicked a link or typed a code you sent to it.
Can I verify an email address without sending an email?
Not reliably. SMTP probes that stop before sending a message are often answered with a generic accept or blocked outright, so they give you a guess. The only proof of a working, owned mailbox is a message the user receives and acts on.
Should I validate emails on the client or the server?
Both, for different reasons. Client-side checks give fast feedback on typos. Server-side checks are the ones you can trust, because anything running in the browser can be bypassed.