Email Bounce Rate: How to Measure It and What to Fix
Summary
Email bounce rate is the share of sent messages a receiving server refused. Keep hard bounces under 1% on a healthy list, investigate at 2%, and treat 5% as an incident, since Amazon SES places accounts at that level under review. Split the rate by stream, source and bounce type, and store the SMTP status code so you can tell a dirty list from a reputation problem.
Your email bounce rate is the share of sent messages that the receiving server refused, divided by the messages you sent. Keep hard bounces under 1% on a healthy list, treat 2% as the point where you investigate, and treat 5% as an incident. Most teams read one blended number off a dashboard and miss that the denominator, the bounce type and the time window each change the answer.
The rest of this piece is about getting the number right first, then deciding what to do about it.
The formula is simple. The denominator is where teams disagree.
Bounce rate equals bounced messages divided by sent messages, times 100. Some ESPs divide by delivered messages instead, which makes the rate look larger because delivered already excludes the bounces. Check which one your provider reports before you compare it to any benchmark.
Amazon SES, for example, computes its bounce rate from hard bounces only, measured against what you sent through the account. That detail matters, because a dashboard that mixes soft and hard bounces will show a higher number than the one your provider uses to judge you.
Pick one definition and write it down next to the metric, in the dashboard title if you have to. We use hard bounces over sent, per sending domain, per 24 hours and per 7 days. If two people on your team quote different numbers for the same week, the denominator is the first thing to compare.

Hard, soft and block bounces are three different signals
A hard bounce is a permanent failure. The address does not exist, the domain does not resolve, or the mailbox was closed. SMTP reports it with a 5.x.x enhanced status code, defined in RFC 3463.
A soft bounce is a transient failure: a full mailbox, a server that is down, a message that is too large. These come back as 4.x.x codes and a well-behaved sender retries them. If you want the full classification, we covered the SMTP code mapping in our earlier soft bounce vs hard bounce guide.
The third category is the one dashboards hide. A block is a 5.x.x rejection that says nothing about the address and everything about you: a blocklisted IP, a failed authentication check, a content or reputation filter. Counting a block as a hard bounce makes your list look dirty when the real problem is your sending setup.
Skip any report that shows a single "bounce" line. Split it into three series, or you will clean a list that was never the problem.
What counts as a good bounce rate in 2026?
There is no single published number, and that is worth knowing before you quote one. Gmail and Yahoo publish thresholds for spam complaints, not for bounces. Google asks bulk senders to keep the spam rate reported in Postmaster Tools under 0.10% and never reach 0.30%, per its sender guidelines FAQ.
For bounces, the working numbers come from ESPs and from practice. These are the thresholds we use as alert levels, not guarantees from any mailbox provider.
Hard bounce rate per domain over 24 hours, and how we treat it:
Under 0.5%: normal for an engaged, verified list.
0.5% to 1%: watch, and check the sources of new addresses.
1% to 2%: investigate, and pause the segment with the highest rate.
2% to 5%: stop bulk sends from that stream and find the import or form behind it.
Over 5%: incident. Amazon SES puts accounts at this level under review.
The last row is a documented line. In its reputation dashboard documentation, Amazon SES states that an account at a 5% bounce rate or higher is placed under review, and that sending might be paused if the rate stays above 10%. Other providers use different numbers and wording, so read your own contract.
Segment first: a blended rate hides the stream that is failing
An account-wide 0.8% can contain a transactional stream at 0.1% and a re-engagement import at 6%. The blend looks acceptable and the second stream is quietly damaging the sending domain.
Calculate the rate per stream, per source and per recipient domain. Four cuts catch most problems:
By stream. Transactional, lifecycle and bulk campaigns should never share one number.
By signup source. Forms, API signups, CSV imports and partner lists have very different address quality.
By recipient domain. A spike at one provider usually means a rejection policy, not a dirty list.
By address age. Addresses collected more than 12 months ago bounce at a higher rate than fresh ones.
This is not a reporting nicety. It is the difference between fixing a form validation bug in an hour and purging a healthy list in a panic.

