The 250 OK Myth: It Does Not Mean Deliverable

You run a list through an email verifier, and 94 percent of the addresses come back with a green check. A week later, hard bounces eat 12 percent of the send and the complaint rate triples. The verifier did not lie. It reported what the receiving mail server told it during the SMTP conversation: a 250 OK at the RCPT TO stage. That code means the server accepted the command. It does not mean a human reads mail at that address, that the mailbox exists, or that the message will survive filtering.

The gap between “the server said 250” and “mail lands in an inbox” is where most deliverability damage happens. A catch-all domain answers 250 to every local part you invent, so any result from that domain is noise dressed up as data. An accept-then-bounce server waits until after it has the message text, then fires a bounce that counts against your sender reputation. The 250 OK is a statement about the SMTP transaction, not a promise about the recipient.

This article breaks down what each 250 actually confirms, why catch-all email verification inflates clean-looking results, and how a single control test with a fake address exposes the difference between a real mailbox and a rubber stamp. The fix is not a better verifier alone. It is reading status codes the way the receiving server meant them.

What the 250 OK SMTP Code Actually Confirms

A 250 response during an SMTP conversation is one of the most misread signals in email verification. People see “250 OK” in a verifier report and conclude the mailbox exists and will accept mail. Neither conclusion follows from the code. The 250 is a protocol acknowledgment from the receiving mail server, and its scope is narrower than most senders assume.

What happens between EHLO and RCPT TO

An email verifier connects to the domain’s mail server, opens the session with EHLO, issues MAIL FROM with a well-formed address, then issues RCPT TO with the address under test. The server’s reply to RCPT TO is the moment of interest. A 250 there means the server has accepted the recipient command and is willing to continue the transaction. It does not mean a mailbox exists behind that local part. It does not mean the mailbox is active, under quota, or free of a block rule. It means the command passed this stage of the handshake.

RFC 5321 defines the code space precisely. A 550 response is the specified answer for an undeliverable recipient, and a 550 at RCPT TO is strong evidence the address will fail. The inverse is not true: a 250 is not evidence of deliverability. It is the absence of an explicit rejection at one specific step, and servers have wide latitude in how they answer.

Three configurations produce a 250 for addresses that cannot receive mail:

  • Accept-then-bounce servers answer 250 at RCPT TO, take the full message text, then send a bounce after receiving it. The rejection arrives as a bounce message hours later, and by then the sending reputation damage is done.
  • Greylisting and anti-spam layers answer 250 to keep probes from learning which addresses are real. The answer is a policy response, not a mailbox fact.
  • Catch-all servers answer 250 OK to RCPT TO for every local part on the domain, as covered in the next section.

There is also the question of what the server bothers to check. Many large providers run recipient validation against internal directories before replying, so their 250 carries real information. Smaller mail servers frequently skip that lookup entirely because it costs resources and leaks information about which accounts exist. RFC 5321 even allows administrators to disable the VRFY command for the same reason, so verifiers that lean on VRFY learn little. The RCPT TO probe is the more reliable channel, and it is still only as good as the server’s willingness to answer honestly.

The practical takeaway: treat 250 as “the server did not refuse the command.” Everything beyond that has to be established by other means, starting with a check on whether the domain answers 250 for addresses that cannot possibly exist.

Catch-All and Accept-All Domains: Why Every Address Gets a 250

A 250 OK on RCPT TO is supposed to mean the mailbox exists. On a catch-all domain it means nothing of the sort. The receiving server is configured to accept mail for every address on the domain, so the SMTP conversation follows the same script no matter what you put in the envelope. You type sales@, zzz9q@, or a string of random characters, and the answer is the same 250. The catch-all result means one thing only: the receiving server accepts mail for every address on the domain. It says nothing about the local part you asked about.

How a catch-all server answers the RCPT TO command

