Deliverability · Bounce handling

Bounce Classification: Hard, Soft, and Block Bounces

Email bounces fall into three categories that demand different handling. Hard bounces (5xx codes like 550 5.1.1) mean a dead or non-existent address and should be suppressed immediately. Soft bounces (4xx codes) are temporary — full mailbox, greylisting, throttling — and should be retried before being converted to hard. Block bounces are the trap: a 5xx that is actually a policy, authentication, or reputation rejection (often 5.7.x) of a valid address, which must be investigated and fixed rather than suppressed. Classify from the SMTP and enhanced status codes, never the human-readable message, because the wording varies by provider while the codes are standardised.

Key takeaways

  • Three types, not two. Hard, soft, and block bounces each need a different response — and the block category is the one most guides miss.
  • Read the code, not the words. Classify from the SMTP and enhanced status codes; the human-readable text varies wildly between providers.
  • Hard bounces: suppress now. A dead address never recovers, and mailing it again damages your reputation.
  • Block bounces: investigate, don’t suppress. Panic-suppressing a block-bounce wave deletes valid recipients over a fixable DNS or reputation issue.
  • Track hard and soft separately. A combined bounce rate hides the signal; hard bounces cost more reputation than soft.

Every bulk sender generates bounces — addresses go stale, mailboxes fill, domains expire, typos slip through forms. Bounces are normal; what separates a healthy sender from one slowly being throttled into the spam folder is what happens after the bounce. Mailbox providers watch how you handle them closely, and the difference between suppressing a dead address and panic-deleting a thousand valid ones comes down to classification. This guide covers how to read a bounce, the three categories that matter, and how to act on each correctly.

What is an email bounce, and why does classification matter?

A bounce is what happens when a message cannot be delivered: instead of reaching the inbox, the receiving server returns a Delivery Status Notification (DSN), also called a non-delivery report, explaining why. That DSN is the bounce message you see in your dashboard or logs, and it carries two machine-readable codes — a three-digit SMTP status code and a more granular enhanced status code — alongside a human-readable explanation.

Classification matters because the right action diverges sharply by type, and getting it wrong is expensive in both directions. Fail to suppress a dead address and you keep mailing it, signalling poor list hygiene to providers and degrading your reputation. Wrongly suppress a valid address that hit a temporary or policy block and you permanently lose a real recipient over a problem that a ten-minute fix would have solved. Accurate classification is the hinge between protecting your reputation and quietly destroying your list.

Hard, soft, and block: the three types of bounce

Most guides describe two types and stop. In real deliverability work there are three, and the third demands completely different handling. A hard bounce is a permanent failure — the address does not exist, the domain has no mail server, or the mailbox has been disabled — and the only correct response is to suppress it forever. A soft bounce is a temporary failure — a full mailbox, an overloaded server, greylisting, or rate limiting — that usually resolves on retry.

The third category is the block bounce, and it is where senders do the most damage to themselves. A block bounce looks like a hard bounce because it carries a 5xx code, but the address is perfectly valid — your message was rejected for policy, authentication, or reputation reasons, not because the mailbox is dead. Suppressing a block bounce removes a real recipient over a problem that lives on your side. The whole art of bounce classification is telling these three apart correctly, every time.

How do you read an SMTP bounce code?

Start with the first digit of the three-digit code, because it carries the most signal: a 5 means permanent failure, a 4 means temporary, and a 2 means success. That single digit is your first hard-versus-soft split. But the three-digit code alone is coarse, which is why modern mail attaches an enhanced status code in the form X.Y.Z, standardised in RFC 3463 and extended through the IANA registry.

The enhanced code is where precision lives. The first number (X) repeats the class — 2, 4, or 5. The second (Y) names the subject: 1 for addressing, 2 for mailbox, 3 for mail system, 4 for network, 5 for protocol, 6 for content, and 7 for security or policy. The third (Z) gives the exact detail. So 5.1.1 reads as permanent, addressing, mailbox-does-not-exist — a clean hard bounce — while 5.7.1 reads as permanent, security/policy — the signature of a block bounce, not a dead address. Read the enhanced code first, fall back to the three-digit code, then apply known exceptions.

A handful of codes sit in a useful middle ground that rewards reading the detail rather than the class. A 552 5.3.4 “message size limit exceeded” is technically permanent, but the address is fine and the fix is on your side — lighten the message and it delivers. A 5.2.2 “mailbox full” inside a delivery report can reflect a temporary quota rather than a dead account, so it is worth treating as soft in the short term and only sunsetting if it persists across several campaigns. These are exactly the cases where blindly mapping “5xx equals suppress” throws away recoverable mail, and where reading the full enhanced code earns its keep.

read-the-dsn
# A DSN carries structured fields — classify from these, not the prose
Reporting-MTA: dns; mail.example.net
Final-Recipient: rfc822; user@recipient.com
Action: failed
Status: 5.1.1
Diagnostic-Code: smtp; 550 5.1.1 <user@recipient.com>: user unknown
 
