Deliverability
SMTP Bounce Codes Explained: 4xx and 5xx Reply Codes
SMTP bounce codes are the numeric replies a receiving mail server sends when it can’t or won’t accept a message. Codes starting with 4 (like 421 or 452) are temporary failures, so the sender should retry later. Codes starting with 5 (like 550 or 554) are permanent failures, so retrying the same message won’t work. Most bounces also carry an enhanced status code such as 5.1.1, which tells you why: a bad address, a full mailbox, a policy block, and so on.
This guide explains how to read both kinds of codes and gives a reference table of real errors from Gmail, Microsoft, and Yahoo, with what each one means for your list.
The two codes in every bounce
A typical bounce line looks like this:
550 5.1.1 The email account that you tried to reach does not exist.
It contains three parts:
550: the basic SMTP reply code, defined in RFC 5321.5.1.1: the enhanced status code, defined in RFC 3463.- The text: a human-readable explanation, which each provider writes however it likes.
The basic code tells your mail server what to do next (retry or give up). The enhanced code and the text tell you what went wrong. The M3AAWG Sender Best Common Practices make the point that the numeric codes weren’t designed for bulk senders and don’t say whether an address should be removed from a list. You need the descriptive text for that.
Basic SMTP reply codes (RFC 5321)
The first digit sets the outcome:
| First digit | Meaning | What your server does |
|---|---|---|
2xx | Success | Message accepted |
3xx | Intermediate | Waiting for more input (for example 354 after DATA) |
4xx | Transient failure | Queue the message and retry later |
5xx | Permanent failure | Don’t repeat the same request |
The codes you’ll see most in bounces, with their RFC 5321 meanings:
| Code | RFC 5321 meaning | In practice |
|---|---|---|
421 | Service not available, closing transmission channel | Server busy, rate-limited, or shutting down. Retry. |
450 | Mailbox unavailable (for example busy or temporarily blocked) | Temporary. Often rate limiting or greylisting. |
451 | Action aborted: local error in processing | Temporary server-side problem. Retry. |
452 | Insufficient system storage | Temporary. Often “mailbox full” or too many recipients. |
550 | Mailbox unavailable (not found, no access, or rejected for policy) | Permanent. Could be a bad address or a block. Read the enhanced code. |
551 | User not local; please try another path | Permanent. Rare in modern mail. |
552 | Exceeded storage allocation | Usually permanent, but see the exception below. |
553 | Mailbox name not allowed (for example bad syntax) | Permanent. Malformed address or domain. |
554 | Transaction failed | Permanent. A catch-all for rejection. |
The 552 exception: RFC 5321 section 4.5.3.1.10 notes that some servers return 552 when a message has too many recipients, where 452 is the correct code, and says clients should treat 552 in that situation as temporary.
Enhanced status codes (RFC 3463)
Enhanced codes have the form class.subject.detail.
The class repeats the outcome: 2 success, 4 persistent transient failure, 5 permanent failure.
The subject tells you which part of the system failed:
| Subject | Area | What it usually points to |
|---|---|---|
x.0.x | Other or undefined | No detail available |
x.1.x | Addressing | The address or domain is wrong |
x.2.x | Mailbox | The recipient’s mailbox (full, disabled) |
x.3.x | Mail system | The receiving system |
x.4.x | Network and routing | DNS, routing, timeouts |
x.5.x | Mail delivery protocol | SMTP protocol errors |
x.6.x | Message content or media | Encoding or media type |
x.7.x | Security or policy | Authentication, spam filtering, blocklists |
Some specific detail codes from RFC 3463 worth memorizing:
x.1.1Bad destination mailbox address (the part before the@is invalid)x.1.2Bad destination system address (the domain is invalid)x.2.1Mailbox disabled, not accepting messagesx.2.2Mailbox full (defined as a persistent transient failure)x.2.3Message length exceeds administrative limitx.4.4Unable to routex.4.7Delivery time expiredx.7.1Delivery not authorized, message refused
The full registry is maintained by IANA under the SMTP Enhanced Status Codes page, which includes later additions such as x.1.10 for a recipient domain with a null MX (RFC 7505).
Common bounce codes by provider
Each mailbox provider writes its own text, so the same enhanced code reads differently in Gmail, Microsoft 365, and Yahoo. Here are the ones you’ll run into most.
Gmail SMTP error codes
From Google’s SMTP error reference:
| Code | Gmail’s text (abridged) | Type | What to do |
|---|---|---|---|
550 5.1.1 | The email account that you tried to reach does not exist | Hard | Suppress the address |
553 5.1.2 | We weren’t able to find the recipient domain | Hard | Suppress; check for a typo |
550 5.2.1 | The email account that you tried to reach is inactive | Hard | Suppress |
452 4.2.2 | The recipient’s inbox is out of storage space | Soft | Retry; watch for repeats |
552 5.2.2 | The recipient’s inbox is out of storage space and inactive | Hard in practice | Suppress |
450 4.2.1 | The user you are trying to contact is receiving email too quickly | Soft | Slow down, retry later |
421 4.7.0 | Try again later, closing connection (several variants) | Soft | Retry; check reputation if persistent |
421 4.7.28 | Gmail has detected an unusual rate of email | Soft | Reduce volume |
550 5.7.1 | This message is likely unsolicited email (one of several variants) | Block | Fix content, list quality, reputation |
550 5.7.25 | Sending IP address doesn’t have a PTR record | Block | Add reverse DNS |
550 5.7.26 | Unauthenticated email is not accepted due to domain’s DMARC policy | Block | Fix SPF/DKIM alignment |
452 4.5.3 | Your message has too many recipients | Soft | Split the recipient list |
Microsoft 365 and Exchange Online
From Microsoft’s NDR reference for Exchange Online:
| Code | Microsoft’s description | Type | What to do |
|---|---|---|---|
5.1.1 | Bad destination mailbox address | Hard | Check the address; suppress if confirmed |
5.1.10 | Recipient not found (SMTP address lookup failed) | Hard | Suppress |
5.4.1 | Recipient address rejected: Access denied | Hard | Usually the address doesn’t exist |
5.4.1 | Relay Access Denied | Config | Receiving server or DNS misconfigured |
5.7.1 | Delivery not authorized | Block | Recipient restricts senders (often a group) |
4.4.7 | Message expired | Soft that gave up | Check the address and the receiving server |
Note that Microsoft’s 5.2.2 means submission quota exceeded, a sender-side rate limit, not “mailbox full.” The same enhanced code can mean different things at different providers, which is another reason to read the text.
Yahoo
Yahoo’s SMTP error codes page groups errors by category rather than listing every code:
554“This user doesn’t have a yahoo.com account”: the address doesn’t exist. Yahoo says not to retry and to remove it from your list.421/451temporary errors: unusual traffic, complaints, or busy servers. Retry later and review Yahoo’s sender requirements.553/554permanent errors: invalid addresses, DMARC or DKIM failure, unacceptable content, or a Spamhaus listing. Don’t retry; remove addresses that produce5xxerrors.- “Excessive unknown recipients”: your server is sending to many invalid addresses. Yahoo tells senders to remove bouncing addresses.
How to act on a bounce code
Here’s a simplified decision function. It’s deliberately conservative: it only suppresses on clear addressing or mailbox failures and treats policy blocks as a sender problem.
import re
def classify_bounce(smtp_reply: str) -> str:
"""Return 'suppress', 'retry', 'fix_sender', or 'review'."""
m = re.search(r'\b([245])\.(\d{1,3})\.(\d{1,3})\b', smtp_reply)
basic = smtp_reply.strip()[:1]
if not m:
# No enhanced code: fall back to the basic reply class
return 'retry' if basic == '4' else 'review'
cls, subject, detail = m.group(1), m.group(2), m.group(3)
if cls == '4':
return 'retry' # mailbox full, throttling, greylisting
if subject == '1' and detail in ('1', '2', '10'):
return 'suppress' # bad mailbox, bad domain, null MX
if subject == '2' and detail in ('1', '2'):
return 'suppress' # disabled or full-and-inactive
if subject == '7':
return 'fix_sender' # auth, reputation, policy
return 'review' # everything else: a human should look
print(classify_bounce("550 5.1.1 The email account that you tried to reach does not exist."))
# suppress
print(classify_bounce("550 5.7.26 Unauthenticated email from example.com is not accepted"))
# fix_sender
In production you’d also count repeated 4xx failures per address and suppress after a threshold. Our existing guide on bounce classification covers that policy side, and retry schedules covers how long to keep retrying a 4xx. If your ESP sends bounces as webhooks, see processing bounce webhooks.
Codes that confuse people
550 doesn’t always mean “user unknown.” RFC 5321 lets 550 cover a missing mailbox, lack of access, or a policy rejection. Always check the enhanced code. For the most common one, see 550 5.1.1 User Unknown.
5.2.2 isn’t always “mailbox full.” As noted above, Microsoft uses it for a sender submission quota.
“Mailbox full” can be a hard or a soft bounce. Gmail uses 452 4.2.2 for a full mailbox and 552 5.2.2 for one that’s full and inactive. More on this in “Mailbox Full” Bounces: Should You Remove the Address?
4.4.7 is a soft bounce that gave up. The sending system retried until the message expired. Look at the earlier deferral reasons to find the real cause.
5.7.x is about you. Policy codes are permanent for that message, but the recipient address is usually fine. Fix your authentication or reputation instead of deleting the contact. For the full breakdown, read Hard Bounce vs Soft Bounce: Causes and Fixes.
Prevent the codes you can control
You can’t prevent 4xx throttling at a busy provider, but you can prevent most 5.1.x errors before you send. The free email verifier on this site checks syntax, confirms the domain exists and has MX records, flags disposable and role-based addresses, identifies free-provider domains, and suggests fixes for common domain typos. That covers the causes of 553 5.1.2 and many typo-driven 5.1.1 errors. It doesn’t connect to the recipient’s mailbox, so it can’t tell you whether a specific user exists at a valid domain.
FAQ
What’s the difference between a 4xx and a 5xx SMTP code?
A 4xx code is a temporary failure, so your server should retry the message later. A 5xx code is a permanent failure for that message, and retrying it unchanged won’t succeed. Whether you should also remove the address depends on the enhanced code: 5.1.x usually means remove, 5.7.x usually means fix your sending setup.
What does SMTP error 554 mean?
RFC 5321 defines 554 as “Transaction failed,” a general permanent rejection. Providers use it for many reasons: Yahoo uses it for addresses that don’t exist and for policy rejections. Read the enhanced code and the text to see which one you have.
Where do I find the bounce code for a failed email?
If you send from an ESP, it appears in the bounce report or webhook event, usually in a field like diagnosticCode or reason. If you send from a regular mailbox, open the “Undeliverable” or “Delivery Status Notification” email and look for the line starting with a three-digit code, or the Diagnostic-Code field in the attached delivery report.
Are enhanced status codes the same at every provider?
The structure is standardized by RFC 3463, but providers apply the codes differently and write their own explanatory text. Microsoft’s 5.2.2, for example, means a sending quota was exceeded, while Gmail’s 552 5.2.2 means the recipient’s mailbox is full and inactive.
Free email verifier: syntax, MX, disposable and role-based addresses, typos. Paste up to 100 at once.