PowerMTA's bounce classification system converts raw SMTP response codes and text into actionable categories that drive the correct downstream action for each delivery failure. Without correct classification, hard bounce responses suppress valid addresses (if policy rejections are classified as hard bounces), or permanent failures continue generating delivery attempts and reputation damage (if hard bounces are classified as soft bounces). The bounce classification pattern library is one of the highest-impact configuration decisions in a production PowerMTA deployment — and one of the most commonly mis-configured.

5.1.1
Most common hard bounce sub-code — mailbox does not exist
5.7.1
Policy rejection — do NOT suppress address, investigate config
6 types
Bounce classification categories: hard, soft, policy, domain, auth, greylist
Quarterly
Recommended audit frequency for bounce pattern library accuracy

Why Bounce Classification Matters for Deliverability

Every SMTP failure the MTA encounters falls into one of two fundamental categories: the address is the problem (invalid, deprovisioned, or non-existent — never send to it again), or something else is the problem (rate limiting, authentication failure, content rejection, blocklist — fix the something else and retry). Bounce classification is the operational mechanism that sorts every failure into the right category and triggers the correct response automatically.

The commercial cost of misclassification has two directions. False positives (classifying a valid address as a hard bounce) remove deliverable contacts from the active list permanently — a contact who would have continued engaging and converting is suppressed because their ISP returned a temporary policy rejection that the bounce classifier misread as a permanent address failure. False negatives (classifying a hard bounce as soft) continue injecting messages to invalid addresses that generate bounce signals damaging IP and domain reputation — each additional send to a hard-bouncing address accumulates a negative ISP reputation signal at zero commercial benefit.

Correct bounce classification eliminates both error types: every permanent address failure is suppressed immediately and never retried; every non-address failure is investigated and retried after the root cause is addressed. The pattern library is the tool that makes this classification accurate at scale, without requiring human review of each individual SMTP response.

PowerMTA Bounce Configuration Basics

PowerMTA's bounce classification is configured in the bounce-cat.php file (or equivalent bounce classification file, depending on the PowerMTA version and configuration approach). The classification file maps SMTP response code patterns and text patterns to bounce type categories. PowerMTA evaluates patterns in order — the first matching pattern determines the bounce type.

# bounce-cat.conf — PowerMTA bounce classification patterns
# Format: pattern [bounce_type] [description]

# Hard bounces — address does not exist
/User unknown/i                  hard  Address does not exist
/5\.1\.1/                        hard  Mailbox not found (RFC enhanced code)
/5\.1\.2/                        hard  Bad destination mailbox address
/5\.1\.3/                        hard  Bad destination mailbox address syntax
/5\.2\.1/                        hard  Mailbox disabled, not accepting messages
/Mailbox not found/i             hard  Mailbox does not exist
/No such user/i                  hard  User does not exist
/Invalid address/i               hard  Address invalid
/Address rejected/i              hard  Address rejected by recipient server

# Policy rejections — do NOT suppress address
/5\.7\.1/                        policy  Message rejected due to policy
/5\.7\.26/                       policy  DMARC failure
/5\.7\.350/                      policy  Microsoft policy rejection
/5\.7\.511/                      policy  Microsoft IP block
/blocked/i                       policy  IP or domain blocked
/spam/i                          policy  Spam classification rejection
/blacklisted/i                   policy  Blocklist rejection

# Domain errors — domain does not exist
/5\.1\.2/                        bad-domain  Domain does not exist
/Domain not found/i              bad-domain  No MX record for domain
/NXDOMAIN/i                      bad-domain  Domain DNS does not exist

# Greylisting — retry quickly
/451.*greylist/i                 greylist  Greylisted — retry in 5 minutes
/try again later/i               greylist  Temporary greylist

# Soft bounces — retry normally
/4\.\d\.\d/                      soft  Temporary failure
/421/                            soft  Service temporarily unavailable
/452/                            soft  Insufficient storage

# Catch-all soft (unknown temporaries)
/^4/                             soft  Unclassified temporary failure

# Catch-all hard (unknown permanents)  
/^5/                             hard  Unclassified permanent failure

Bounce Types: Hard, Soft, Policy, Domain, Authentication

Each bounce type drives a different downstream action. The action mapping must be consistent across all components that consume bounce data — the MTA's retry logic, the application's suppression database, and the analytics pipeline that calculates campaign metrics.

Bounce typeMeaningMTA actionList actionAnalytics
hardAddress permanently invalidStop all retries immediatelyAdd to permanent global suppressionCount as hard bounce rate
softTemporary failure — deliverableRetry with exponential backoffNo suppression unless persistent (5+ attempts)Count as deferral
policyPolicy rejection — address validHold for investigation, do not retry automaticallyDo NOT suppress address — fix config firstFlag for deliverability review
bad-domainDomain does not exist or has no MXStop all retries to this domainSuppress all addresses at the domainCount per domain, audit acquisition source
authenticationAuth failure (DMARC/SPF/DKIM)Hold for investigationDo NOT suppress — fix authenticationAlert deliverability team immediately
greylistGreylisting — retry quicklyRetry after 5–10 minutes (shorter than standard soft)No suppressionCount separately from standard soft bounces

