You've imported a fresh CSV, connected it to your ESP, and scheduled the campaign. Then the bounce notifications arrive. Some addresses were mistyped, several domains no longer accept mail, and a few servers reject every recipient your system thought was valid. The problem usually isn't a missing regex. It's treating email testing as a single pass instead of a system that runs throughout an address's lifetime.
A production-grade approach answers several different questions: Is the string shaped like an email address? Does the domain route mail? Does the receiving server appear to recognize the mailbox? Is the address risky even if it responds positively? The answer can change after signup, so real-time checks and periodic list verification belong in the same workflow.
Table of Contents
- Why Testing Email Addresses Matters Before You Send
- Checking the Format and Syntax First
- Domain and MX Record Lookups That Reveal Routing
- Probing the Mailbox With SMTP
- Bulk Testing Versus Real-Time Signup Checks
- Reading Scores, Reason Codes, and Tooling Output
- Practical Checklist and Troubleshooting Common Failures
Why Testing Email Addresses Matters Before You Send
Bad addresses create more than a few failed deliveries. Hard bounces give mailbox providers evidence that your list quality is poor, which can weaken sender reputation and reduce inbox placement for messages that would otherwise succeed. Spam traps create a different risk because they can expose acquisition and hygiene failures without behaving like ordinary invalid mailboxes. Your ESP may also charge for attempted sends, so retaining unusable records increases operational waste.
Unverified cold lists commonly contain about 20% to 40% invalid addresses, according to industry email verification statistics. On a list of 100,000 records, that means 20,000 to 40,000 addresses may be bad before sending. The same source reports that verification can reduce bounce rates by 60% to 80% after cleanup, although the result depends on the list, provider mix, and how the verification service handles uncertain responses.

The four signals worth keeping
A useful pipeline narrows risk in stages:
- Syntax: Reject malformed input before making network calls.
- Domain routing: Confirm that the domain exists and publishes mail-exchange information.
- SMTP behavior: Ask the receiving server whether it appears to accept the recipient, without transmitting message content.
- Heuristics: Identify disposable domains, role accounts, catch-all behavior, free-provider addresses, and other conditions that affect business decisions.
A team that skips verification might send a campaign, see widespread hard bounces, clean the file, and repeat the mistake on the next import. A better rebuild stores each result and reason code, quarantines uncertain records, and runs the same checks both at signup and before high-volume sends.
The historical basis for this layered process comes from email's delivery standards. SMTP was first standardized in RFC 821 in 1982 and later revised by RFC 5321 in 2008, which formalized envelope behavior and delivery rules still used by validators. A deliverability benchmark discussing SMTP standards describes the technical foundation behind syntax checks, MX lookups, and mailbox-oriented SMTP behavior.
Practical rule: A “valid” result should mean “safe enough for the next action,” not “guaranteed to receive every future message.”
Checking the Format and Syntax First
Syntax validation is the cheapest layer, so run it before DNS or SMTP. Start by removing accidental whitespace and display-name wrappers such as John Doe <john@example.com>. Preserve the address itself, but avoid destructive normalization. Lowercasing the domain is safe because DNS names are case-insensitive. The local part can be case-sensitive under the specification, even though many providers treat it as case-insensitive, so only apply provider-aware normalization when you know the mailbox system supports it.
Plus-addressing deserves deliberate handling. user+filter@example.com may be a real delivery address, not a duplicate or an error. Some products should preserve the tag for account identity and routing, while analytics systems may derive a separate canonical value. Don't strip it at ingestion.
A validator should enforce structural rules rather than attempt to describe every legal mailbox syntax with one enormous regular expression. Check for a single usable separator, a nonempty local part and domain, valid dot placement, valid domain labels, and a total address length within the limits your implementation supports. The email validation format guidance is useful when deciding which syntax rules belong in the application layer.
Examples that expose weak validators
| Input Address | Expected Result | Reason |
|---|---|---|
user.name+filter@example.co.uk |
Pass | Normal local-part characters, plus tag, and multi-label domain |
.leading@x.com |
Fail | The local part begins with a dot |
name..section@example.com |
Fail | Consecutive dots are not valid in an unquoted local part |
John Doe <john@example.com> |
Normalize, then pass | Strip the display-name wrapper before validation |
user@192.168.1.1 |
Require explicit handling | A domain-literal address needs bracketed syntax if your product supports it |
büro@example.com |
Normalize deliberately | Internationalized addresses require provider and library support |
user@example.com |
Trim, then validate | Trailing pasted whitespace must not enter the stored value |
Naive regexes often accept consecutive dots, consume trailing whitespace, or reject legitimate plus-addressing. They can also mishandle quoted local parts and internationalized domain names. For IDN domains, convert the domain to its ASCII-compatible punycode representation for DNS operations while retaining the user-facing form where appropriate.
Keep syntax results separate from deliverability results. valid_syntax means the string is structurally plausible. It doesn't mean the mailbox exists, the domain routes mail, or the recipient wants your message.
Domain and MX Record Lookups That Reveal Routing
A syntactically correct address can still point to a nonexistent or non-mail domain. DNS gives you the next signal by showing whether the domain exists and where it expects incoming mail to go. A domain with no usable mail-exchange route has nowhere to deliver the message, so an SMTP probe would either fail or waste time.
For a quick investigation, query the domain's MX records with a command such as dig MX example.com +short or use nslookup -type=mx example.com. In returned records, compare exchanger preference values and inspect the time-to-live value. Preference helps you understand which server is preferred when multiple exchangers exist. TTL tells you how long a resolver may cache the answer, which matters when a provider changes routing.

