An email bounce occurs when a message you send cannot be delivered to the recipient's mailbox and is returned to the sender with a failure notification. While a single bounce might seem insignificant, a high bounce rate erodes your sender reputation over time, causing more and more of your legitimate email to be filtered to spam or rejected outright. This guide explains the critical difference between Hard Bounces and Soft Bounces, how to read SMTP error codes, analyze mail server logs, and implement fixes that genuinely reduce your bounce rate.

How Email Delivery Works and Why Bounces Occur

When you send an email, your Mail Transfer Agent (MTA) opens an SMTP connection to the destination mail server. The receiving server then responds with a status code that indicates whether it accepts the message, is temporarily unavailable, or permanently rejects delivery. If the server cannot accept the message, it generates a Non-Delivery Report (NDR) — also called a Bounce Message — and returns it to the sender.

A bounce message contains three critical pieces of information: the SMTP status code, the Enhanced Status Code (ESC) providing additional context, and a human-readable diagnostic string. Understanding how to parse this information is the starting point for fixing delivery problems effectively.

What Is a Hard Bounce?

A Hard Bounce is a permanent delivery failure. The receiving server responds with a 5xx SMTP code indicating that no amount of retrying will result in successful delivery. The sending MTA records the failure and stops attempting retransmission immediately.

The most common causes of Hard Bounces include:

Hard Bounces are serious because each one is a direct signal to receiving infrastructure that your list hygiene is poor. Google, Microsoft, and Yahoo use bounce rates as a key factor in their filtering decisions — senders with consistently high hard bounce rates see their mail routed to spam or blocked entirely.

What Is a Soft Bounce?

A Soft Bounce is a temporary delivery failure. The receiving server responds with a 4xx SMTP code indicating that it cannot accept the message right now but may be able to do so later. The sending MTA queues the message and retries delivery on a schedule — typically every 15-30 minutes with increasing intervals — for a period of 24 to 72 hours before giving up and generating a bounce notification.

Common causes of Soft Bounces include:

While individual soft bounces are a normal part of email delivery, a Soft Bounce that repeats multiple times against the same address is a warning sign. Many email platforms automatically convert a repeated Soft Bounce into a Hard Bounce to prevent indefinite retry loops.

Hard Bounce vs Soft Bounce: SMTP Code Reference

Type SMTP Code Enhanced Code Meaning Action
Hard 550 5.1.1 User Unknown / mailbox does not exist Remove from list immediately
Hard 551 5.1.6 User not local; forwarding not permitted Remove from list
Hard 554 5.7.1 Rejected — spam or policy violation Check Blacklist + SPF/DKIM/DMARC
Soft 421 4.3.2 Service unavailable / rate limit Let MTA retry automatically
Soft 452 4.2.2 Mailbox full / over quota MTA retry; notify recipient if persistent
Soft 452 4.3.1 Insufficient system storage MTA retry automatically

Reading and Analyzing Bounce Logs

Effective bounce management starts with reading the MTA log directly. The two most common MTAs in Linux hosting environments are Postfix and Exim. Both record detailed bounce information that tells you exactly why delivery failed — not just that it failed.

Analyzing Postfix Logs

Postfix logs are typically found at /var/log/maillog or /var/log/mail.log. Lines containing bounce events are marked with status=bounced.

# View all bounce events in Postfix log
grep "status=bounced" /var/log/maillog | tail -50

# Example output:
# Jun 9 10:23:11 mailserver postfix/smtp[1234]: ABC123: to=<[email protected]>,
#   relay=mail.example.com[93.184.216.34]:25,
#   status=bounced (host mail.example.com said:
#   550 5.1.1 The email account does not exist)

# Count bounces grouped by destination domain
grep "status=bounced" /var/log/maillog \
  | grep -oP 'to=<[^@]+@\K[^>]+' \
  | sort | uniq -c | sort -rn | head -20

Analyzing Exim Logs

Exim is used by DirectAdmin and many shared hosting environments. The main log is at /var/log/exim_mainlog. Bounce events are marked with **.

# View bounce events in Exim log
grep " \*\* " /var/log/exim_mainlog | tail -50

# Example output:
# 2026-06-09 10:25:00 1lOXxx-0000YY-00 ** [email protected]
#   R=dnslookup T=remote_smtp: SMTP error after RCPT TO:
#   550 5.1.1 User unknown

# Count today's bounces
grep "$(date '+%Y-%m-%d')" /var/log/exim_mainlog | grep " \*\* " | wc -l

Fixing Hard Bounces Systematically

Hard bounces require immediate and systematic action. The steps below address the root causes rather than just the symptoms.