The critical distinction that most classification systems get wrong: policy rejections (5.7.x codes) are not hard bounces. A 550 5.7.1 response means the ISP's policy rejected the message — the recipient address may be perfectly valid and deliverable once the policy issue is resolved (authentication fixed, IP delisted, content modified). Suppressing the recipient address in response to a 5.7.1 rejection removes a valid contact and hides the actual policy problem that needs to be fixed. Classify 5.7.x responses as "policy" and route them to an investigation queue, not to the suppression database.

Building the Bounce Pattern Library

The initial pattern library above covers the most common bounce scenarios. A production pattern library needs to be extended with the specific response text patterns observed from the ISPs the programme actually sends to. The pattern building process:

Step 1 — Mine the accounting log for common response texts. Query the accounting log database for the most frequent SMTP response texts over the past 90 days, grouped by response text and classified by response code. This produces a ranked list of the actual SMTP responses the programme's sending encounters most frequently.

-- Top 50 unclassified or uncertain SMTP response texts
SELECT dlvStatusMessage, COUNT(*) as freq,
       MIN(dlvRc) as min_code, MAX(dlvRc) as max_code
FROM delivery_events
WHERE dlvRc >= 400
GROUP BY dlvStatusMessage
ORDER BY freq DESC
LIMIT 50;

Step 2 — Classify each response text manually. For each of the top 50 response texts, determine the correct bounce classification based on the meaning of the response. Is this response saying the address does not exist (hard), the message was rejected for policy reasons (policy), the domain has no MX (bad-domain), or is it a temporary failure (soft)?

Step 3 — Add patterns for each newly classified response. For each response text classified in Step 2, add a regex pattern to the bounce classification file that will match this and similar responses. Test each new pattern against the accounting log data to verify it matches the intended responses and does not produce false positives.

Step 4 — Verify accuracy of the catch-all rules. The catch-all rules at the bottom of the pattern file (all 5xx → hard, all 4xx → soft) classify responses that no specific pattern matched. After adding patterns for the top 50 responses, check what percentage of bounce events are still being classified by the catch-all rules. If more than 5% of events are reaching the catch-all, there are significant response text patterns that need specific classification rules.

ISP-Specific Bounce Patterns

Major ISPs use characteristic response text patterns that appear consistently across their bounce responses. Building ISP-specific pattern rules improves classification accuracy for the ISPs that generate the highest bounce volumes.

Gmail:

/550 5\.1\.1 The email account that you tried to reach does not exist/  hard  Gmail invalid address
/550 5\.2\.1 The email account that you tried to reach is disabled/     hard  Gmail disabled account
/550 5\.7\.26.*DMARC policy/i                                           auth  Gmail DMARC rejection
/421 4\.7\.0.*Try again/i                                               soft  Gmail rate limit

Microsoft (Outlook.com / Microsoft 365):

/550 5\.1\.10 RESOLVER\.ADR\.RecipientNotFound/                         hard  Microsoft recipient not found
/550 5\.4\.1.*Recipient address rejected/i                              policy Microsoft tenant policy
/550 5\.7\.511.*.*Access denied.*HCT/                                   policy Microsoft IP block (SNDS)
/550 5\.7\.520.*Access denied.*sender is blocked/i                     policy Microsoft domain block
/421 4\.16\.55.*MG:B4/i                                                 soft  Microsoft rate limit

Yahoo:

/554 delivery error.*No such user/i                                     hard  Yahoo invalid user
/421 4\.7\.0.*Temporarily deferred.*TS01/i                              soft  Yahoo FBL enrollment required
/421 4\.7\.0.*Temporarily deferred.*TS02/i                              soft  Yahoo poor reputation throttle
/554 5\.7\.9.*Message not accepted.*TS03/i                              policy Yahoo auth/content rejection

GMX / Web.de (European):

/550 5\.1\.1 User unknown/i                                             hard  GMX unknown user
/452 4\.3\.1.*Insufficient system storage/i                             soft  GMX over-quota
/421 4\.3\.2.*Service temporarily not available/i                       soft  GMX rate limit

Automated Suppression Workflows

The bounce classification system is only useful if its output drives automated suppression with minimal latency. The target suppression latency: hard bounce suppression within 60 seconds of the bounce event; policy bounce investigation queue update within 5 minutes; soft bounce reclassification check every 72 hours.