Interpret DNS outcomes instead of flattening them
- NXDOMAIN: The domain doesn't exist. A typo, expired registration, or disposable-domain entry is likely.
- NoError with an empty MX response: The domain exists but doesn't publish a mail exchanger. Your resolver may need to apply fallback behavior, so classify this carefully rather than treating every response identically.
- Unexpected aliasing: A configuration that wraps an apex in a CNAME can behave differently across DNS providers and resolver implementations.
- Dead exchanger target: The domain publishes a route, but the target host may no longer accept connections or may belong to an abandoned provider.
Inline DNS lookups are reasonable for a small service, but they add latency and create resolver-management work in a large batch pipeline. A managed MX record checker can cache common domain results, amortize lookup cost, and centralize retries and failure classification.
Caching needs boundaries. Don't cache a domain result forever, and don't treat a temporary resolver timeout as proof that every address at the domain is invalid. Store the lookup timestamp, response state, and relevant records so a later decision can distinguish “no mail route” from “DNS was unavailable during the check.”
Probing the Mailbox With SMTP
SMTP probing starts after syntax and routing checks. The verifier connects to the receiving mail server, identifies itself, issues MAIL FROM, and then sends RCPT TO for the address under test. It stops before DATA, so it doesn't transmit a message body.
A 250 response to RCPT TO is a strong positive signal, but it isn't proof that a person reads the mailbox or that your future message will reach the inbox. A 550 response often indicates a permanent rejection, yet some providers use it for policy decisions or anti-abuse behavior. A 450 or 451 response generally means the server wants a retry, not that the mailbox is definitely invalid.

