Contents
Why bounce categorization matters
Every bulk sender generates bounces, and what an operation does with those bounces, which addresses it suppresses, which reputation signals it acts on, how it counts its delivery health, depends entirely on how the bounces are categorized. A bounce that is categorized correctly drives the right action; a bounce that is miscategorized drives a wrong one. Bounce categorization is therefore not a clerical detail, it is the input to the decisions that protect a sender's list quality and reputation.
This guide exists because PowerMTA's bounce categorization, while capable, depends on pattern matching that does not perfectly fit every sender's receiving environment out of the box. The built-in patterns are a starting point; the receiving providers each phrase their bounces differently and change that phrasing over time, so accurate categorization usually needs custom patterns tuned to the bounce text a particular sender actually receives. The structure of this guide: how PowerMTA classifies bounces, the bounce categories, the built-in pattern set and where it falls short, the soft-versus-hard distinction, writing custom patterns, ISP-specific bounce text, why categorization drives suppression, testing custom patterns, and the diagnostic workflow when bounces are miscategorized.
How PowerMTA classifies bounces
PowerMTA classifies bounces by pattern matching. When a delivery attempt fails, the receiving server returns a response with an SMTP status code and diagnostic text. PowerMTA takes that response and matches it against a set of patterns, each of which maps to a bounce category, and records the resulting category in the accounting log alongside the bounce.
The matching is driven by a bounce-category-patterns file. This file contains the patterns, expressions matched against the bounce response, and the category each pattern assigns. PowerMTA works through the patterns and the first matching pattern determines the category.
The flow:
- A delivery fails; the receiver returns an SMTP code and diagnostic text.
- PowerMTA matches that response against the patterns in the bounce-category-patterns file.
- The matching pattern assigns a category.
- PowerMTA records the bounce and its category in the accounting log.
- Downstream processing reads the category and acts on it, suppression, analytics, reputation signals.
So the bounce-category-patterns file is the brain of bounce classification, and the quality of the categorization is the quality of that file's patterns relative to the actual bounce text the sender receives.
The bounce categories
PowerMTA's bounce categories distinguish the fundamentally different reasons a delivery fails. The important categories, conceptually:
| Category type | What it means | Typical action |
|---|---|---|
| Bad mailbox / bad address | The recipient address does not exist | Suppress the address |
| Mailbox full / over quota | The mailbox exists but is full | Soft, retry, suppress only after persistence |
| Spam / content related | The message was flagged as spam | Reputation signal, do not suppress address |
| Policy related | A receiver policy rejected the message | Reputation signal, investigate |
| Transient / other soft | A temporary failure | Retry, do not suppress |
The bad mailbox category is the clearest: the address does not exist, and continuing to mail it is pointless and harmful to list hygiene. This category drives suppression.
The mailbox full category is a soft condition: the address is real but cannot receive right now. It should not immediately suppress; the address may be deliverable later.
The spam-related and policy-related categories are about the message or the sender, not the address. A spam-flagged bounce is a reputation signal; suppressing the recipient address would not address the actual problem, which is that the receiver disliked the message or the sender's reputation.
The transient category covers temporary failures that warrant a retry rather than any permanent action.
The categories matter because each implies a different action, and the whole point of categorization is to route each bounce to its correct action. A category scheme that lumps these together loses the ability to act differently on a dead address versus a full mailbox versus a spam block.
The built-in pattern set and its limits
PowerMTA ships with a built-in bounce-category-patterns file. This built-in set covers common bounce responses and handles many bounces correctly out of the box.
The built-in patterns are a genuinely useful starting point: they classify the typical, well-phrased bounce responses, the standard non-existent-mailbox messages, the common full-mailbox responses, and so on, into the right categories without the operator writing anything.
But the built-in set has limits, and understanding them is the reason custom patterns exist:
- Provider-specific phrasing. Gmail, Yahoo, Microsoft, and others each phrase their bounce responses in their own way, with their own diagnostic text. The built-in patterns cannot perfectly match every provider's specific text.
- The receiving landscape changes. Providers update their bounce responses over time, introduce new codes, change wording. A built-in pattern set reflects a point in time and drifts out of date.
- New conditions. New rejection types appear, the authentication-enforcement rejections that became prominent with the 2024 bulk sender rules, for instance, and the built-in patterns may not classify them precisely.
The consequence of these limits is that some bounce text falls through the built-in patterns to a generic, catch-all, or unclassified category. A bounce in a generic category has lost the specific meaning that would drive the right action. The built-in set is a good 80-percent solution; closing the remaining gap is what custom patterns are for.
The soft versus hard distinction
Underlying the categories is the fundamental soft-versus-hard bounce distinction, which the categorization must respect.
A hard bounce is a permanent failure: the address does not exist, the domain does not exist, the recipient is permanently undeliverable. A hard bounce will not succeed on retry, and the address should be suppressed. Hard bounces correspond to the bad-mailbox and bad-address categories and carry 5xx SMTP codes for permanent conditions.
A soft bounce is a temporary failure: the mailbox is full, the receiver is temporarily deferring, a transient problem occurred. A soft bounce may succeed on retry, and the address should not be suppressed on a single soft bounce. Soft bounces correspond to the full-mailbox and transient categories and carry 4xx SMTP codes for temporary conditions.
The distinction is not perfectly captured by the SMTP code alone, which is exactly why pattern matching on the diagnostic text matters. A 5xx code is generally permanent, but a 5xx can be returned for a policy or reputation reason that is not about the address being bad, and that should not be treated as a hard bounce of the address. A 4xx is generally temporary, but a persistent 4xx, a mailbox that has been full for weeks, eventually behaves like a hard failure for practical purposes.
So the categorization combines the code and the diagnostic text to place a bounce correctly: not just soft-or-hard by the code's first digit, but the specific category that reflects what actually happened, which then drives whether and when to suppress. The soft-versus-hard distinction is the coarse layer; the categories are the precise layer; and the custom patterns are how the operator makes the precise layer accurate for their receiving environment.
Writing custom patterns
Custom bounce patterns are written into the bounce-category-patterns configuration, supplementing the built-in patterns. Each custom pattern matches a piece of bounce text and assigns it a category.
The process of building custom patterns:
- Examine the accounting log. Look at the actual bounce responses the sender's mail receives, and find the ones landing in generic, catch-all, or unclassified categories. These are the gaps the built-in patterns are not closing.
- Identify the correct category. For each gap, read the bounce text and the code, and determine which category the bounce truly belongs in, bad mailbox, full mailbox, spam-related, policy, transient.
- Write a pattern. Write a pattern that matches the distinctive text of that bounce response, mapping it to the correct category. The pattern should be specific enough to match the intended bounce text without wrongly matching unrelated responses.
- Add it to the configuration and apply.
- Verify that bounces of that type now classify correctly.
A custom pattern conceptually pairs a text match with a category, for example matching a distinctive phrase that a particular provider uses for non-existent mailboxes and assigning it the bad-mailbox category.
The key principle in writing patterns is specificity balance: a pattern too narrow misses variations of the bounce text; a pattern too broad wrongly catches unrelated bounces. The distinctive, stable part of a bounce response, often a specific phrase or an enhanced status code, is what the pattern should key on. The exact syntax for the patterns follows PowerMTA's bounce-category-patterns documentation; the conceptual work is the matching of text to category.
ISP-specific bounce text
The reason custom patterns are usually needed is that the major receiving providers each phrase their bounces distinctively, and a sender's volume to those providers means their bounces dominate the bounce stream.
Each major provider has its own conventions:
- Gmail returns specific diagnostic text and enhanced status codes, and has its own phrasings for non-existent addresses, for policy and reputation blocks, and for rate-related deferrals. Gmail's responses also reference its help documentation in ways that are distinctive.
- Yahoo uses its own diagnostic text, including the TSS-prefixed codes for throttling, and its own phrasings for the various rejection reasons.
- Microsoft returns its own diagnostic text and codes, including the S-prefixed codes and, since the 2025 enforcement, the 550 5.7.515 rejection for bulk-sender compliance failures.
Because a sender's mail goes substantially to these major providers, the bounces from these providers are the bulk of what the bounce categorization handles. Getting the categorization right for Gmail, Yahoo, and Microsoft bounce text is therefore the highest-leverage custom-pattern work.
The custom patterns for ISP-specific bounce text are built the same way as any custom pattern, examine the accounting log, find the provider bounces landing in generic categories, write patterns matching the provider's distinctive text, but the focus is on the providers the sender actually delivers to. A sender whose mail is mostly to Gmail and Microsoft prioritizes custom patterns for Gmail and Microsoft bounce text.
This is ongoing work, because the providers change their bounce responses. A custom pattern set is maintained, not written once: as a provider introduces new bounce text, new patterns are added. Periodically reviewing the accounting log for newly-appearing generic-category bounces keeps the pattern set current.
Categorization drives suppression
The reason all this categorization work matters comes down to suppression: the bounce category determines whether an address is suppressed, and a wrong category causes a wrong suppression decision.
Suppression is not mailing addresses that should not be mailed. The decision to suppress an address after a bounce depends on the bounce category:
| Category | Suppression decision |
|---|---|
| Bad mailbox / bad address | Suppress, the address is permanently dead |
| Mailbox full / soft | Do not suppress on one bounce; suppress only after persistence |
| Spam / policy related | Do not suppress the address; it is a sender-side signal |
| Transient | Do not suppress; retry |
The cost of bad categorization is concrete. Miscategorize a non-existent-mailbox bounce as a soft transient failure, and the dead address is never suppressed, so the sender keeps mailing it indefinitely, wasting sends and signalling poor list hygiene to the receivers. Miscategorize a soft full-mailbox bounce as a hard failure, and a perfectly deliverable recipient is wrongly suppressed and permanently lost from the list. Miscategorize a spam-related policy block as a benign address problem, and the sender suppresses the recipient, which does nothing about the actual reputation issue, while also missing the reputation signal the bounce was carrying. Each of these is a real, costly mistake, and each traces directly back to the bounce landing in the wrong category. Accurate categorization is the prerequisite for accurate suppression.
This is the whole justification for caring about bounce patterns. The categorization is not an end in itself; it is the input to suppression, and suppression directly affects list quality and sender reputation. A sender with accurate categorization suppresses dead addresses promptly, retains deliverable ones, and reads the spam and policy bounces as the reputation signals they are. A sender with inaccurate categorization mails dead addresses, loses good ones, and misses reputation warnings. The custom patterns are the mechanism that makes the categorization accurate, and through it, the suppression correct.
Testing custom patterns
Custom patterns should be tested before being relied on, because a pattern that is wrong, too broad, too narrow, mapping to the wrong category, makes the categorization worse rather than better.
Testing a custom pattern means confirming two things: that it matches the bounce text it is intended to match, and that it does not match bounce text it should not.
The testing approach:
- Match the intended text. Take real examples of the bounce response the pattern targets, from the accounting log, and confirm the pattern matches them and assigns the intended category.
- Check for over-matching. Consider whether the pattern could wrongly match other, unrelated bounce responses. A pattern keyed on a too-common phrase might catch bounces it should not.
- Observe in the accounting log. After adding the pattern, watch the accounting log to confirm that the targeted bounces now classify correctly and that nothing else has shifted category unexpectedly.
The accounting log is the testing instrument throughout: it is where the operator sees the actual categorization happening, finds the gaps, and confirms the fixes. A workflow of examining the log, writing a pattern, applying it, and re-examining the log to confirm the effect, is how custom patterns are developed and validated reliably.
Pattern changes should be made carefully and observed, because the categorization feeds suppression, and a bad pattern propagates into bad suppression decisions. Testing a pattern before trusting it, and watching its effect after, keeps a custom-pattern improvement from becoming a categorization regression.
When bounces are miscategorized
When bounces are being miscategorized, the diagnostic workflow:
Step 1: identify the miscategorization in the accounting log. Examine the bounce categories in the accounting log. Look for bounces landing in generic or unclassified categories, and for bounces in categories that seem wrong given their text.
Step 2: read the actual bounce text. For a miscategorized bounce, read the full diagnostic text and the SMTP code the receiver returned. This is the raw material the categorization should have matched correctly.
Step 3: determine the correct category. From the text and code, determine which category the bounce truly belongs in.
Step 4: check whether a pattern matched. Determine whether the bounce fell through to a generic category because no pattern matched, or whether a pattern matched but assigned the wrong category.
Step 5: for no match, write a pattern. If the bounce fell through, write a custom pattern matching its distinctive text and assigning the correct category.
Step 6: for a wrong match, fix the pattern. If an existing pattern matched but assigned the wrong category, the pattern is either too broad, catching this bounce when it should not, or mapped to the wrong category. Narrow it, or correct its category mapping, taking care not to break its correct matches.
Step 7: apply and verify. Apply the pattern change and watch the accounting log to confirm the bounce now classifies correctly.
Step 8: check the downstream effect. Confirm the corrected categorization produces the correct suppression. If the miscategorization had been causing wrong suppression, dead addresses kept active or good addresses wrongly suppressed, the affected addresses may need a corrective review.
An operator we worked with noticed their bounce rate to one major provider was stubbornly higher than it should be, and it was not improving even though they believed their suppression was working. Their list, they thought, was being kept clean: bounces drove suppression, dead addresses were removed, the bounce rate should have been trending down. Yet it stayed elevated. The investigation went to the accounting log and the bounce categorization. What they found was that a substantial fraction of the bounces from that provider were landing in a generic, catch-all category rather than the bad-mailbox category. Reading the actual bounce text, these were genuine non-existent-mailbox bounces, the provider was clearly saying the addresses did not exist, but the provider had at some point updated the specific wording of its non-existent-mailbox response, and the built-in bounce-category-patterns did not match the new phrasing. So these bounces, which should have been categorized as bad mailbox and should have driven suppression, were instead falling into a generic category that the operator's downstream suppression logic did not treat as a suppress-worthy bounce. The result was that for months, dead addresses at that provider had been bouncing on every campaign and never being suppressed, because the categorization never told the suppression logic they were dead. The sender had been mailing the same non-existent addresses over and over, which both wasted sends and kept the bounce rate elevated, and an elevated bounce rate to a provider is itself a reputation signal. The fix was a custom pattern: the operator examined the provider's current non-existent-mailbox bounce text, wrote a pattern matching its distinctive phrasing, mapped it to the bad-mailbox category, tested it against the real bounce examples, and applied it. From then on, those bounces categorized correctly and drove suppression, the accumulated dead addresses were suppressed, and the bounce rate came down. The lesson is the central one about the built-in patterns' limits: the providers change their bounce wording, the built-in patterns drift out of date, and bounces start falling into generic categories where they no longer drive the right action. Periodically reviewing the accounting log for bounces landing in generic categories, and writing custom patterns to classify them, is what keeps the categorization, and therefore the suppression, accurate as the receiving landscape evolves.
PowerMTA bounce categorization is the input to the decisions that protect a sender's list quality and reputation, above all the suppression decision. PowerMTA classifies bounces by matching the bounce response against the bounce-category-patterns file, and while the built-in patterns are a useful starting point, they cannot perfectly match every provider's specific bounce text or keep pace with the providers' changes. Custom patterns close the gap: by examining the accounting log for bounces landing in generic categories and writing patterns that match the actual ISP-specific bounce text, an operator makes the categorization accurate for their real receiving environment. Accurate categorization matters because it drives correct suppression, suppressing dead addresses, retaining deliverable ones, and reading spam and policy bounces as reputation signals rather than address problems. Custom patterns should be tested before being trusted and maintained as the receiving landscape evolves. Operators who supplement the built-in patterns with custom ISP-specific patterns, and review their categorization periodically, get bounce handling that reflects reality; operators who rely on the built-in patterns alone find, often months later, that miscategorized bounces have been quietly producing wrong suppression all along.