The automated suppression pipeline in PowerMTA uses the pipe-to-script mechanism: PowerMTA writes accounting log records in real-time to a named pipe that is read by a processing script. The script classifies each event, looks up the bounce type, and calls the suppression API to add hard bounce addresses to the global suppression database:

# In PowerMTA config:
<acct-file |/usr/local/bin/bounce-processor.py>
  records d,b
  fields timeLogged,type,rcpt,dlvRc,dlvStatusMessage,dlvStatus,vmta
</acct-file>
#!/usr/bin/env python3
# bounce-processor.py — reads PowerMTA accounting records from stdin
import sys, json, requests, re

SUPPRESSION_API = 'https://app.brand.com/api/suppressions'
POLICY_QUEUE_API = 'https://app.brand.com/api/policy-queue'

HARD_PATTERNS = [re.compile(p, re.I) for p in [
    r'5\.1\.[123]', r'user unknown', r'mailbox not found', r'no such user'
]]
POLICY_PATTERNS = [re.compile(p, re.I) for p in [
    r'5\.7\.\d+', r'blocked', r'spam', r'blacklist', r'DMARC'
]]

for line in sys.stdin:
    fields = line.strip().split('|')
    if len(fields) < 7: continue
    _, rec_type, rcpt, smtp_code, smtp_text, status, vmta = fields[:7]
    
    if status == 'success' or rec_type not in ('d', 'b'):
        continue
    
    smtp_code = int(smtp_code) if smtp_code.isdigit() else 0
    
    # Classify
    if smtp_code >= 500:
        if any(p.search(smtp_text) for p in HARD_PATTERNS):
            requests.post(SUPPRESSION_API, json={'email': rcpt, 'reason': 'hard_bounce'})
        elif any(p.search(smtp_text) for p in POLICY_PATTERNS):
            requests.post(POLICY_QUEUE_API, json={'email': rcpt, 'smtp_code': smtp_code, 'smtp_text': smtp_text})

Quarterly Bounce Classification Audit

The bounce pattern library requires quarterly maintenance because ISP response text patterns change when ISPs update their mail systems. A pattern that correctly classified Gmail's "mailbox not found" response in 2024 may no longer match if Gmail updated its response text wording in 2025. The quarterly audit checks that the classification system remains accurate for all response texts the programme currently encounters.

The audit procedure: (1) Query the accounting log for the distribution of bounce events by bounce type classification (hard/soft/policy/bad-domain/auth/greylist) for the past 90 days. (2) Sample 20-30 records from each bounce type bucket and verify that the SMTP response text in the sample is correctly classified as that type — a "policy" bucket that contains response texts clearly indicating invalid addresses has a false positive problem. (3) Query for the most common response texts that are classified by the catch-all rule (not by a specific pattern) and add specific patterns for any that should be classified differently than the catch-all. (4) Update the bounce classification file with the new and corrected patterns. (5) Document the update with the date and the specific patterns changed.

The quarterly audit typically takes 60-90 minutes and produces 2-8 pattern additions or corrections per quarter. The patterns added during quarterly audits represent the drift between the initial pattern library and the evolving ISP landscape — they are the maintenance investment that keeps the classification system accurate as the sending programme's ISP mix and the ISPs' own response text patterns evolve over time.

Bounce Data in Operational Reporting

Classified bounce data in the operational reporting dashboard provides deliverability intelligence that unclassified aggregate bounce rates cannot. The per-classification metrics in the weekly report:

  • Hard bounce rate per campaign: Tracks address quality per list segment and acquisition source. Rising hard bounce rate in a specific segment identifies the source of list decay.
  • Policy rejection count per ISP: A spike in policy rejections from a specific ISP indicates an authentication or reputation event at that ISP that needs investigation — it does not indicate list quality problems.
  • Bad-domain bounce rate per acquisition cohort: B2B lists with high bad-domain rates have significant domain-level staleness from company closures, acquisitions, or domain changes.
  • Authentication bounce count (weekly): Any authentication bounce (DMARC or SPF rejection) should be zero or near-zero for a correctly configured programme. Any non-zero count warrants immediate investigation of the authentication stack for the source IP and domain generating the failures.

The classified bounce report converts what would be a single "bounce rate" number into a diagnostic instrument that tells the deliverability team specifically what is going wrong and where. A 1.2% bounce rate is a problem; a 1.2% bounce rate composed of 0.3% hard bounces (acceptable), 0.8% policy rejections from Microsoft (authentication incident at Microsoft needing investigation), and 0.1% bad-domain bounces (B2B list staleness in the most recently imported segment) is an actionable diagnosis. Build the classification system correctly, and every bounce rate becomes a precise delivery quality indicator rather than a vague performance signal.

H
Henrik Larsen

MTA Operations Manager at Cloud Server for Email. Specialising in email deliverability, infrastructure architecture, and high-volume sending operations.