Step 1 — Remove Bounced Addresses From Your List

Any email address that generates a Hard Bounce must be removed from your mailing list immediately and never retried. Continued sending to known-invalid addresses is one of the clearest spam signals that filtering systems use. The following Python script extracts unique hard-bounced addresses from a Postfix log:

import re

bounced_emails = set()
with open('/var/log/maillog') as f:
    for line in f:
        if 'status=bounced' in line:
            match = re.search(r'to=<([^>]+)>', line)
            if match:
                bounced_emails.add(match.group(1).lower())

with open('hard_bounce_list.txt', 'w') as out:
    for email in sorted(bounced_emails):
        out.write(email + '\n')

print(f"Found {len(bounced_emails)} hard-bounced addresses")

Step 2 — Verify and Fix Your DNS Authentication Records

A significant proportion of Hard Bounces, especially those with 554 5.7.1 or 550 5.7.26 codes, result from SPF, DKIM, or DMARC misconfigurations. The receiving server rejects email because it cannot verify that it genuinely originates from your domain.

# Check SPF record
dig TXT yourdomain.com | grep "v=spf1"

# Check DKIM public key
dig TXT selector1._domainkey.yourdomain.com

# Check DMARC policy
dig TXT _dmarc.yourdomain.com

# A correct SPF record looks like:
# "v=spf1 mx a ip4:your.server.ip include:mail.provider.com ~all"

# A correct DKIM record looks like:
# "v=DKIM1; k=rsa; p=MIGfMA0GCSq..."

# A monitoring DMARC record (start here):
# "v=DMARC1; p=none; rua=mailto:[email protected]"

Step 3 — Check and Resolve Blacklist Listings

If Hard Bounces are occurring across multiple destination domains with policy rejection codes, your sending IP or domain may be blacklisted. Use the following method to check against Spamhaus — the most widely used blacklist:

# Check an IP against Spamhaus ZEN (reverse the octets first)
# Example: checking 93.184.216.34 → query 34.216.184.93.zen.spamhaus.org
dig 34.216.184.93.zen.spamhaus.org A

# If the query returns 127.0.0.x = LISTED (blocked)
# If the query returns NXDOMAIN = NOT LISTED (clean)

# Check multiple lists at once using MXToolbox (manual):
# https://mxtoolbox.com/blacklists.aspx

# After delisting:
# 1. Fix the root cause (spam complaints, compromised account)
# 2. Submit delisting request to each list
# 3. Monitor for re-listing over the next 30 days

Reducing Soft Bounces and Unnecessary Retries

Most Soft Bounces resolve automatically through the MTA's retry mechanism. However, when specific Soft Bounce types recur persistently, proactive intervention is more efficient than waiting.

Handling Repeated Mailbox Full Bounces (452)

If a key contact's mailbox repeatedly appears full, contact them through an alternative channel (phone, instant messaging) to let them know. For users on your own server, you can increase their quota through DirectAdmin or the command line:

# Increase mailbox quota via DirectAdmin API
curl -k "https://your-server:2222/CMD_API_EMAIL_QUOTA" \
  -u admin:password \
  -d "domain=yourdomain.com&user=username"a=1024"
  # quota value is in MB

Configuring Postfix Send Rate Limits to Avoid 421 Errors

When sending bulk email, per-domain rate limits prevent you from triggering 421 throttling responses from large providers. Configure these in Postfix:

# /etc/postfix/main.cf — rate limiting configuration
smtp_destination_rate_delay = 1s          # 1 second delay between messages
smtp_extra_recipient_limit = 10           # max 10 recipients per connection
default_destination_concurrency_limit = 2  # max 2 simultaneous connections per domain
smtp_destination_recipient_limit = 50     # max 50 recipients per destination

# Apply changes
postfix reload

Pro Tip: Before sending any large email campaign, run an Email List Verification pass to remove invalid addresses before they become bounces. Combine this with Double Opt-In for all new signups. Your target before sending should be a predicted Hard Bounce Rate below 2% and a Soft Bounce Rate below 5%.

Protecting Sender Reputation with SPF, DKIM, and DMARC

Properly configured email authentication is the single most effective way to prevent Policy Rejection bounces. Starting in 2024, Google and Yahoo made SPF, DKIM, and DMARC mandatory for bulk senders. Even for transactional email, these three records are essential.

SPF — Define Authorized Senders

# Complete SPF record example
yourdomain.com. IN TXT "v=spf1 mx a ip4:192.0.2.1 include:sendgrid.net ~all"