# Status 5.1.1 -> permanent / addressing / no mailbox -> HARD -> suppress
# Status 5.7.1 -> permanent / security-policy -> BLOCK -> investigate
# VERP return-path tells you WHO bounced without parsing the body:
Return-Path: bounce+user=recipient.com@example.net

Hard bounces: suppress immediately

Hard bounces are unambiguous once you read the code, and the action is never in doubt: remove the address permanently. The most common is 550 5.1.1, user unknown — the mailbox simply does not exist, usually from a signup typo like gmial.com, an abandoned account, or a stale harvested address. Related hard bounces include 553 5.1.2 for an invalid domain with no mail server, and 551 5.1.6 when a mailbox has moved with no forwarding. None of these will ever accept mail, so retrying is pointless and harmful.

The discipline that matters here is acting fast and never retrying. Continuing to send to addresses that have already hard-bounced is one of the clearest signals to a mailbox provider that you do not maintain your list, and it drags your reputation down across all your mail. The single largest source of hard bounces is invalid addresses entering your list in the first place, which is why the real fix is upstream — verification at intake — rather than cleanup after the damage.

Soft bounces: retry, then convert

Soft bounces carry 4xx codes and mean “not now, try again later.” A mailbox over its storage quota returns something like 452 4.2.2; an overloaded or throttling server returns 421 with a 4.7.x detail; greylisting shows up as 450 4.7.x; and a transient service issue can return 451 4.7.1. A particularly common trap is mistaking that last one for a permanent block — Apple’s servers, for instance, return it during inbound load spikes when the right response is simply to wait.

Your mail server should queue soft-bounced messages and retry automatically over a window of one to three days — typically three retries over 72 hours for cold outbound, stretching to five for engaged marketing lists. The crucial rule is conversion: a temporary failure that persists is functionally permanent. If the same address soft-bounces across three or more consecutive campaigns, or exhausts your retry schedule, convert it to a hard bounce and suppress it. A mailbox that has been “full” for two months is abandoned, and a server “unavailable” for a week is either gone or deliberately refusing you.

Classify by code, then actBounce code?read enhanced first4xx = SOFTretry 72h, then convert5.1.x = HARDsuppress immediately5.7.x = BLOCKinvestigate, don’t suppressdead address: gone for good-> permanent suppressionvalid address, your-side problem:auth / reputation / blocklist
The same 5xx code can mean two opposite things. The enhanced status code — 5.1.x versus 5.7.x — is what separates a dead address from a fixable block.

Block bounces: the trap that gets valid addresses suppressed

This is the category that costs senders real recipients. A block bounce arrives with a permanent-looking 5xx code — commonly 554 or 553 with a 5.7.1 detail — but the address is valid; the receiving server rejected your message for policy, authentication, or reputation reasons. A broken SPF record, a missing DKIM signature, a failed DMARC check, or a blocklist listing can generate these across your entire list at once, in a wave that looks alarmingly like a mass hard-bounce event.

The wrong instinct — and a genuinely damaging one — is to suppress everything in that wave. We have seen teams delete thousands of valid addresses after a block-bounce surge when the actual cause was a misconfigured DNS record that took ten minutes to fix. The correct response is to investigate your side: check SPF, DKIM, and DMARC alignment with our authentication guide, and check whether you have landed on a major list using the blacklist removal guide. One provider-specific subtlety to know: a DMARC failure surfaces as 5.7.26 at Gmail, 5.7.509 at Microsoft, and 5.7.1 at Yahoo — the same root cause wearing three different codes, which is why you always check the provider’s own table.

Why you must classify from the code, not the message

The most common mistake in homegrown bounce processing is classifying from the human-readable text instead of the status codes. The prose wording varies wildly between providers — one server’s “mailbox unavailable” is another’s “recipient rejected” — while the codes are standardised across all of them. Build your classification on the SMTP and enhanced status codes, and use the diagnostic text only as a secondary hint for genuine edge cases, never as the primary signal.

A second distinction worth internalising is synchronous versus asynchronous bounces. A synchronous bounce is rejected during the live SMTP conversation, so you get the code immediately. An asynchronous bounce is accepted first and returned later as a DSN, with the failure details buried inside a non-delivery email that you have to parse. The lesson from both is the same: capture the code-and-text pair on every attempt, not just the last one, so a late async bounce or a shifting code pattern is something you can see rather than something that silently corrupts your list.

How do you capture and parse bounces at scale?

At volume, you need a pipeline rather than a person reading DSNs. Bounce data arrives through one of three channels depending on your infrastructure: raw SMTP DSN messages you parse yourself, structured webhook callbacks where your ESP has already extracted the fields into JSON, or a notification service like Amazon SNS. Whichever you use, the parser’s job is to pull out four things: the recipient address, the three-digit code, the enhanced code, and the diagnostic text.

Identifying which recipient bounced is cleanest with VERP — a Variable Envelope Return Path that encodes each recipient’s address into a unique return-path, so the bounce tells you who failed without parsing the message body. From there, map the raw codes into a small set of normalised internal reasons — user_unknown, mailbox_full, message_too_large, throttled, policy_block, auth_failed, and a dozen or so others — and apply codified rules to each. That normalisation is what lets you act consistently instead of juggling fifty different provider phrasings for the same underlying failure.

