Hard Bounce vs Soft Bounce: Suppress or Retry

A hard bounce is a permanent failure. The server answered with a 5xx reply code, it will answer the same way tomorrow, and the address should be suppressed. A soft bounce is a temporary failure. The server answered with a 4xx code, the message stays queued, and delivery may succeed later. The first digit of the reply code is the rule. The label your provider prints on top of it is a convention.

Neither term is in the specification. A full-text search of RFC 5321, RFC 3463 and RFC 3464 returns no occurrence of "hard bounce" or "soft bounce" in any of the three. The RFCs define reply classes. Hard and soft are vocabulary the email service providers built on top of those classes, and the providers do not fully agree with each other about where the line sits.

What do the RFCs actually define?

Two axes, and the ESP labels flatten both into one.

The first is severity. RFC 5321 splits negative replies by leading digit. A 4yz reply is a "Transient Negative Completion reply", where "the error condition is temporary, and the action may be requested again". A 5yz reply is a "Permanent Negative Completion reply", where the client "SHOULD NOT repeat the exact request (in the same sequence)". RFC 3463 carries the split into enhanced status codes: class 4 is a "Persistent Transient Failure", class 5 a "Permanent Failure" that "is not likely to be resolved by resending the message in the current form". RFC 5321 adds a caveat that gets ignored: "Even some 'permanent' error conditions can be corrected", for instance after the user has altered the account status.

The second axis is what your own MTA did about it. RFC 3464 gives the bounce message an Action field whose values are failed, delayed, delivered, relayed and expanded. Nothing hard, nothing soft. It also states that the axes are independent: "a 'temporary failure' ('4') status code could be used with an action-value of either 'delayed' or 'failed'". Its worked example is an MTA that retries a nameserver timeout, issues a delayed DSN, then abandons the message days later with a failed DSN carrying the same 4 code.

That combination, failed action plus class 4 status, is what most providers hand you as a bounce. The spec keeps "the server said never" and "we gave up" apart. The hard/soft binary does not.

Which codes map to which label?

The permanent side, the one that should trigger suppression:

The transient side, the one that stays in the queue:

The full SMTP reply code list covers the rest.

How does each provider classify and act?

Concretely, and not the same way.

Amazon SES uses three top-level types: Undetermined, Permanent (hard) and Transient (soft), each with subtypes, including NoEmail and OnAccountSuppressionList on the permanent side and MailboxFull and MessageTooLarge on the transient side. SES "does not retry hard bounces, with the exception of DNS lookup failures", and retries soft bounces "multiple times" before stopping. It notifies you of both, but only hard bounces count toward the bounce rate it measures you on. It also runs a global suppression list of addresses that recently hard bounced for any SES customer, where an address "can remain on the suppression list for up to 14 days", and bounces caused by that list count against your quota and your bounce rate.

SendGrid has no hard/soft binary. It buckets every rejection into seven classifications: Invalid Address, Technical, Content, Reputation, Frequency/Volume, Mailbox Unavailable and Unclassified. Only Invalid Address maps to the colloquial term, and SendGrid says so: "Invalid Address rejections are often referred to as hard bounces". The others are blocks rather than bounces. SendGrid is also candid that its Technical class cannot be attributed to either party, because "it is difficult or impossible to determine which side the problem is on from the rejection message alone".

Postmark publishes a longer list: Hard Bounce, Soft Bounce, Autoresponder, Transient/Undeliverable, Message Delayed, DNS Error, Challenge Verification, Unsubscribe and Address Change. Only Hard Bounce and Spam Complaint deactivate an address automatically, and only the hard bounce is reversible. Deleting a HardBounce entry through the Suppressions API reactivates the address, while a SpamComplaint suppression cannot be deleted at all. Soft bounced addresses need no reactivation before you send again.

Mailgun keeps the binary but documents that it leaks. Its temporary failure webhook fires for events like a full mailbox and does not add the address to the Bounces suppression table. Its permanent failure webhook fires when the recipient "was not found, or was determined to not exist", and also when soft bounced mail exhausts all delivery attempts, when an ESP blocks the message over sender domain or IP reputation, and when the address already sits on one of Mailgun's three suppression tables. Four situations, one event.

Mailchimp removes the address itself. Hard bounces "are cleaned from your audience automatically and immediately", and a cleaned contact cannot receive anything you send later. It is also the only one of these five that converts repeated soft bounces into hard ones on a published schedule.

How many soft bounces before an address is treated as dead?

Mailchimp is the only one that publishes a number: "We'll allow 7 soft bounces for an email address with no subscriber activity and up to 15 soft bounces for contacts with previous subscriber activity before converting a soft bounce into a hard bounce."

Amazon SES, Postmark and Mailgun do not publish one. SES says it retries "multiple times". Postmark says it makes "several attempts". Mailgun says it tries "later on a few more times". None of the three states a count or a schedule in its documentation, so there is nothing to average. SendGrid has no escalation count to publish, because it never converts a soft bounce into a hard one.

