An SMTP reply is three digits plus optional text, and an enhanced status code is three
dot-separated numbers inside that text. Together they answer exactly two questions: **should this
message be retried, and whose problem is it?** Every other use of these codes is decoration.
The retry answer comes from the first digit of the reply. The fault answer comes from the middle
number of the enhanced code. If you remember nothing else, remember those two positions.
Reply code structure
RFC 5321 defines the first digit as the outcome class and the second as a broad category.
| First digit | Meaning |
|---|---|
2xx | The command succeeded. |
3xx | The server is ready for the next part of the input. |
4xx | Transient negative. The command failed; retry the same message later. |
5xx | Permanent negative. The command failed; do not retry. |
There is no 1xx class in SMTP. Tables that list "1XX - informational responses" have borrowed
the row from HTTP. SMTP has no informational replies, and no server will ever send one.
The 3xx class has exactly two members in normal use: 354 Start mail input after DATA, and
334 as the base64 challenge during AUTH. Tables describing 3xx as "persistent transient
negative completion" have mangled the RFC's own wording, which applies that phrase to 4xx.
The replies you will actually see
Success and intermediate:
| Code | Meaning |
|---|---|
220 | Service ready - the greeting. |
250 | Requested action completed. |
251 | User not local; will forward. |
334 | AUTH challenge, base64. |
354 | Start mail input; end with <CRLF>.<CRLF>. |
Transient failures - retry these:
| Code | Typical text | What to do |
|---|---|---|
421 4.7.0 | Service not available, closing transmission channel | Reduce connection rate; retry. |
450 4.2.1 | Mailbox unavailable, or recipient rate limited | Retry later, do not suppress. |
451 4.3.0 | Local error in processing | Receiver-side; retry. |
451 4.4.2 | Bad connection | Network between MTAs; retry. |
452 4.2.2 | Insufficient storage - mailbox full | Retry for a few days, then give up. |
452 4.5.3 | Too many recipients | Split the batch and resend. |
454 4.7.0 | Temporary authentication failure | Retry; check the auth backend. |
Permanent failures - do not retry:
| Code | Typical text | Suppress the address? |
|---|---|---|
500 5.5.2 | Syntax error, command unrecognised | No - fix your client. |
502 5.5.1 | Command not implemented | No - fix your client. |
503 5.5.1 | Bad sequence of commands | No - fix your client. |
530 5.7.0 | Authentication required | No - fix your credentials. |
535 5.7.8 | Credentials not accepted | No - fix your credentials. |
550 5.1.1 | Mailbox does not exist | Yes. |
550 5.1.2 | Host or domain unknown | Yes. |
550 5.7.1 | Message rejected by policy | No - this is about you. |
552 5.2.2 | Mailbox over quota | No - retry in a few days. |
552 5.3.4 | Message size exceeds limit | No - send a smaller message. |
554 5.7.1 | Transaction failed, blocked | No - fix reputation or authentication. |
556 5.1.10 | Domain does not accept mail (null MX) | Yes. |
Enhanced status codes, digit by digit
RFC 3463 defines the format as class.subject.detail, and RFC 5248 maintains the registry of
assigned values.
The class repeats the reply class: 2 success, 4 transient, 5 permanent. If the class
digit and the reply's first digit disagree, trust the reply - the enhanced code is often copied
inconsistently between server versions.
The subject is the part worth learning, because it tells you who owns the problem:
| Subject | Area | Whose problem |
|---|---|---|
.0 | Other or undefined | Unknown - read the text. |
.1 | Addressing | The recipient address. |
.2 | Mailbox | The recipient's mailbox state. |
.3 | Mail system | The receiving server. |
.4 | Network and routing | Infrastructure between you. |
.5 | Mail delivery protocol | Your client's SMTP conversation. |
.6 | Message content or media | Your message body. |
.7 | Security and policy | You - reputation, authentication, content judgement. |
So 5.1.1 is a permanent addressing failure: the address is dead, suppress it. 5.7.1 is a
permanent policy failure: the address is fine and something about your sending is not. Those two
get conflated constantly, and conflating them is how senders end up with suppression lists full of
valid contacts and an unfixed reputation problem.
Turning codes into a working policy
- Branch on the reply's first digit first.
4xxqueues,5xxstops. Nothing else. - For `5xx`, branch on the subject digit. Only
.1and the null-MX5.1.10justify
suppression.
- Give `4xx` a retry schedule with a ceiling. Retry frequently for the first hours, then back
off, and give up after four to five days. Then record a bounce.
- Treat `.7` as an alarm, not a bounce. Count
.7rejections per receiving provider. A rise
at one provider is a policy change or a reputation slide you can still fix.
- Keep the raw string. Store the full
Diagnostic-Code:text, not just the number. Providers
put the actionable detail - a block reference, a help URL, a bracketed internal code - in the
text.
What not to do
- Do not key your logic on the enhanced code alone. Plenty of servers send mismatched pairs,
such as 530 5.7.1 where the registry says 5.7.0.
- Do not collapse `4xx` and `5xx` into one "bounce" counter. They demand opposite actions.
- Do not suppress on `.7`. You will burn good contacts and leave the real cause in place.
- Do not retry a `5xx` because the text sounds temporary. "Try again later" inside a
550is
boilerplate; the class digit is the contract.
MailPilot acts on this distinction rather than averaging it away: it tracks per-mailbox reputation
daily, measures inbox placement per provider with a seed-inbox network, and checks SPF, DKIM and
DMARC - so when .7 rejections start appearing you can see immediately whether authentication or
reputation is the cause.
Ready to reach the inbox every time?
Automated email warmup across real peer mailboxes. Live inbox placement monitoring. Free 7-day trial - no credit card required.
Start free trial