An email checker answers one question at scale: does this address actually receive mail — and the honest answer has five verification levels, each more expensive than the last, each lying less. Syntax validation catches malformed strings in microseconds with zero network cost. DNS/MX lookup confirms the domain publishes mail-exchanger records (a domain without MX is either dead or uses implicit A-record mail — the distinction worth a query). SMTP handshake probing — connecting to the domain's mail server and walking the RCPT TO dialogue without sending mail — tells you whether the server claims the mailbox exists (catch-all servers claim everything, which is the layer's honest limitation, not a bug). Full verification (actual delivery) is the expensive truth-tier most mass tools skip. This is email-checker making decoded: the five-level pipeline, the catch-all and disposable-domain problems that break naive checkers, the mass architecture (per-domain connection pooling, throttling that keeps SMTP servers from blacklisting the checker), and the output taxonomy that downstream pipelines actually consume.
ROUTE MAP (PLAIN ENGLISH)
The five levels run in strict order, each gated on the previous level's pass: syntax (RFC-shaped validation — format well-formedness, TLD presence, no consecutive-dot or label-length violations — catches typos and malformed concatenations at zero cost); domain resolution (the domain resolves in DNS at all — NXDOMAIN kills the line before any mail-server contact); MX lookup (the domain publishes MX records; domains with MX-null (MX 0 .) explicitly refuse mail — a distinct dead-class from no-MX; domains with no MX but resolvable A records fall back to implicit-A mail per RFC — probed with a different expectation than MX-declared servers); SMTP RCPT probe (TCP connect to the highest-priority MX, SMTP handshake, MAIL FROM, RCPT TO with the candidate address, reading the server's response code — 250 means the server claims the mailbox, 550-class means rejected, 4xx-class means temporary defer needing retry; the probe ends at RCPT response and QUIT, no mail sent); and full-verify (actual message delivery to confirm — expensive, slow, the tier only low-volume high-accuracy needs, skipped by mass pipelines that accept RCPT-level truth).
The two structural problems define the craft. Catch-all servers accept RCPT for every address at the domain (accept-all configurations common on corporate and some hosting mail) — RCPT-probe classifies everything valid, which is honest (the server does accept the mail) but useless for list-hygiene (dead addresses pass); the checker's catch-all detection (probe a random improbable address — a guaranteed-nonexistent string like a long UUID at the domain — and if the server accepts that too, flag the whole domain catch-all, classify all its RCPT-passes as catch-all-qualified rather than verified) is the difference between a checker that knows its own accuracy and one that lies silently. Disposable-domain tracking (the rotating temporary-email services) deserves its own class rather than dead: these addresses work exactly as designed (they receive mail, briefly), which is why downstream consumers filter them by class rather than trusting a binary valid/invalid.
STEP 1 - LEVELS ONE THROUGH THREE, THE CHEAP TRUTH
STEP 2 - THE SMTP PROBE, HONESTLY
STEP 3 - MASS ARCHITECTURE
STEP 4 - CATCH-ALL, DISPOSABLE, AND HONESTY
WORKED EXAMPLE - A 20,000-ADDRESS LIST
Input: 20,000 addresses, mixed sources. Syntax layer kills 412 malformed and 187 typo-domains (probable-intended recorded per line) — 19,401 proceed. Domain/MX layers: 298 NXDOMAIN dead, 44 MX-null refuse, 312 implicit-A flagged — 18,747 reach MX-published domains. Provider map paces the SMTP layer: 23 major-provider domains routed through provider-aware pacing (slower RCPT-per-connection), 890 other domains through standard pools. Random-probe flags 214 domains catch-all (their 1,847 RCPT-passes reclassify catchall-qualified). SMTP first pass: 11,203 verified (RCPT-250 on non-catch-all), 3,411 dead (550-class extended-codes preserved), 892 defer-4xx (retry queue), 301 policy-554 (checker-sender blocked at those domains — egress/sender rotation queue), 2,844 catchall-qualified, 156 disposable-matches on the list-layer. Retry pass after greylist-window backoff: 641 of the 892 defers convert to verified (greylist acceptance on re-contact — confirming the retry-class design), 251 stay deferred (re-run class). Final tallies: 11,844 verified, 3,411 dead, 2,844 catch-all-qualified, 251 defer-parked, 301 policy-parked, 156 disposable — run report showing the honest accuracy story: 11,844 verifieds are RCPT-level truths on non-catch-all domains; the 2,844 catchall-class are server-accepted-but-unverifiable; and the 214 catch-all domains' presence (heavy in the list's corporate-source segment) means a naive checker would have reported 14,688 "valid" — inflating by 24% over honest classification.
WORKING SEQUENCE
QUICK ANSWERS
RELATED
The five levels run in strict order, each gated on the previous level's pass: syntax (RFC-shaped validation — format well-formedness, TLD presence, no consecutive-dot or label-length violations — catches typos and malformed concatenations at zero cost); domain resolution (the domain resolves in DNS at all — NXDOMAIN kills the line before any mail-server contact); MX lookup (the domain publishes MX records; domains with MX-null (MX 0 .) explicitly refuse mail — a distinct dead-class from no-MX; domains with no MX but resolvable A records fall back to implicit-A mail per RFC — probed with a different expectation than MX-declared servers); SMTP RCPT probe (TCP connect to the highest-priority MX, SMTP handshake, MAIL FROM, RCPT TO with the candidate address, reading the server's response code — 250 means the server claims the mailbox, 550-class means rejected, 4xx-class means temporary defer needing retry; the probe ends at RCPT response and QUIT, no mail sent); and full-verify (actual message delivery to confirm — expensive, slow, the tier only low-volume high-accuracy needs, skipped by mass pipelines that accept RCPT-level truth).
The two structural problems define the craft. Catch-all servers accept RCPT for every address at the domain (accept-all configurations common on corporate and some hosting mail) — RCPT-probe classifies everything valid, which is honest (the server does accept the mail) but useless for list-hygiene (dead addresses pass); the checker's catch-all detection (probe a random improbable address — a guaranteed-nonexistent string like a long UUID at the domain — and if the server accepts that too, flag the whole domain catch-all, classify all its RCPT-passes as catch-all-qualified rather than verified) is the difference between a checker that knows its own accuracy and one that lies silently. Disposable-domain tracking (the rotating temporary-email services) deserves its own class rather than dead: these addresses work exactly as designed (they receive mail, briefly), which is why downstream consumers filter them by class rather than trusting a binary valid/invalid.
STEP 1 - LEVELS ONE THROUGH THREE, THE CHEAP TRUTH
- Syntax layer: RFC-shaped validation — local-part rules (dot-atom vs quoted-string forms, no leading/trailing/double dots in dot-atom, label length caps, total length caps), domain-label rules (hyphen-position constraints, TLD presence, no all-numeric TLD), and normalization (case-folding the domain, preserving local-part case since some servers treat it case-sensibly in theory if almost never in practice); the layer's value: kills malformed lines before they earn DNS or SMTP cost, and the catch-rate on typo-heavy lists runs high enough to pay for the whole checker's existence.
- Domain and MX layers: A/AAAA resolution for the domain (NXDOMAIN class), MX record lookup (priority-ordered mail-exchanger list), MX-null detection (explicit refuse — distinct dead-class), and implicit-A fallback flagging (no-MX with resolvable A — mail assumed at the domain itself per RFC, probed with adjusted expectations); the MX list feeds the SMTP layer's connection queue (highest-priority first, failover down the list on connection failure).
- Provider-aware shortcuts: known-provider domains (the major free-mail providers, common corporate-mail providers) route to provider-aware handling — some publish mailbox-existence signals through other channels, some aggressively rate-limit RCPT probing (which the mass-architecture section's throttling must respect), and some implement catch-all-by-default at the edge; the provider map (built from observed behavior, not documentation) lets the checker pace and classify per-domain-class instead of one global policy that misfits both ends.
- Typo-domain detection: the syntax layer's sibling — addresses whose domain almost-matches a known major provider with a one-character deviation (gnail, yaho, hotmal classes) classify as typo-dead with the probable-intended-domain recorded, which downstream consumers use for auto-correction suggestions; this layer alone justifies email checkers on subscriber-list hygiene deployments, where typo domains run 1-3% of typical inbound lists.
STEP 2 - THE SMTP PROBE, HONESTLY
- Connection discipline: TCP connect to the MX (highest-priority first, timeout budgeted tight — connect failures failover the MX list, not classify the address), SMTP handshake (EHLO with a properly-formed checker domain, honoring the server's advertised capabilities), MAIL FROM (a checker-domain envelope sender — the from-address's reputation matters: some servers greylist unknown senders on first contact, which the retry-class handles rather than classify dead), then the RCPT TO probe itself.
- Response-code taxonomy: 250-class = server claims mailbox (qualified by the domain's catch-all status — verified where the domain is not catch-all, catch-all-qualified where it is); 550-class (including 550 5.1.1 user-unknown variants) = rejected, dead-class with the server's extended status code preserved; 4xx-class (421, 450, 451, 452 families) = temporary defer, retry-class with backoff — never dead on 4xx, ever; 5xx non-550 (554 rejections on policy grounds) = policy-class, domain-blocked rather than address-dead — the distinction matters because policy-rejections apply to the checker's sending identity, not the address's existence.
- Greylisting and first-contact friction: many servers greylist unknown senders (4xx on first contact, accept on retry from same IP+sender within a window) — the checker's retry-class handles this (backoff minutes, re-probe from same egress), and the retry budget reflects reality: one retry on 4xx is not enough against greylisting windows, two-to-three retries with real backoff is the working pattern; greylist-heavy domains' first-pass stats always undercount valids, which is why the run report separates first-pass and post-retry tallies.
- QUIT discipline and connection hygiene: clean SMTP termination per probe, connection reuse where the server allows multiple RCPT per session (MAIL FROM once, multiple RCPT TO, QUIT — massive throughput improvement on cooperative servers), and per-connection RCPT caps (hammering one server with hundreds of RCPT on one session triggers tarpitting and blacklisting — the pacing layer's per-domain throttle counts RCPT per connection, not just connections per minute).
STEP 3 - MASS ARCHITECTURE
- Connection pooling per domain: one SMTP connection per domain (or small pool) reused across that domain's candidate addresses (the RCPT-multiplexing pattern) — connection setup is the expensive part of SMTP probing, and a domain with 500 candidate addresses should not open 500 connections; the pool's per-connection RCPT cap and pacing throttle keep the server happy (tarpit avoidance) while the domain's queue drains through the shared connection.
- Concurrency model: async worker pool for DNS layers (massively parallel — DNS servers expect and handle query volume), worker pool with per-domain serialization for SMTP layers (concurrent across domains, sequential-with-pacing per domain) — the two-layer model (parallel DNS, serialized-per-domain SMTP) is what keeps mass runs fast without domain-level bans; egress strategy: multiple source IPs distributed across the SMTP layer's connections so one domain's throttle does not serialize the whole batch behind one exit's pacing.
- Retry scheduling: 4xx-class and network-failure lines park in a retry queue with domain-aware backoff (greylist-window-aware timing on first retry, exponential beyond), re-entering the SMTP layer when their backoff expires — the batch's wall-clock spans the retry windows, which is why the run report shows first-pass and final-class tallies separately (first-pass undercounts greylist-heavy domains, final includes retried valids).
- Output classes: verified.txt (RCPT-250 on non-catch-all domain), catchall.txt (domain flagged catch-all — address unverifiable at this layer, domain-class recorded), dead.txt (550-class with extended-code preserved), typo.txt (with probable-intended-domain), disposable.txt (known temporary-mail service — domain-class recorded), policy.txt (554-policy-class — checker's sending identity blocked, domain needs different egress or sender before re-probe), defer.txt (4xx retry-exhausted — temporary, re-run class not dead), unknown.txt (network-layer tool-side failures, never dead).
STEP 4 - CATCH-ALL, DISPOSABLE, AND HONESTY
- Catch-all detection protocol: per-domain random-probe (a long improbable local-part — UUID-class string — at the domain); 250-response = catch-all domain, flagged domain-class; every subsequent RCPT-250 at that domain classifies catchall-qualified rather than verified — the checker's output honestly records what the server claimed without overclaiming what it knows; domains flip catch-all status (hosting changes, config changes) so the flag ages like every other classification, re-probed on refresh passes.
- Disposable-domain tracking: maintained lists of known temporary-mail services (updated periodically — the services rotate domains constantly, which is why the list is a living artifact, not a shipped-static); matches classify disposable-class rather than dead (the address receives mail — briefly, by design — and downstream consumers' policies on disposable-range from different); unknown-new disposable domains slip past the list (the list-game's honest limitation), and provider-behavior heuristics (mail-domain age, MX patterns) catch some newcomers before the list does.
- Role-account classes: postmaster, abuse, info, admin, support at any domain — RFC-significant addresses that exist structurally but are not personal mailboxes; downstream marketing-hygiene deployments filter them separately (role ≠ personal ≠ dead), transactional deployments often keep them (postmaster bounces are real deliverability signals); the checker records the role-class flag, the consumer decides policy.
- Accuracy reporting: the run report's honesty layer — per-level pass counts, catch-all-domain count, greylist-retry recovery count, disposable matches, policy-blocked domains needing egress rotation; the numbers that let a consumer know exactly what "verified" means on this run (RCPT-level truth on non-catch-all domains, not delivery-level truth), which is the difference between a checker that earns trust and one that inflates valid-counts on catch-all-heavy lists.
WORKED EXAMPLE - A 20,000-ADDRESS LIST
Input: 20,000 addresses, mixed sources. Syntax layer kills 412 malformed and 187 typo-domains (probable-intended recorded per line) — 19,401 proceed. Domain/MX layers: 298 NXDOMAIN dead, 44 MX-null refuse, 312 implicit-A flagged — 18,747 reach MX-published domains. Provider map paces the SMTP layer: 23 major-provider domains routed through provider-aware pacing (slower RCPT-per-connection), 890 other domains through standard pools. Random-probe flags 214 domains catch-all (their 1,847 RCPT-passes reclassify catchall-qualified). SMTP first pass: 11,203 verified (RCPT-250 on non-catch-all), 3,411 dead (550-class extended-codes preserved), 892 defer-4xx (retry queue), 301 policy-554 (checker-sender blocked at those domains — egress/sender rotation queue), 2,844 catchall-qualified, 156 disposable-matches on the list-layer. Retry pass after greylist-window backoff: 641 of the 892 defers convert to verified (greylist acceptance on re-contact — confirming the retry-class design), 251 stay deferred (re-run class). Final tallies: 11,844 verified, 3,411 dead, 2,844 catch-all-qualified, 251 defer-parked, 301 policy-parked, 156 disposable — run report showing the honest accuracy story: 11,844 verifieds are RCPT-level truths on non-catch-all domains; the 2,844 catchall-class are server-accepted-but-unverifiable; and the 214 catch-all domains' presence (heavy in the list's corporate-source segment) means a naive checker would have reported 14,688 "valid" — inflating by 24% over honest classification.
WORKING SEQUENCE
Code:
email checker: syntax (RFC shape + typo-domain detect) -> domain resolve (NXDOMAIN dead) -> MX lookup (null-MX refuse, implicit-A flag) -> SMTP RCPT probe (EHLO/MAIL FROM/RCPT, no delivery; 250=claim, 550=dead+ext-code, 4xx=defer retry, 554=policy-block) -> catch-all random-probe per domain (250 on UUID local = flag whole domain, reclassify pass as catchall-qualified) -> mass: async DNS parallel, per-domain serialized SMTP with connection reuse + RCPT caps, multi-egress -> greylist-aware retry windows -> classes: verified/catchall/dead/typo/disposable/policy/defer/unknown, first-pass vs final tallies reported separately
QUICK ANSWERS
- What does an email checker actually verify? Five levels, each more expensive: syntax (RFC-shaped), domain resolution, MX publication, SMTP RCPT-probe (server claims mailbox — no mail sent), and full delivery (rare, expensive); mass tools run through RCPT-probe level, and "verified" honestly means the server accepted the address at RCPT, qualified by whether the domain is catch-all — delivery-level truth requires the fifth tier most pipelines skip.
- What is a catch-all domain and why does it break checkers? A domain accepting RCPT for every address (accept-all configuration) — the probe gets 250 on dead addresses, inflating valid-counts; the fix: random improbable-address probe per domain — if the server accepts a UUID local-part too, flag the domain catch-all and reclassify all its RCPT-passes as catchall-qualified (server-accepted but unverifiable), which keeps the output honest instead of 20%+ inflated on corporate-heavy lists.
- Why do some valid addresses come back as deferred? Greylisting — many servers 4xx-reject first contact from unknown senders and accept on retry from the same IP+sender within a window (minutes to hours); the checker's retry queue with domain-aware backoff re-probes after the window, which recovers the majority of 4xx-class on greylist-heavy domains — which is why run reports separate first-pass and post-retry tallies (first-pass undercounts on those domains by design of the server, not the checker).
- What is the difference between dead and policy-blocked? Dead (550 user-unknown) is the address — the server says this mailbox does not exist; policy-blocked (554-class rejections) is usually the checker's sending identity or egress — the server refuses the dialogue on sender-reputation or IP-reputation grounds regardless of the address's validity; conflating the two dumps real addresses into dead-file and hides an egress problem behind address verdicts, which is why policy-class parks for sender/egress rotation, not address rejection.
- How does mass checking avoid getting SMTP-blacklisted? Per-domain serialization (concurrent across domains, paced within each), connection reuse with RCPT caps (cooperative-server multiplexing, not one-connection-per-address hammering), multi-egress distribution (one domain's throttle does not serialize the batch behind one IP), greylist-aware retry timing rather than hammering 4xx servers, and provider-map pacing (major mail providers get slower RCPT-per-connection than tolerant hosts) — the throttle discipline is what separates a sustainable checker from one that burns its egress reputation in the first hour.
- Should disposable addresses classify as dead? No — they receive mail by design (briefly); classify disposable-class with the domain recorded, and let the downstream consumer apply policy (marketing hygiene filters them, transactional flows sometimes accept them); the disposable domain-list is a living artifact (services rotate domains constantly), so unknown-new disposables slip through until the list updates, with domain-age and MX-pattern heuristics catching some newcomers in the meantime.
RELATED