Why a positive reply can mislead you
Catch-all domains accept mail for recipients that don't exist. Their server may return 250 for a real address and a deliberately random address alike, then decide what to do later. A verifier should test catch-all behavior with a controlled comparison and record accept_all rather than presenting every recipient as confidently valid.
Greylisting creates another ambiguous case. The first connection may receive a temporary response, and a later attempt may produce a different result. Providers also throttle repeated probes, especially when many recipients share a domain. A fast loop that looks efficient in a slide deck can produce more unknown results and more blocks than a controlled worker pool.
The practical state machine is small:
- Connect to the destination server and respect its greeting.
- Issue
MAIL FROMwith a controlled envelope sender. - Issue one
RCPT TOfor the candidate address. - Parse the response code and enhanced status where available.
- Stop without issuing
DATA. - Store the result as valid, invalid, accept-all, or unknown.
The SMTP verification glossary provides useful terminology for teams implementing or reviewing this layer.
Rate limits matter on both sides. Use bounded concurrency, retry temporary responses with backoff, and avoid sending probes from infrastructure that resembles a spam operation. A dedicated sender identity can help separate verification traffic from application mail, but it doesn't remove provider policies or guarantee cooperation.
Watch the accompanying walkthrough after reviewing the state machine. It's most useful when you compare the server response with the reason code your own system stores.
Bulk Testing Versus Real-Time Signup Checks
A CSV cleanup and a signup gate solve different timing problems. Bulk verification can spend more time on each record because the user isn't waiting for a form response. A signup check has to protect the user experience, so it should return quickly and avoid unnecessary network work.
For bulk jobs, use the complete pipeline. Normalize the input, validate syntax, inspect domain routing, probe SMTP where appropriate, and apply disposable, role-account, and catch-all heuristics. Preserve the original value, normalized value, check timestamp, provider response, and final decision. If you enrich the file, keep enrichment separate from deliverability so a failed enrichment call doesn't erase a useful verification result.
Real-time signup checks should use a smaller decision path. Syntax and MX results are inexpensive, while role-account and disposable-domain checks can often run from local or cached data. An SMTP result cached by domain and recipient state can reduce repeated network calls, but cache entries need expiry because mailbox conditions change.
Three ways to pair the workflows
Signup only is simple, but it leaves aging records untreated. A mailbox can become unavailable after capture, and a valid address can later become risky when provider policies change.
Bulk only protects campaign sends but allows low-quality records into your product database. That contaminates activation metrics, notification queues, and support workflows before marketing ever imports the list.
Continuous pairing works better operationally. The signup service accepts, challenges, or blocks the address, then a scheduled bulk job rechecks older segments and feeds reason-code changes back into suppression and CRM systems.
| Dimension | Real-Time Signup Check | Bulk CSV Verification |
|---|---|---|
| Primary objective | Prevent poor data at capture | Reduce risk before a send or import |
| Latency preference | Short and predictable | Slower processing is acceptable |
| Typical signals | Syntax, MX, cached risk data, role and disposable flags | Full syntax, DNS, SMTP, catch-all, and heuristic pipeline |
| Output action | Accept, challenge, or reject the form | Suppress, quarantine, review, or export |
| Main limitation | Limited time for deep probing | Doesn't protect addresses captured afterward |
For bulk work, throttle workers and retry temporary responses instead of treating timeouts as invalid. For signup, challenge uncertain users with confirmation email, double opt-in, or another anti-abuse step rather than blocking every address that lacks a definitive positive result.
Reading Scores, Reason Codes, and Tooling Output
A boolean result is convenient for a demo and inadequate for production. The reason code tells your application what happened, what message to show, and whether the record deserves another check. Store both the raw provider response and your normalized internal classification.
Common codes include:
invalid_syntax: The input fails structural validation.no_mx: The domain has no usable mail route.role_account: The address appears to represent a function such as support or sales rather than an individual.accept_all: The server accepts arbitrary recipients, so the mailbox result is uncertain.smtp_invalid: The server rejected the recipient during the probe.smtp_unverified: The response was temporary, inconclusive, or blocked.mailbox_full: The provider indicates a capacity problem that may be temporary.disposable: The domain matches a temporary-mail classification.spam_trap: The address is associated with a known trap signal and should be handled as high risk.
Some systems expose numeric scores built from weighted dimensions. Treat those scores as decision support, not universal truth. A single score can hide why an address was classified as risky, and the same numeric value may require different treatment in a password-reset flow and a promotional campaign.
Use operational states instead of one pass gate
Map reason codes to outcomes that fit the workflow:
- Allow: The address is deliverable enough for the intended action.
- Allow with monitoring: The server responded, but catch-all, role-based, or other risk signals warrant observation.
- Challenge: Require confirmation, CAPTCHA, or double opt-in before activating the record.
- Block: Reject malformed, unroutable, disposable, or known trap addresses when your policy requires it.
An open-source stack can combine Python's email-validator, dnspython, and a carefully controlled SMTP probe. That gives engineering teams transparency, but they must maintain provider exceptions, retries, DNS behavior, and reputation data themselves. Paid APIs add operational history, disposable-domain intelligence, and feedback from prior sends, which can be more valuable for marketing databases than a locally calculated syntax result.
For transactional systems, don't over-block. A role address may be the customer's legitimate billing contact, and an SMTP-unknown result may reflect temporary provider defenses. Marketing teams can apply stricter quarantine rules because the cost of repeatedly sending to risky records is higher.
Practical Checklist and Troubleshooting Common Failures
Verification works best as an ongoing maintenance runbook. Set it up once, then run it repeatedly across signup flows and list pipelines. At capture time, normalize the input, check syntax, inspect domain routing, apply disposable and role-account rules, and decide whether an uncertain result needs a challenge. Before a bulk send, recheck aging segments and review recent bounce reasons.
A recurring review should include:
- Review recent bounces: Group them by the provider response and your internal reason code.
- Re-probe uncertain records: Retry temporary SMTP responses instead of suppressing them immediately.
- Quarantine suspicious rows: Separate catch-all, disposable, role-based, and trap-like records from confident deliverables.
- Record timestamps: Store the DNS and SMTP check time beside every decision.
- Document skipped layers: If provider restrictions prevented SMTP checks, record that limitation.
- Revisit old segments: Addresses decay over time, so a one-time cleanup cannot protect later sends.
For list hygiene, an operational benchmark is to keep bounce rates under 2%, while rates above 5% are treated as high-risk deliverability damage in email deliverability guidance from Cleverly. The same guidance describes well-maintained lists around 1.2% average bounce and reports that real-time verification programs can reach roughly 0.3% bounce rates with about 95% inbox placement. Use these figures as operating references, not promises for every sender or mailbox mix.
| Failure Mode | Likely Cause | Fix |
|---|---|---|
| Greylisting | The server temporarily defers unfamiliar probes | Retry with backoff, then classify as unknown if the response stays ambiguous |
| Catch-all false positive | The domain accepts arbitrary recipients | Run a controlled catch-all test and route the result to monitoring or challenge |
| Expired domain with MX | DNS records remain after the organization stops using the domain | Check domain status, probe the exchanger, and quarantine inconsistent results |
| Role-address bounces | A shared inbox rejects external or bulk mail | Keep the address for transactional use only when policy allows, or challenge it for marketing |
| IPv6-only mail server | Your probe infrastructure lacks compatible connectivity | Add IPv6 support or use a verifier that can reach the destination |
| Temporary MX outage | DNS or provider infrastructure is unavailable during the check | Store the timestamp, retry later, and avoid permanent suppression from one failed lookup |
Technical readiness does not guarantee inbox placement. A 2025 deliverability report says visible mailbox placement was 66% globally, while SPF adoption reached 90% and DKIM reached 87%. It also notes that spam placement could exceed 30% in some cases even with full SPF, DKIM, and DMARC. The 2025 deliverability report shows the boundary of verification: it can assess address and server signals, but cannot certify that a future message will reach the inbox.
A separate Validity 2025 benchmark report observed an unexpected nearly 5% deliverability decline and identified Microsoft as the toughest major mailbox provider at 75.6% inbox placement. Provider behavior changes, engagement filters tighten, and DNS answers age. Store every result with its probe time, then run periodic re-verification instead of trusting an old pass indefinitely.
Mailbeam provides a developer-facing API and bulk tools that combine syntax, MX, SMTP, disposable-domain, role-account, and catch-all checks with machine-readable reason codes. Teams can use it to add continuous verification to signup flows and list maintenance without building the complete probe and retry system themselves. Review the integration options at Mailbeam.