A fifth cut worth adding once the others are in place: by sending IP or domain. If you run a dedicated IP for transactional mail and a shared pool for campaigns, a spike on one of them tells you where to look before you open a single log line.
Reading bounce events from your provider without losing them
Every serious ESP exposes bounces as events: a webhook, a notification topic or an events API. Treat that feed as the source of truth and write it into your own store, because dashboards aggregate and lose the detail you need later.
Persist these fields for each event: message id, recipient, bounce type, the enhanced status code, the diagnostic text and the timestamp. With those six you can answer almost every question that comes up in a postmortem.
{
"event": "bounce",
"message_id": "msg_01H9",
"recipient": "user@example.com",
"bounce_type": "permanent",
"status": "5.1.1",
"diagnostic": "550 5.1.1 user unknown",
"stream": "lifecycle",
"ts": "2026-11-02T09:14:03Z"
}Make the handler idempotent, and key it on the provider event id plus the message id. Providers retry webhooks, and a duplicated hard-bounce event that increments a counter twice will distort your rate and can suppress an address that is actually fine.
Postmark and Resend both separate bounce types in their events and let you pull them per message stream, which makes the stream-level split above cheap to build.
The suppression rule that does most of the work
The single highest-leverage control is automatic suppression. After one hard bounce, stop sending to that address, permanently, at the application layer rather than relying only on the provider list.
Most ESPs suppress hard bounces for you. The gap appears when you switch providers, run two in parallel, or send from a system that never reads the suppression list. Your own table keyed on a normalized address closes that gap.
For soft bounces, use a counter instead of a single event. Our default is to suppress after three consecutive soft bounces across at least seven days. A mailbox that has been full for a week is, for lifecycle purposes, gone.
Do not delete bounced addresses from your user table. Flag them with the status code and the date. A deleted row cannot tell you that the same address bounced twice last quarter. You need the record to avoid re-importing the same address from the next CSV, which is the most common way a "cleaned" list gets dirty again.

Why the rate suddenly jumps: the usual causes, ranked
When the rate moves, look for the cause in this order. The first three explain most spikes.
A new import. A CSV from an event, a partner or an old CRM export. Check the bounce rate by source before anything else.
A signup form without validation. Typos like gmial.com and disposable domains. A syntax and MX check at submit time removes most of them, and a confirmation email removes the rest before they ever count as a send in a lifecycle flow.
A sending change. A new IP, a new domain, or a warmup that ramped too fast, which turns into blocks rather than hard bounces.
An authentication break. SPF, DKIM or DMARC alignment failing after a DNS change.
A provider-side rejection policy. One recipient domain tightened its filters. Your rate is up at that domain only.
The diagnostic is the status code distribution, grouped by stream and by recipient domain over the same window as the spike. A rise in 5.1.1 (user unknown) points at the list. A rise in 5.7.x points at policy, authentication or reputation. Those need opposite fixes, which is why you store the code.
What we would alert on
Alerting on a daily average is too slow. A bad import can send 40,000 messages in an hour. Alert on a rolling window instead.
Hard bounce rate over 1% across the last 1,000 sends in any stream.
Any single recipient domain above 5% on at least 200 sends in an hour.
A 5.7.x block count that exceeds your normal baseline by a clear margin.
Wire the first two to a pause on the offending stream, not to a page for a human. A human can investigate afterwards. The pause is what protects your reputation in the next ten minutes.
Export the rate to the monitoring you already run, whether that is Grafana, Datadog or something homegrown, and keep the stream label on the series so the split survives the export.
For reporting upward, use hard bounce rate per stream over a 7-day window, plus the count of blocks. Leave soft bounces in the engineering view, where they are useful, and out of the executive one, where they cause confusion. Never report the blended account number alone, because it moves for reasons nobody in the room can explain.
If a stakeholder asks for one figure, give the transactional stream's hard bounce rate. It is the stream where a failure costs you a password reset or an invoice, and it is the cleanest read on whether your infrastructure is healthy.
The next concrete step is small: pull the last 30 days of bounce events, group by stream and status code, and see which row you did not expect.