# Explanation:
# mx         = servers listed in MX records are authorized
# a          = A record of the domain is authorized
# ip4:x.x.x  = explicit IP authorization
# include:   = inherit authorization from another domain's SPF
# ~all       = softfail (mark but don't reject) — recommended during migration
# -all       = hardfail (reject immediately) — recommended for stable setups

DKIM — Cryptographic Signing

# Generate DKIM key pair (OpenSSL)
openssl genrsa -out dkim_private.pem 2048
openssl rsa -in dkim_private.pem -pubout -out dkim_public.pem

# The public key goes into DNS as a TXT record:
# selector1._domainkey.yourdomain.com TXT "v=DKIM1; k=rsa; p=<BASE64_PUBLIC_KEY>"

# Verify DKIM signing is working by checking email headers:
# Look for: DKIM-Signature: v=1; a=rsa-sha256; d=yourdomain.com; s=selector1
# And verify result: Authentication-Results: dkim=pass

DMARC — Policy and Reporting

# Start with p=none (monitoring mode)
_dmarc.yourdomain.com. IN TXT "v=DMARC1; p=none; rua=mailto:[email protected]"

# After reviewing aggregate reports for 2-4 weeks, move to quarantine:
"v=DMARC1; p=quarantine; pct=25; rua=mailto:[email protected]"

# Gradually increase pct until reaching reject:
"v=DMARC1; p=reject; rua=mailto:[email protected]; ruf=mailto:[email protected]"

Ongoing Bounce Rate Monitoring

Reducing your bounce rate is not a one-time fix — it requires continuous monitoring. The following tools and practices keep your bounce rate under control long-term:

#!/bin/bash
# /usr/local/bin/check_bounce_rate.sh
DATE=$(date '+%Y-%m-%d' -d "yesterday")
TOTAL=$(grep "$DATE" /var/log/maillog | grep "status=" | wc -l)
BOUNCED=$(grep "$DATE" /var/log/maillog | grep "status=bounced" | wc -l)

if [ "$TOTAL" -gt 0 ]; then
  RATE=$(echo "scale=2; $BOUNCED * 100 / $TOTAL" | bc)
  echo "Date: $DATE | Sent: $TOTAL | Bounced: $BOUNCED | Rate: ${RATE}%"
  if (( $(echo "$RATE > 5" | bc -l) )); then
    echo "ALERT: Bounce Rate exceeded 5% — immediate investigation required"
  fi
fi

# Add to crontab to run at 08:00 daily:
# 0 8 * * * /usr/local/bin/check_bounce_rate.sh | mail -s "Daily Bounce Report" [email protected]

Frequently Asked Questions

What is the difference between a Hard Bounce and a Soft Bounce?

A Hard Bounce is a permanent delivery failure where the receiving server responds with an SMTP 5xx code, indicating the email can never be delivered. Common causes include non-existent addresses, invalid domains, and permanent policy blocks. These must be removed from your list immediately. A Soft Bounce is a temporary failure (SMTP 4xx), where the MTA queues the message and retries delivery for 24-72 hours. Common causes include full mailboxes, server downtime, and rate limiting.

What bounce rate is acceptable and when should I be concerned?

A Hard Bounce Rate below 2% is generally acceptable. Once you exceed 2%, your sender reputation begins to suffer. If your Hard Bounce Rate exceeds 5%, you risk IP or domain Blacklisting, which causes widespread delivery failures. You should clean your email list every 3-6 months and implement Double Opt-In to prevent accumulation of invalid addresses over time.

How do I read SMTP bounce error codes in mail logs?

SMTP codes fall into two groups: 4xx for temporary failures (Soft Bounce) and 5xx for permanent failures (Hard Bounce). Common examples: 421 = service temporarily unavailable or rate limiting, 452 = mailbox full or insufficient storage, 550 = mailbox does not exist or policy rejection, 554 = rejected as spam or violating policy. The enhanced status code provides more specificity — for example, 550 5.1.1 means User Unknown specifically.

How do I fix a high bounce rate caused by a Blacklist listing?

First check whether your IP or domain is blacklisted using MXToolbox or MultiRBL. If listed, investigate the root cause — spam complaints, a compromised account sending spam, or botnet activity — and resolve it first. Then submit a Delisting Request to each blacklist you appear on, explaining the corrective actions taken. Simultaneously, verify your SPF/DKIM/DMARC records are correctly configured, clean your email list of invalid addresses, and implement Double Opt-In to prevent future accumulation of bad addresses.

Business Email Hosting at Your Own Domain

AsiaGB Email comes with SPF, DKIM, and DMARC pre-configured for high deliverability. Starting from 200 THB/year.

View Email Plans