The payoff of a real pipeline is that it turns bounces into early warnings rather than after-the-fact cleanup. Break your bounce metrics out by recipient domain and by acquisition source, because both views catch different problems: a spike of user_unknown from one signup form points at a collection issue, while a sudden cluster of policy_block at a single provider points at an authentication or reputation problem with that provider specifically. Per-domain alerting also lets you respond precisely — if 4.7.x throttling climbs at one mailbox provider, you slow your sending to that provider rather than throttling everything. Feed those signals back to the right team, and a bounce report stops being noise and becomes an operational dashboard.

What bounce rate is acceptable?

Track hard and soft bounce rates separately, because a combined number hides the signal you actually need — they have different causes, fixes, and reputation costs. As operational thresholds, a total bounce rate under 2% is healthy and under 1% is ideal; 2–5% needs attention, above 5% is serious, and above 10% means stop sending immediately. Hard bounces specifically should stay under 0.5%, since that is the rate providers scrutinise most.

The reputation math is asymmetric, and it changes your priorities. Hard bounces hurt more than soft ones, because providers expect occasional temporary failures but read a high hard-bounce rate as a sender mailing addresses they should not have — a 3% hard-bounce campaign damages you more than a 5% soft-bounce one. The Gmail and Yahoo bulk-sender rules make the stakes concrete for anyone sending over 5,000 messages a day: complaint rate under 0.3%, bounce rate trending below 1%, and enforced authentication. Most ESPs flag accounts above 2% and suspend above 5%, so these are not abstract targets.

The point at which a soft bounce becomes a hard one is a policy decision, and the major platforms encode it differently — worth knowing if you rely on an ESP’s automatic cleanup. Mailchimp, for example, converts a repeatedly soft-bouncing address after roughly seven attempts for unengaged subscribers and fifteen for engaged ones; Klaviyo applies engagement weighting that keeps addresses with recent opens in play longer than silent ones. The shared logic is that a temporary problem eventually becomes permanent, and that an address still opening your mail deserves more patience than one that has gone quiet. If you run your own conversion rules, mirror that engagement-aware approach rather than applying one flat retry count to every address.

Preventing bounces before they happen

Classification handles the bounces you get; prevention reduces how many you get, and it is overwhelmingly an upstream problem. Pre-send verification is the single most effective tool, eliminating 90–95% of hard bounces by catching invalid, broken, and disposable addresses before they ever cost you a reputation hit — it produces the same routing decision the SMTP server would, without the damage of finding out via a live bounce. Because email data decays at roughly 2% per month, verification is not a one-time event but a recurring pass on any list not validated in the last 30 days.

Two more habits close the gap. Authenticate everything — SPF, DKIM, and DMARC — because that is what prevents the policy and block bounces that verification cannot touch. And be honest about list sources: catch-all domains are far more likely to bounce because they accept everything during verification then reject later, and a purchased or scraped list will defeat any suppression logic you build on top of it. If you find yourself migrating senders or rotating addresses, expect a burst of transient bounces and pace accordingly — our IP migration strategy covers that, just as complaint handling and reputation recovery cover the neighbouring signals. Owning your sending infrastructure is what gives you direct control over bounce processing, VERP, and the stream separation that keeps one bad list from poisoning everything.

Frequently asked questions

What’s the difference between a hard and soft bounce?
A hard bounce is a permanent failure with a 5xx code — the address doesn’t exist or the domain has no mail server — and should be suppressed immediately. A soft bounce is a temporary failure with a 4xx code, like a full mailbox or server load, which should be retried and only converted to a hard bounce if it keeps failing.
What is a block bounce?
A block bounce is a 5xx rejection of a valid address for policy, authentication, or reputation reasons rather than because the mailbox is dead — often 554 or 553 with a 5.7.1 detail. It should not be suppressed; instead investigate your SPF, DKIM, and DMARC and whether you’re on a blocklist, since suppressing it deletes real recipients.
Should I classify bounces from the error message or the code?
From the code, always. The three-digit SMTP code and the enhanced status code (like 5.1.1 or 4.2.2) are standardised across providers, while the human-readable message wording varies wildly. Read the enhanced code first, fall back to the three-digit code, and use the diagnostic text only as a secondary hint for edge cases.
What does 550 5.1.1 mean?
It’s the most common hard bounce: the recipient mailbox does not exist on the destination server. The enhanced code 5.1.1 reads as permanent (5), addressing (1), mailbox-does-not-exist (1). Suppress the address immediately and never retry — it usually comes from a typo at signup, an abandoned account, or a stale harvested address.
What’s an acceptable bounce rate?
Keep your total bounce rate under 2%, ideally under 1%, and hard bounces specifically under 0.5%. Above 5% needs serious attention and above 10% means stop sending. Track hard and soft rates separately, since hard bounces cost more reputation, and note that Gmail and Yahoo expect bulk senders to trend below 1%.