What is a Bounce Address?
A bounce address, also called the return path or envelope sender, is the email address that receives non-delivery reports (NDRs) when an email cannot be delivered. This address is separate from the "From" address visible to recipients and is used exclusively for automated delivery notifications.
How Bounce Addresses Work
Email transmission uses two sets of addresses:
Header From (visible to recipient):From: John Doe <john@example.com>
Envelope From (SMTP-level, used for bounces):
MAIL FROM: <bounces@example.com>
When delivery fails, the receiving server sends the bounce to the envelope sender, not the header From address.
SMTP Conversation Example
Client: MAIL FROM: <bounces@example.com>
Server: 250 OK
Client: RCPT TO: <invalid@recipient.com>
Server: 550 No such user here
Client: QUIT
# Later, server sends bounce to bounces@example.com
Types of Email Bounces
Hard Bounces
Permanent delivery failures:
- User doesn't exist: 550 No such user
- Domain doesn't exist: 550 Domain not found
- Rejected by policy: 550 Spam blocked
Soft Bounces
Temporary failures:
- Mailbox full: 452 Insufficient system storage
- Server temporarily unavailable: 421 Service not available
- Message too large: 552 Message size exceeds limit
Block Bounces
Deliverability issues:
- IP blacklisted: 554 Service unavailable; Sender IP blocked
- Content filtered as spam: 550 Spam score too high
- Rate limiting: 450 Too many emails
Bounce Address Configuration
Setting Return Path in Email Headers
PHP (mail function):$to = "recipient@example.com";
$subject = "Test Email";
$message = "Email body";
$headers = "From: sender@example.com\r\n";
$headers .= "Return-Path: bounces@example.com\r\n";
mail($to, $subject, $message, $headers, "-f bounces@example.com");
PHPMailer:
$mail = new PHPMailer();
$mail->From = "sender@example.com";
$mail->Sender = "bounces@example.com"; // Return path
$mail->addAddress("recipient@example.com");
$mail->Subject = "Test Email";
$mail->send();
Postfix (SMTP):
# /etc/postfix/main.cf
sender_canonical_maps = hash:/etc/postfix/sender_canonical
# /etc/postfix/sender_canonical
@example.com bounces@example.com
# Apply changes
postmap /etc/postfix/sender_canonical
systemctl reload postfix
Dedicated Bounce Handling Services
Most email service providers offer bounce management:
Amazon SES:{
"Message": {
"Subject": "Test",
"From": "sender@example.com",
"ReturnPath": "bounces@example.com"
}
}
SendGrid:
const msg = {
to: 'recipient@example.com',
from: 'sender@example.com',
replyTo: 'reply@example.com',
return_path: 'bounces@example.com',
subject: 'Test Email',
text: 'Email body'
};
Bounce Address Naming Conventions
Subdomain Approach
bounces@example.com # General bounces
no-reply@example.com # No-reply emails
returns@example.com # Returns/receipts
Campaign-Specific
Track bounces per campaign:
bounces-newsletter@example.com
bounces-campaign-123@example.com
bounces-transaction@example.com
Variable Envelope Return Path (VERP)
Encode recipient in bounce address:
Sending to: user@recipient.com
Return path: bounces+user=recipient.com@example.com
When bounce arrives at bounces+*, parse to identify failed recipient
Processing Bounce Messages
Automated Bounce Parsing
Python Example:import email
from email import policy
def parse_bounce(raw_email):
msg = email.message_from_string(raw_email, policy=policy.default)
# Extract bounce type
if "550" in msg.get_payload():
return "hard_bounce"
elif "452" in msg.get_payload():
return "soft_bounce"
# Extract failed recipient
for part in msg.walk():
if part.get_content_type() == "message/delivery-status":
# Parse delivery status
pass
return bounce_info
# Integrate with mailing list to remove hard bounces
Webhook-Based Bounce Handling
Modern ESPs provide webhooks:
SendGrid Webhook:POST /bounce-webhook
{
"email": "recipient@example.com",
"event": "bounce",
"reason": "550 5.1.1 User unknown",
"type": "blocked",
"status": "5.0.0"
}
Action: Update database to mark email as bounced.
SPF and Bounce Addresses
SPF checks the envelope sender (bounce address), not the From header:
Message:
From: newsletter@example.com (header)
Return-Path: bounces@mail-server.com (envelope)
SPF Check:
Queries: mail-server.com TXT record (not example.com)
Must include sending IP in mail-server.com's SPF
Bounce Domain SPF Configuration
bounces.example.com. IN TXT "v=spf1 include:_spf.sendgrid.net ~all"
Ensure your bounce subdomain has appropriate SPF records for your sending infrastructure.
Bounce Address Best Practices
Use a Dedicated Bounce Address
Never use your primary email for bounces:
# Bad
Return-Path: info@example.com
# Good
Return-Path: bounces@example.com
Monitor Bounce Rates
| Bounce Rate | Assessment | Action |
|---|---|---|
| < 2% | Healthy | Continue monitoring |
| 2-5% | Concerning | Audit email list quality |
| 5-10% | Poor | Immediate list cleaning needed |
| > 10% | Critical | Deliverability at risk |
Implement Bounce Processing
Automate removal of hard bounces:
-- Mark emails with hard bounces
UPDATE mailing_list
SET status = 'bounced', bounce_count = bounce_count + 1
WHERE email IN (SELECT email FROM recent_hard_bounces);
-- Remove after 3 hard bounces
DELETE FROM mailing_list
WHERE bounce_count >= 3;
Separate Transactional and Marketing Bounces
transactional-bounces@example.com # Order confirmations, receipts
marketing-bounces@example.com # Newsletters, campaigns
Different bounce rates are expected for each type.
Set Up Bounce Processing Automation
Cron Job Example:#!/bin/bash
# Process bounces every hour
# Fetch bounces from IMAP
fetchmail -c /etc/fetchmailrc
# Parse and update database
/usr/local/bin/process-bounces.py
# Clean up processed bounces older than 30 days
find /var/mail/bounces -mtime +30 -delete
Backscatter and Bounce Security
Backscatter Problem
When your server accepts spam and then bounces it, you're sending to forged addresses:
1. Spammer sends email with forged From
2. Your server accepts it
3. Your server realizes it's spam/invalid
4. Your server bounces to forged From address
5. Innocent party receives bounce (backscatter)
Solution: Reject at SMTP time, don't accept then bounce:
# Postfix: Reject unknown users at SMTP time
smtpd_recipient_restrictions = reject_unauth_destination
local_recipient_maps = hash:/etc/postfix/local_recipients
Bounce Forgery
Attackers can forge bounce messages to:
- Harvest valid addresses
- Deliver spam disguised as bounces
- Phish credentials via fake delivery reports
- Check bounce originated from MX server
- Verify bounce is for email you actually sent
- Parse delivery-status headers carefully
Common Bounce Scenarios
Scenario 1: All Emails Bouncing
Cause: SPF failure, IP blacklist, or server reputation Check: SPF records, sender IP reputation, DMARC reportsScenario 2: Bounces Not Being Received
Cause: Bounce address misconfigured or doesn't exist Check: MX records for bounce domain, mailbox existsScenario 3: High Soft Bounce Rate
Cause: Recipient servers overloaded, rate limiting, large messages Check: Sending rate, message size, recipient server errorsScenario 4: Bounce Loops
Cause: Bounce address triggers auto-reply, which triggers another bounce Check: Disable auto-responders on bounce addressesTesting Bounce Handling
Send test email with invalid recipient:# Test bounce to invalid address
swaks --to invalid-user@test-domain.com \
--from bounces@example.com \
--server mx.test-domain.com
# Check if bounce arrives at bounces@example.com
Verify SPF for bounce domain:
dig bounces.example.com TXT
# Should show SPF record with authorized senders
Proper bounce address management is critical for maintaining sender reputation, list hygiene, and deliverability.