Reading SMTP Rejection Codes from Gmail, Outlook, and Yahoo (and What Each One Actually Wants)
Every rejection line from a major mailbox provider is a machine-readable instruction, not an insult. Learn to parse the reply code, the enhanced status, and the vendor's private subcodes into a concrete root cause — and to tell a "back off and retry" 4xx apart from a "stop retrying, fix DNS/auth first" 5xx.
EvilMail TeamJuly 16, 202610 min read
Here is a single line from a Postfix log that sends people into a spiral:
text
status=deferred (host gmail-smtp-in.l.google.com said:
421-4.7.28 [203.0.113.10 15] Gmail has detected an unusual rate of
unsolicited mail originating from your IP address. To protect our
users from spam, mail sent from your IP address has been temporarily
rate limited. 421 4.7.28 https://support.google.com/mail/answer/81126)
Most operators do one of two things with this: they panic, or they mash "retry now" a dozen times. Both are wrong, and the second actively makes it worse — every aggressive retry against a throttle is another data point teaching the filter that you behave like a spammer.
The line already tells you exactly what to fix. 421 means defer, not dead. 4.7.28 means security/policy, rate class. The bracketed [203.0.113.10 15]
Reading SMTP Rejection Codes: Gmail, Outlook & Yahoo Explained — EvilMail Blog
is your sending IP followed by a reputation counter. The instruction is: slow down, lower your complaint rate, and let the existing queue drain on its normal backoff schedule. The rest of this is just learning to read that instruction on sight instead of reacting to the English.
The two numbers that matter
Every SMTP response carries two codes, defined by two different RFCs, and you need both.
The basic three-digit reply (RFC 5321) is the one everybody sees. The first digit is the whole game:
2xx — accepted. 250 means queued for delivery.
4xx — transient failure. Defer and retry with backoff; the condition is expected to clear.
5xx — permanent failure. Bounce. Retrying is pointless and reputationally expensive.
The enhanced status code (RFC 3463) is the dotted triple, class.subject.detail. The class mirrors the first digit (4 or 5). The subject is the useful field almost nobody reads:
So 5.7.26 decodes to permanent + security/policy + detail 26. 4.7.28 decodes to transient + security/policy + detail 28. Read left to right and you know the severity and the department before you read a word of English.
The trap: vendors append their own English text and a bracketed subcode after the enhanced status, and that tail is where the real instruction lives. [TSS04], [TS03], [BL21], [203.0.113.10 15] are not noise — they are the vendor's private index into its own knowledge base.
Alert on anything matching 5\.7\. — that is the family that means "your DNS, auth, or reputation is broken," and it will not fix itself.
Gmail: authentication and rate, spelled out
Google's codes are the best documented of the three, and since the 2024 bulk-sender rules went to full enforcement they are also the most literal.
`550 5.7.26` — "This message does not have authentication information or fails to pass authentication checks." Translation: you failed SPF or DKIM, and you failed DMARC alignment. For a bulk sender this is a hard wall, not a spam-score nudge.
`550 5.7.25` — "The IP address sending this message does not have a PTR record setup." Pure rDNS problem. Fix the reverse zone.
`421 4.7.28` — the throttle from the opening. Volume and complaints on your IP. Defer; do not parallelize retries.
`550 5.7.1 ... likely unsolicited mail` — content and reputation block. This is your domain or IP reputation talking, not a config bug.
`452 4.2.2` — recipient over quota (transient). `550 5.4.5` — you hit Gmail's daily sending limit. `550 5.1.1` — no such user; suppress that address permanently.
Google Postmaster Tools is the source of truth behind these. The number that governs your fate is the spam complaint rate: keep it under 0.30%, and realistically aim under 0.10%. Sit above 0.30% for any sustained stretch and 421 4.7.28 becomes your daily reality. Watch domain reputation and IP reputation separately — a warmed IP with a fresh, unaligned domain still fails 5.7.26.
To test authentication end to end against Google's real MX from your own host:
Then read the Authentication-Results header on the delivered copy. If it shows spf=pass ... dkim=pass ... dmarc=pass, 5.7.26 will not happen.
Outlook / Microsoft 365: it's a blocklist conversation
Microsoft's dialect is blunter and almost entirely about IP reputation. Content matters less; whether Redmond trusts your IP matters more.
`550 5.7.606`–`5.7.649` "Access denied, banned sending IP [ip]" — you are on Microsoft's internal blocklist. There is no DNS fix; you delist through the mitigation form at sender.office.com. The form only works from a matching PTR — if your reverse DNS is broken, you cannot even ask to be let out.
`550 5.7.511 "Access denied, banned sender"` — SmartScreen has flagged the sending domain, not just the IP.
`550 5.7.1 "Service unavailable, Client host [ip] blocked using Spamhaus"` — a third-party RBL. Microsoft is only enforcing it. Fix this at Spamhaus, not at Microsoft.
`S3140` / `S3150` — spam-content text blocks. `421 4.3.2` — too many concurrent connections; cap your concurrency.
Two tools actually move the needle here, and neither is the mitigation form. SNDS (Smart Network Data Services, postmaster.live.com/snds) shows the complaint and trap-hit data Microsoft holds on your IP range, and JMRP (Junk Mail Reporting Program) mails you a copy every time an Outlook.com user hits "junk." Enroll in both before you have a problem; they are your only window into a system that otherwise says nothing but "banned."
Yahoo / AOL: the bracketed subcode is the manual
Yahoo and AOL share infrastructure, and both encode the actual reason inside a bracket tag. Ignore the tag and every message looks identical; read it and you get a precise diagnosis.
`421 4.7.0 [TSS04]` / `[TSS09]` — temporary deferral driven by complaint rate. Retrying works, but only once you lower complaints; otherwise you defer forever.
`421 4.7.0 [TS03]` — "Messages from [ip] will be permanently deferred; Retrying will NOT succeed." This is the landmine: a 4xx code that is permanent in intent. Your queue will burn its entire retry lifetime on it and then bounce. Treat it as a hard block and open a Yahoo Sender Hub case.
`553 5.7.1 [BL21]` — your IP is on an RBL (usually Spamhaus).
Yahoo enforces the same 2024 requirements as Gmail: SPF and DKIM both passing, DMARC at minimum p=none with alignment, RFC 8058 one-click unsubscribe, and complaint rate under 0.3%. Enroll in Yahoo's Complaint Feedback Loop through Sender Hub so you can actually see who is complaining.
React correctly: your queue should not hammer 5xx
Parsing the code is half the job. The other half is making your MTA behave.
In Postfix, a 4xx leaves the message queued and retried on a schedule between minimal_backoff_time and maximal_backoff_time, up to maximal_queue_lifetime (default 5 days), then it bounces. A 5xx bounces immediately. Manually flushing a queue full of 5xx failures does nothing but re-hit the provider and re-confirm your bad reputation.
bash
postqueue -p # inspect the queue and read the reasons
postqueue -f # flush — only useful for 4xx that has cleared
postsuper -d DEADBEEF123 # delete one stuck message by queue id
postsuper -d ALL deferred # nuke the deferred queue (use with care)
When a provider throttles you, the correct move is not faster retries — it is a slower, dedicated transport so you stop tripping the rate limit at all. In master.cf:
ini
yahoo unix - - n - - smtp
-o smtp_destination_rate_delay=1s
A non-zero smtp_destination_rate_delay pins per-destination concurrency to a single connection and paces one message per second — no concurrency_limit line needed, because the rate delay overrides it. Route Yahoo/AOL mail to this transport via transport_maps, and [TSS04] quietly goes away. Do the same per destination for any provider that throttles you.
The three fixable causes behind 90% of these codes
Once you have parsed a few hundred of these, the same three root causes account for nearly everything:
1.Broken SPF/DKIM/DMARC alignment — Gmail 5.7.26, Yahoo 554 5.7.9. The message is signed or framed wrong.
2.A PTR that does not match your HELO — Gmail 5.7.25, and the reason Microsoft's delist form silently fails.
3.A complaint rate over 0.3% — Gmail 421 4.7.28, Yahoo [TSS04], Microsoft SNDS flags.
Here is evilmail.pro's own live setup as a worked example, imperfections included:
Look at that last line. The PTR resolves to mail.example.net, not anything under evilmail.pro. That is a real-world alignment gotcha: as long as the sending host's HELO also announces mail.example.net, and forward DNS for mail.example.net resolves back to 203.0.113.10, the forward-confirmed reverse DNS is consistent and providers accept it — even though the PTR hostname lives in a different domain than the envelope sender. What breaks deliverability is a PTR that matches *nothing* you announce, not a PTR in a sibling domain. Keep the HELO, the PTR, and the forward record pointing at each other and Gmail 5.7.25 never fires.
Fix-it checklist
Verify the PTR for your sending IP, make your HELO announce that exact hostname, and confirm forward DNS resolves back to the IP (dig -x, then dig the result).
Publish SPF that lists your real sending IP and ends in -all (or a monitored ~all) — don't leave a wide-open policy on a production sender.
Sign with DKIM and confirm DMARC alignment — check adkim/aspf, and that the d= domain matches the From:.
Add List-Unsubscribe and List-Unsubscribe-Post: List-Unsubscribe=One-Click (RFC 8058) to every bulk message.
Register for Google Postmaster Tools, Microsoft SNDS and JMRP, and Yahoo Sender Hub with the Complaint FBL.
Hold the spam complaint rate under 0.3%, and treat 0.1% as your real ceiling.
Add per-destination rate limiting before a provider throttles you, not after.
Parse enhanced status codes out of your logs and alert on any 5.7.x.
Special-case Yahoo [TS03] and persistent Gmail 421 in your retry logic — treat them as permanent so your queue does not waste five days pretending they will clear.