The mechanics are simple. An email verifier connects to the domain’s mail server, opens the SMTP conversation with EHLO, sets MAIL FROM to a well-formed address it controls, and issues RCPT TO for the address under test. On a normal server, the response splits real mailboxes from fakes: 250 for a match, 550 for a miss, as RFC 5321 specifies for undeliverable recipients. A catch-all server answers 250 OK to RCPT TO for every local part, because it has been told to hand all unmatched mail to one inbox or to a filtering layer behind it.

That is why catch-all email verification is a different problem from ordinary verification. The protocol gives you a truthful answer, but the question it answers is “will this server take mail for this domain,” not “does this person exist.” Verifiers detect catch-all using a control test with an invented address: a random local part that cannot plausibly exist. If the invented address also returns 250, the domain is accept-all and the original result carries no information about the mailbox.

The accept-all email status is the label most tools attach at this point, and it is often stored internally as accept_all or unknown status. The distinction matters in reporting. A single 250 on a catch-all domain looks identical to a confirmed result in a spreadsheet column, and that is exactly how inflated deliverability numbers happen. Teams filter out rows marked invalid, keep everything else, and export a list where a third of the “valid” addresses were never actually confirmed.

There are more ways a 250 can mislead. Some servers accept at RCPT TO and bounce later, so an accept-then-bounce server sends a bounce after receiving message text, long after the verifier recorded a pass. Some disable recipient validation entirely to blunt address harvesting, which RFC 5321 allows through disabling VRFY and is commonly paired with accept-all behavior at RCPT TO. Others sit behind a temporary email provider or a greylisting appliance that answers 250 first and decides later.

Treat a catch-all result as not a reason to delete an address, and not a reason to trust it either. It is a flag, not a verdict.

Practical rule: any domain that returns 250 for an invented local part should be labeled catch-all in your data, kept out of hard-bounce and deliverability statistics, and handled with its own sending policy. what catch-all means in email verification has more details on this topic. Blending those rows into a clean list is how a verifier’s output stops matching what your mail server actually sees.

The Control Test That Exposes a Fake 250

A single 250 at RCPT TO tells you almost nothing on its own. To find out whether that 250 means anything, you have to ask the same server a question you already know the answer to. That is the control test: invent a local part that cannot possibly exist, run the same SMTP conversation against the same domain, and watch what comes back.

Here is the procedure. Open a session with the domain’s mail server, send EHLO, set MAIL FROM to a well-formed address you control, then issue RCPT TO with a random string in the local part, something like qt7x2v9m4k1@example.com with a timestamp or random suffix so it cannot be a real mailbox. If the server answers 250 to that invented recipient, the domain is accept-all. It answers 250 OK to RCPT TO for every local part, so the 250 you got for the real address carries no information about whether that mailbox exists.

Run the control test per domain, not once globally. Accept-all behavior is a domain-level setting, and a provider may switch it on for one customer and off for another. Use a fresh random string each time, because some servers cache recent RCPT TO results and a repeated fake address can produce misleading answers. Keep the control address syntactically valid: a malformed recipient can trigger a 501 syntax error and tell you nothing about the domain’s policy.

The outcomes map cleanly onto verification results:

  • Fake address gets 250, real address gets 250. Accept-all domain. The real address is unknown status, not deliverable. The original 250 is meaningless for that address.
  • Fake address gets 550, real address gets 250. The server does discriminate. The 250 is a genuine acceptance of that recipient, which still does not guarantee the mailbox is read.
  • Fake address gets 550, real address gets 550. The address is rejected. Trust the rejection, though check the response text for greylisting or policy blocks before labeling it known-bad.
  • Fake address times out or returns 4xx. Inconclusive. Retry later from a different IP; do not read the result either way.

Two complications are worth knowing. Some servers accept at RCPT TO and then bounce after receiving the message text, so an accept-then-bounce server passes the control test and still fails the address. And RFC 5321 allows administrators to disable VRFY, which is why the control test relies on RCPT TO rather than VRFY. The control test is not a complete verification; it isolates one specific lie, the blanket 250.