If your suppression logic assumes a common industry threshold, it is assuming something only one vendor has written down.

How long should a message keep retrying?

The only numbers from a standards body are in RFC 5321. The retry interval "SHOULD be at least 30 minutes". The give-up time "generally needs to be at least 4-5 days". And experience favours "two connection attempts in the first hour the message is in the queue, and then backing off to one every two or three hours". These are recommendations, not requirements. The same RFC says the retry parameters must be configurable, so no two MTAs are obliged to behave alike.

Provider practice is thinner than the spec. Since October 2024, SES lets a customer set a maximum delivery time for messages hitting temporary issues such as soft bounces, "with options ranging from 5 minutes to 14 hours". That is a configurable ceiling, not a disclosure of the default cadence when nobody sets it, and the default is not published. Postmark's advice to a human is to "wait a day or two before attempting to send to this recipient again", and to try another channel if the problem outlasts 48 hours.

What does a bounce cost your sending reputation?

For SES, a documented amount. A bounce rate of 5% or greater automatically places the account under review. 10% or greater may pause its ability to send. Complaints carry their own numbers on the same page: 0.1% for review, 0.5% for a possible pause. Only hard bounces to unverified domains feed that bounce rate, and soft bounces and bounces from blocked IP addresses are excluded by SES's own description.

The recommended target, as opposed to the enforcement line, is inconsistent inside AWS's own documentation. One SES page says "maintain a bounce rate below 5%". Another says "you should maintain a bounce rate below 2%". Both agree on 5% and 10% for enforcement. Treat the enforcement numbers as the real ones and the target as unsettled. SendGrid separately recommends "generating hard bounces from fewer than 5% of your attempted messages", while stating in the same paragraph that "there is no exact number or percentage of hard bounces that causes deliverability issues".

Then the correction most articles on this topic get wrong. Google and Yahoo publish no bounce-rate threshold. Google's Email sender guidelines contain no numeric bounce figure anywhere. The one quantified requirement is a spam complaint rate: keep it below 0.3%, with a stated target under 0.10%, as measured in Postmaster Tools. Google's bounce guidance is qualitative, that senders should "automatically unsubscribe recipients who have multiple bounced messages". Yahoo's Sender Hub requirements, enforced since February 2024, have the same shape: a 0.3% spam rate ceiling calculated on mail delivered to the inbox, and no bounce number at all.

No trustworthy industry average exists to compare yourself against either. The benchmark percentages that circulate trace back to vendor blog posts with no disclosed sample size or methodology, often citing each other. Your own trend line, week over week, is worth more.

Does a hard bounce mean the mailbox never existed?

No, and three sources say so independently.

RFC 5321's gloss on 550 covers "mailbox not found, no access, or command rejected for policy reasons" in one code, so the reply alone cannot tell you which happened. RFC 3463's 5.7.1 is a permanent code that exists to report per-host or per-recipient filtering, meaning a working mailbox that refused you. And Mailgun documents that its permanent failure event fires on reputation-based ESP blocks and on exhausted soft bounces, not only on missing recipients.

So read the enhanced status code before suppressing in bulk. A 5.1.1 is an address problem and the address should go. A 5.7.1 is a sender problem wearing permanent-failure clothing, and suppressing those addresses fixes nothing while quietly deleting real customers from your list.

How do you get bad addresses out before the send?

Pre-send verification runs the same lookup that would produce the bounce. A verifier opens an SMTP connection and issues RCPT TO without sending DATA, then reads the reply code, using the same definitions RFC 5321 lays out for a real delivery attempt. Addresses that answer like 5.1.1 never enter the send, so they never become a hard bounce, never reach a suppression list, and never move the rate SES enforces on.

The method has one honest limit: the catch-all domain. A catch-all accepts RCPT TO for every local part, existing or not, so a single probe cannot separate a real mailbox from a typo. A second probe to a randomly generated address is a workaround at the verifier layer, not a feature of SMTP. The correct output for an address on a catch-all domain is unknown, not valid. Any verifier that returns valid for a catch-all domain is guessing, and you find out which ones it guessed wrong on from the next bounce report. Trueguard's email validation API reports those addresses as unknown rather than resolving them either way.

Frequently Asked Questions

No. RFC 5321 defines reply code 550 as covering "mailbox not found, no access, or command rejected for policy reasons", which is three different situations behind one number. RFC 3463's 5.7.1 is a permanent code created specifically to report per-host or per-recipient filtering, so the mailbox may be perfectly healthy and simply refusing your mail. Mailgun documents the same overlap from the provider side: its permanent failure event also fires on reputation-based blocks and on soft bounces that exhausted their retries. Read the enhanced status code before suppressing.

Trueguard Basic is free.

Start identifying visitors and signals right away, for free

Sign up for free

No credit card required.

trueguard-logo© 2026 Trueguardinfo@trueguard.io