- January 2023
- Engineering Memo · External Release
The accounting log for a high-volume sending programme contains dozens of different SMTP response codes and error types every day. Treating all errors identically — suppressing on any 5xx, retrying on any 4xx — produces both unnecessary suppressions (for policy rejections that don't indicate invalid addresses) and missed suppressions (for persistent 4xx deferrals that indicate functionally undeliverable addresses). The classification framework in this note provides the correct operational response for each major error category encountered in production email sending.
Address Errors vs Policy Errors
Address errors indicate that the recipient address itself is the problem — it is invalid, non-existent, or deprovisioned. The correct response is permanent suppression: do not retry, do not send again. Key address error codes: 550 5.1.1 (mailbox not found), 550 5.1.2 (bad destination mailbox address), 553 (mailbox name not allowed), 551 (user not local). These codes confirm that the address cannot receive email at the specified mailbox and should be permanently suppressed.
Policy errors indicate that the receiving server rejected the message for policy reasons — IP reputation, content filtering, domain reputation, or authentication failure — not because the recipient address is invalid. The correct response is investigation: the address may be valid, but the sending configuration needs to be corrected before the message can be delivered. Key policy error codes: 550 5.7.1 (message rejected for policy reasons), 550 5.7.26 (DMARC failure), 554 5.7.1 (spam reputation rejection). For policy errors, suppress the specific message send but do not suppress the recipient address — correct the configuration first, then re-attempt delivery.
The critical distinction: suppressing a valid address because of a policy rejection wastes a legitimate marketing contact and may violate the programme's data obligations. Not suppressing an invalid address because its rejection was classified as a policy error generates ongoing hard bounces that damage reputation. Getting the classification right determines whether the correct list management action follows each error.
Figure 1 — SMTP Error Classification Framework
Domain Errors and Infrastructure Errors
Domain errors indicate the recipient's domain does not exist or has no MX record: 550 5.1.2 (bad destination domain), DNS resolution failure (no MX record). The correct response: domain-level suppression. Not just the specific address that generated the error, but all addresses at the same domain should be investigated — if the domain has no MX record, all addresses at that domain are undeliverable. Domain-level errors from B2B contact databases frequently indicate company closures, domain migrations, or domain expiry.
Infrastructure errors (connection timeouts, TLS negotiation failures, session resets) indicate network or configuration issues rather than address or policy problems. The correct response: investigate the infrastructure rather than suppressing the address. A connection timeout to a specific ISP affects all messages to that ISP simultaneously — not just the individual recipient address that generated the timeout. Treating infrastructure errors as address errors produces mass-suppression of valid addresses from the affected ISP.
Blocklist errors (554 from DNSBL lookup, specific blocklist rejection text) indicate the sending IP or domain is on a blocklist. The correct response: investigate the blocklist listing and request delisting. The recipient addresses are valid; the sending infrastructure's reputation is the problem. Suppressing recipients who generated blocklist-related rejections removes valid contacts whose deliverability will recover when the blocklist listing is resolved.
Table 1 — SMTP error classification and correct operational response
| Error category | Example codes | Correct action |
|---|---|---|
| Address invalid | 550 5.1.1, 553 | Suppress address permanently |
| Policy rejection | 550 5.7.1, 554 5.7.x | Investigate config; don't suppress address |
| Domain invalid | 550 5.1.2, DNS NXDOMAIN | Suppress all addresses at domain |
| Infrastructure error | Connection timeout, TLS fail | Investigate infrastructure; retry |
| Blocklist rejection | 554 (DNSBL text) | Delist; do not suppress recipients |
| Temporary deferral | 421, 450, 451 | Retry with backoff; reclassify if persistent |
Implementing the classification framework in the bounce processing pipeline requires pattern matching against SMTP response text (since the 3-digit code alone often does not distinguish address errors from policy errors — both commonly use 550). The extended status codes (5.1.1 vs 5.7.1) and the response text are the signals that determine the correct classification. PowerMTA's bounce classification system, configured with per-pattern bounce types as documented in the bounce taxonomy note, implements this framework automatically. The operational value of correct classification: suppression decisions that accurately reflect address quality rather than conflating different error types into a single "hard bounce" classification that generates both false positives and false negatives. Get the classification right, and every suppression decision the system makes automatically is the correct one.
Authentication Error Classification
Authentication failures (DMARC rejections, SPF failures, DKIM failures) are a distinct error category that requires careful handling. When an ISP rejects a message with a 550 5.7.26 (DMARC policy violation), the rejection is not because the recipient address is invalid — the address is valid, but the message failed authentication. Suppressing the recipient address in response to a DMARC rejection wastes a valid contact and hides the real problem: a misconfigured authentication stack that will fail for every message sent to that ISP until the configuration is corrected.
The correct response to authentication failure rejections: create an investigation queue for messages that generated authentication-specific SMTP codes. The investigation queue holds the affected messages (with recipient addresses, sending source, and authentication failure code) pending a configuration review. Once the authentication issue is corrected (DKIM key rotation, SPF record update, DMARC alignment fix), the queued messages can be re-injected and the recipients are not incorrectly suppressed. This queue-and-investigate approach requires more operational overhead than simple suppression but produces dramatically better outcomes: authentication issues are identified and resolved, valid recipients are not unnecessarily suppressed, and the root cause is addressed rather than masked by suppression.
PowerMTA's bounce classification configuration supports an "authentication" bounce type that can be mapped to authentication-specific SMTP response patterns. Messages classified as authentication bounces are handled separately from hard bounces (which trigger suppression) — they are logged for investigation without triggering automatic suppression. The investigation workflow is then a manual or semi-automated review of authentication bounce classifications, with the goal of identifying and resolving the authentication configuration issue before re-injecting the affected messages.
Rate Limiting vs Content Filtering
Rate limiting responses (421 throttle, "try again later") are fundamentally different from content filtering responses (554 content rejected, "message identified as spam"). Both may appear in the accounting log as delivery failures, but they require completely different responses. Rate limiting responses indicate that the sending rate exceeded the ISP's current limit for the sending IP — the correct response is to reduce the injection rate and retry with exponential backoff. Content filtering responses indicate that the message content or sender reputation triggered spam classification — the correct response is to investigate the content, authentication, and reputation signals that triggered the rejection.
Confusing rate limiting with content filtering leads to incorrect interventions: treating rate limiting as a content problem triggers content reviews that find nothing wrong; treating content filtering as a rate problem triggers rate reductions that do not address the actual classification trigger. The SMTP response text provides the signal that distinguishes the two: rate limiting responses contain language like "try again," "resources temporarily unavailable," or specific rate limit codes (421 4.16.55 for Microsoft rate limiting); content filtering responses contain language like "spam," "content rejected," "policy violation," or reputation-related phrases.
Building this distinction into the bounce classification system — with separate bounce types for rate limiting vs content rejection — produces accounting log data that enables the correct operational response automatically. The domain block configuration responds to rate limiting by reducing connection rates; the investigation workflow responds to content filtering by reviewing the spam signal analysis. Both responses are correct; both depend on the error being correctly classified before the automated or manual response is triggered.
The Classification Audit
Quarterly classification audits review the bounce type distribution in the accounting log to verify that each error type is being correctly classified and that the operational responses triggered by each classification are appropriate. The audit questions: What percentage of 550 errors are classified as hard bounces vs policy rejections vs authentication failures? Are there any response text patterns in the 550 category that are being classified as hard bounces but should be classified as policy rejections? Are infrastructure error patterns (connection timeouts) being incorrectly classified as hard bounces?
The audit is most valuable when it reviews the specific response texts in each classification bucket — not just the aggregate counts. A bucket labeled "hard bounce" that contains some response texts clearly indicating policy rejections has a classification accuracy problem that aggregate counts do not reveal. Sampling 50-100 individual error records from each bounce type bucket and verifying that the response text matches the expected classification for that bucket provides the per-record accuracy check that aggregate distribution analysis cannot.
Correct error classification is foundational operational infrastructure — it determines which list management actions are taken automatically for every SMTP error the programme encounters. When the classification is correct, the automated responses are correct: hard bounces generate suppression, policy errors generate investigation alerts, infrastructure errors generate retry and monitoring alerts. When the classification is wrong, the automated responses are wrong: valid addresses get suppressed from policy errors, hard bounces get retried as infrastructure errors, authentication failures get masked as general rejections. The 30 minutes of quarterly classification audit is the operational investment that keeps the automated response system calibrated to the correct response for each error type, indefinitely.
Implementing the Classification Framework in PowerMTA
PowerMTA's bounce classification system uses a configuration file with regex patterns that match SMTP response text and assign each pattern to a bounce type. The standard bounce types are: hard (permanent address failure — triggers suppression), soft (temporary deferral — triggers retry), bad-domain (domain error — triggers domain-level review), policy (policy rejection — triggers investigation, not suppression), spam (spam classification — triggers investigation and reputation review), authentication (authentication failure — triggers config review), and greylist (greylisting deferral — triggers rapid retry).
Each bounce type has a corresponding downstream action in the sending application: hard → add address to suppression list; soft → retry with exponential backoff; bad-domain → flag all addresses at domain for review; policy → add to investigation queue; spam → add to investigation queue and trigger reputation alert; authentication → add to auth-failure investigation queue; greylist → retry after minimum greylist interval (typically 5-10 minutes).
The most important patterns to configure correctly are the ones that distinguish hard bounces from policy rejections within the 550 response code space. Example patterns: /5\.1\.[12]/ → hard (invalid mailbox or domain); /5\.7\.(1|26|350|511)/ → policy (various policy rejection sub-codes); /User.*(unknown|does not exist|not found)/i → hard; /(spam|blocked|rejected).*(policy|reputation)/i → policy. The patterns are ordered by specificity — more specific patterns take precedence over more general ones. Building the pattern library from the actual response texts observed in the accounting log produces the most accurate classification for the specific ISPs and corporate destinations the programme sends to.
The Commercial Cost of Misclassification
Misclassifying policy rejections as hard bounces has a direct commercial cost: valid contacts are removed from the active list and suppressed permanently. For B2B programmes where each contact represents significant potential commercial value, incorrectly suppressing a valid decision-maker because their company's mail server returned a policy rejection (not a mailbox-invalid code) removes a potentially valuable contact permanently from future outreach. The lost pipeline value from these false suppressions is typically invisible — the suppressed contacts never appear in campaign performance reports because they are never sent to — but it is real and accumulating with every misclassified policy rejection.
Misclassifying hard bounces as policy errors (not suppressing when suppression is correct) has a reputation cost: the undeliverable address continues to receive campaign injections, generating hard bounce signals that accumulate in ISP reputation models. At scale, a classification system that under-suppresses generates bounce rate pressure that degrades IP and domain reputation. At 0.1% false-negative classification rate (hard bounces not suppressed) for a programme generating 500 hard bounces per campaign: 0.5 additional undelivered messages per campaign re-injected to invalid addresses, compounding with each campaign cycle. At 12 campaigns per year, this is 6 additional messages to invalid addresses per year — trivial individually, but representative of a systematic classification gap that scales proportionally with programme volume.
The classification framework documented in this note is the operational investment that minimises both types of misclassification cost: false positives (incorrectly suppressing valid addresses from policy errors) and false negatives (not suppressing invalid addresses from hard bounce misclassification). Both have real commercial consequences; both are addressable through correct pattern configuration and quarterly classification audits. The investment in getting the classification right is the investment in protecting both the list quality (no false suppressions) and the sender reputation (no false retention of undeliverable addresses) simultaneously.
SMTP errors are not equal. Each error type carries specific information about what went wrong and what the correct operational response is. The programme that reads this information correctly — through a well-configured classification system and a periodic audit of classification accuracy — operates its list management with precision that misclassification-based programmes cannot achieve. Classify correctly; respond appropriately; and the accounting log's error data will continuously improve both list quality and reputation management rather than generating the false suppressions and false retentions that incorrect classification invariably produces.
Infrastructure Assessment
Our PowerMTA configuration includes a curated bounce classification pattern library that correctly classifies address errors, policy rejections, domain errors, infrastructure errors, and blocklist rejections — producing the right suppression and investigation action for each error type automatically. Request assessment →