Any email verifier worth its price runs this check internally and labels the result accept_all. If your verification results show a 250 as deliverable without a matching control test on the same domain, you are reading a status code, not a fact. AllMail publishes blog content about email verification that covers this distinction in detail. A 250 is a claim by the receiving server. The control test is how you check whether the claim means anything.

Reading Verification Results Correctly: From Status Codes to Real Deliverability

A raw SMTP log is not a deliverability verdict. The useful output of any email verifier is a labeled status you can act on, and the labels only hold up when the control test was run. Treat each result as one of four buckets: deliverable, undeliverable, accept-all (catch-all email verification returned 250 for both the real local part and the invented one), or unknown. The unknown bucket is the one that gets abused. A verifier that could not complete the SMTP conversation, hit a greylist, or timed out should return unknown status, not deliverable. If your provider collapses unknown into “valid,” you are sending to addresses that were never validated at all.

For catch-all domains, the honest label is accept-all, not valid. A catch-all result means the receiving server accepts mail for every address on the domain, so the 250 you saw is identical to the 250 it would return for a random string. That address is neither confirmed nor refuted. It is a coin flip with your sender reputation on the line, because a catch-all server that later rejects the mailbox often does so as an accept-then-bounce server: it takes the message text, then sends a bounce after receiving it. Hard bounces from that pattern damage reputation just like any other.

Weighting verifier output comes down to what evidence sits behind each label. Use this rough hierarchy when you triage a list:

Result label What backs it Send decision Risk if wrong
Deliverable (control test passed) 250 on RCPT TO, non-250 on invented local part Send normally Low; mailbox may still be full later
Accept-all / catch-all domain 250 on every local part tested Send only to engaged contacts, throttle volume Medium; accept-then-bounce pattern
Undeliverable 550 or 5xx on RCPT TO per RFC 5321 Suppress immediately Low; code is explicit
Unknown / timeout / greylisted No usable SMTP response Retry verification later, hold send High if treated as valid
Known-bad list or temporary email provider hit Blocklist or disposable domain match Suppress or quarantine Low; domain-level signal is reliable

Before sending, run these checks on any ambiguous address:

  • Confirm the address is well-formed and the domain resolves to a live mail server with an MX record.
  • Check whether the domain appears on known-bad lists or matches a temporary email provider pattern.
  • Re-run the control test if the verifier result is older than 30 days; catch-all configurations change.
  • For catch-all results, require prior engagement (an open, a click, or a reply) before adding the address to a regular send.
  • Keep the raw SMTP conversation, including MAIL FROM and RCPT TO lines, so a disputed result can be audited.

A catch-all result is not a reason to delete an address, and it is not a license to mail it. Segment those addresses, send them low-volume, engagement-gated campaigns, and let behavior decide what the SMTP codes could not.

The next time a verifier hands you a 250 OK, do one thing before you act on it: run the control test yourself against that domain. Open a manual SMTP check or a raw socket session, send MAIL FROM with a well-formed address you control, then issue RCPT TO with a random local part such as zz9x7q2k8v that cannot plausibly exist. If the catch-all server answers 250 OK for that invented address, you are looking at an accept-all domain and the original 250 tells you nothing about the mailbox. Label the address accept_all or unknown status, keep it out of your primary campaign, and if you mail it at all, route it through a low-volume segment with engagement tracking so a bounce or complaint never touches your main sending reputation.

Build this into a routine rather than a one-off. Sample 20 to 50 addresses from every new list, run the control test on each distinct domain, and log which domains behave as catch-all. Feed the results into your suppression logic: hard 550 responses go to known-bad lists immediately, catch-all results get quarantined for a separate workflow, and only verifier output backed by a clean control test earns a place in your main send. The email verifier is a starting point, not a verdict. A 250 OK is a server saying it will take the command, and the only way to know whether a deliverable address sits behind it is to ask a question the server cannot answer with a blanket yes.