Hard bounce vs soft bounce: the difference, and what to do with each one
Published Updated 7 min readBy the Rasket team

What a bounce is, hard and soft
A bounce is a receiving mail server refusing a message. The refusal comes back as a reply code on the SMTP conversation, or as a message to your return path, and a sending platform turns it into an event. The distinction everybody needs is between the refusals that will never change and the ones that might.
A hard bounce is permanent. The mailbox does not exist, the domain does not resolve, or that server has decided it will not take mail from you. Sending again changes nothing except how often you are seen mailing addresses that do not work.
A soft bounce is temporary. The mailbox is full, the server is overloaded, or you are being asked to slow down. The same message to the same address may well succeed in an hour.
Getting bounce handling right is mostly about not confusing the two: a hard bounce you retry is wasted reputation, and a soft bounce you suppress is a customer you stopped talking to because their mailbox was briefly full.
The two, side by side
| Hard bounce | Soft bounce | |
|---|---|---|
| Meaning | Permanent refusal | Temporary refusal |
| Reply class | 5xx | 4xx |
| Typical causes | Address does not exist, domain does not resolve, sender blocked | Mailbox full, server unavailable, rate limited, greylisting |
| Retry? | Never | Yes, for a bounded window |
| Suppress? | Immediately | Only after it repeats for days |
| Event type | Permanent | Transient |
| What it costs you | Reputation, directly and quickly | Little, unless the pattern continues |
| Best for deciding | Remove the address and find where it came from | Leave the address alone and try later |
There is a third type. Undetermined is a refusal the receiving server gave without saying clearly whether the problem is permanent, and it is reported as its own type rather than folded into one of the other two — because guessing in either direction is wrong. It is rare, and the right handling is to count it and watch.
Reading the reply code
RFC 5321 gives the first digit its meaning: a 5 is a permanent failure and a 4 is a transient one. RFC 3463 adds the enhanced status code — the three-part number after it — which narrows the reason in a way a human can act on.
550 5.1.1 The email account that you tried to reach does not exist.550 5.1.2 Domain not found550 5.7.1 Message rejected: sender not allowed452 4.2.2 Mailbox full451 4.3.0 Temporary server error, try again later421 4.7.0 Too many messages from this sender, slow downThe text after the code is free-form and varies by provider, which is why parsing it is a losing game and why the platform reports a type instead. Read the type in code; read the text when you are investigating one specific message.
A 5xx is not always about the address
550 5.7.1 usually means the receiving server refused you, not the recipient — authentication, reputation or a block list. Suppressing the address is the wrong response to that: nothing is wrong with the address, and the same refusal is waiting for every other recipient at that provider.
What a bounce costs you
Mailbox providers read your bounce rate as a statement about your list. A sender who frequently mails addresses that do not exist looks either careless or like somebody working from a purchased list, and neither gets the benefit of the doubt when a filtering decision is marginal.
There is no single published threshold that applies everywhere, so the trend is the signal. A rate that climbs week over week means the list is decaying faster than you are cleaning it. A sudden spike almost always traces to one import, one form without validation, or one integration that started sending to a field it should not have.
The email bounce rate to watch is bounces as a share of attempted sends, per sending domain, per week. The metrics endpoint reports it alongside delivery and complaint rates, broken down by domain or by broadcast, which is usually enough to find the stream responsible without going through individual messages.
Handling the bounce event
A bounce reaches you as an email.bounced webhook. The payload carries the message id, the recipient, and a bounce object whose type is the field your code branches on.
// Inside your verified webhook handler.if (event.type === "email.bounced") { const { email_id, bounce } = event.data;
switch (bounce.type) { case "Permanent": await suppress(recipientOf(email_id), "hard bounce"); break; case "Transient": await countSoftBounce(recipientOf(email_id)); break; default: // "Undetermined": the server refused without saying why. Count it, // watch it, and suppress only if it keeps happening. await countUndetermined(recipientOf(email_id)); }}Three things that handler should not do. It should not parse the message text to decide what happened — the type is the decision. It should not retry a permanent bounce, ever. And it should not assume it runs once: events can be delivered more than once, so the suppression and the counter both need to be safe to repeat. The webhooks article covers the verification and deduplication that go around this.
How long to keep retrying a soft bounce
A bounded window, then stop. A full mailbox or a briefly unavailable server usually clears within a day, so a handful of attempts over that period is reasonable. Beyond that you are mailing an address that has not accepted anything in a week, which is a hard bounce that has not said so out loud. Count consecutive soft bounces per address and suppress at a threshold you can defend.
Suppression lists, and why they are not optional
A suppression list is the memory a transport does not have: the set of addresses this team will not send to, and why. A send to an address on it is stopped before it leaves, and reported as email.suppressed rather than silently dropped.
It applies to every kind of mail, including the transactional message whose author is certain it is important enough to be an exception. That is deliberate. The list exists so that an address which already bounced or complained is not mailed again by any part of your product, and a carve-out for “important” mail is how the whole mechanism stops working. If an entry is genuinely wrong, remove it explicitly — the API has a route for exactly that — rather than routing around the check.
Complaints belong on the same list. A complaint is not a bounce: the message arrived, and the recipient pressed the report-spam button. But the correct response is identical and more urgent, because a complaint is a direct signal to the mailbox provider in a way a bounce is not. The suppressions reference documents the reasons a row can carry.
Reducing bounces before they happen
Handling bounces well keeps a bad list from getting worse. Not collecting bad addresses in the first place is the part that actually moves the rate.
- Validate at the point of entry. Syntax, then a DNS check that the domain has a mail server at all. It catches typos and abandoned domains before they cost you anything.
- Confirm the address. Sending one message and requiring the recipient to act on it proves the mailbox exists and that somebody reads it. It is the single most effective control there is, and it is also what separates a list you can defend from one you cannot.
- Never buy or import a list you did not build. A purchased list is a bounce rate and a complaint rate in one purchase, and the damage lands on the domain your receipts go out from.
- Re-engage or remove. An address that has not opened anything in a year is more likely to become a spam trap than a customer. Removing it improves nearly every rate you measure.
Keep the two kinds of mail on separate subdomains as well, so that a campaign with a bad list cannot drag down the password resets going out beside it — the transactional and marketing article covers why, and the deliverability guide is the wider picture this one sits inside.
Frequently asked questions
What bounce rate is too high?
Anything sustained above a couple of per cent means your list is stale, and mailbox providers will notice before you do. There is no single published threshold that applies everywhere, so treat the trend as the signal: a rate that climbs week over week is a list problem, and a sudden spike is usually one bad import.
Should I ever retry a hard bounce?
No. A hard bounce is the receiving server telling you the address does not exist or will never accept mail from you. Retrying it sends a message that cannot arrive, to a domain that is now watching how often you do that. Suppress the address and fix whatever put it on the list.
How long should I retry a soft bounce?
For a bounded window, then stop. A full mailbox or a temporarily unavailable server often clears within a day, so a few attempts over that period is reasonable. An address that soft-bounces every send for a week is functionally dead even though nobody has said so, and should be suppressed like a hard bounce.
What is an undetermined bounce?
One where the receiving server refused the message without saying clearly whether the problem is permanent. It is reported as its own type rather than folded into one of the other two, because guessing in either direction is wrong: treating it as permanent loses a real address, and treating it as transient keeps mailing a wall.
Does a suppression stop a transactional email too?
Yes, and that is deliberate. A suppression list exists so that an address which already bounced or complained is not mailed again by any part of your product, including the part that thinks its message is important. If you believe an entry is wrong, remove it explicitly rather than routing around it.
Is a spam complaint a bounce?
No. A bounce is a refusal at delivery time; a complaint is a recipient pressing the report-spam button after the message arrived. They reach you as different events and mean different things, but the handling is the same in one respect — both belong on the suppression list immediately.
Sources
- RFC 5321: Simple Mail Transfer Protocol — IETF, read 2026-09-16
- RFC 3463: Enhanced Mail System Status Codes — IETF, read 2026-09-16
- Email sender guidelines — Google, read 2026-09-16
Related
- Events — Every event a webhook can carry, with one real payload each.
- Suppressions — Addresses we will not send to, and why.
- Email glossary — Plain definitions of the words that turn up in email infrastructure: DKIM, SPF, DMARC, bounces, complaints, suppressions, idempotency, webhooks and more.
- Email deliverability guide for developers — Delivered is not the same as inboxed. Authentication, domain reputation, list hygiene, the headers bulk senders need, and the numbers worth watching every week.
- Email webhooks explained: events and signatures — What an email webhook is, the delivery events and what fires each, the payload shape, verifying the signature, and handling retries and out-of-order events.