Every email-marketing operator has a sense that bounces are bad. The deeper truth is that bounces are diagnostic — different bounce types carry different signals. A spike in hard bounces means one thing (list hygiene); a spike in soft bounces means a very different thing (sender reputation event). Reacting wrongly to a bounce surge — pruning the list when the problem is reputation, or warming the IP when the problem is data quality — burns budget and time.
This article walks the bounce taxonomy Senddera uses (hard, soft, unknown — see app/Model/BounceLog.php), what each means at the SMTP level, what Senddera does automatically with each, and the patterns that should prompt operator action.
The three Senddera bounce categories
Senddera's BounceLog model defines three constants:
public const HARD = 'hard';
public const SOFT = 'soft';
public const UNKNOWN = 'unknown';
A BounceLog row is created via recordHardBounce() or recordSoftBounce() (or record() with an explicit type) when the bounce-handler IMAP poller encounters a non-deliverable status notification, or when the synchronous SMTP exchange returns a permanent failure. The row carries:
tracking_log_id— points at the original sendcustomer_id— for multi-tenant isolationbounce_type— one of the three constants aboveruntime_message_id— the Message-ID the receiver sawraw— the full DSN body (preserved verbatim — read it when in doubt)
Hard bounces — permanent failures
Hard bounces are the SMTP equivalent of "this address will never accept mail." Senddera marks them by:
- 5xx responses during the SMTP transaction — the receiver synchronously rejects with
550,551,552,553,554etc. - Async DSNs with
5.x.xin the status field — RFC 3463 enhanced codes returned by the receiving MTA via bounce email.
The semantics across the 5xx range:
| SMTP code | DSN code | Meaning | Action |
|---|---|---|---|
| 550 | 5.1.1 | User unknown | Suppress permanently |
| 550 | 5.1.10 | Recipient address rejected (user not found in directory) | Suppress permanently |
| 550 | 5.7.1 | Sender denied (policy block) | Reputation issue — investigate |
| 550 | 5.4.6 | Routing loop / too many hops | Misconfigured MX — check recipient's setup |
| 552 | 5.2.2 | Mailbox over quota | Soft in spirit, hard if persistent — see edge cases |
| 553 | 5.7.1 | Mailbox not allowed | Domain block — investigate |
| 554 | 5.7.1 | Refused | Reputation block at edge filter |
The crucial distinction: 5.1.1 (user unknown) is a list-hygiene issue. 5.7.1 (policy denied) is a reputation issue. Senddera records both as bounce_type = hard, but the corrective action is different. Always read the raw field of the bounce log when investigating sustained hard-bounce rates above 2 %.
Senddera's auto-suppression: hard bounces are added to the customer's bounce_list (a per-tenant suppression table). Future campaigns from that customer skip suppressed addresses automatically. You can't undo a suppression by re-importing the address — you must explicitly remove it from the suppression list.
Soft bounces — transient failures
Soft bounces are deferrals: "I can't accept this right now, try later." Common SMTP causes:
- 4xx responses during the SMTP transaction (
421 service not available,450 mailbox unavailable,451 local error). - Async DSNs with
4.x.xstatus fields — the receiving MTA queued and then deferred.
Senddera's worker queues a retry on a 4xx (Laravel queue retry semantics; configured in the queue connection). Retry interval grows with attempt count: 5 min → 15 min → 1 hour → 6 hours.
Common soft-bounce diagnostics:
| Code | Meaning | Action |
|---|---|---|
| 421 | Service not available; throttling | Reduce send rate — likely reputation event |
| 421 RP-002 | Microsoft "rate-protected" defer | YELLOW SNDS — pause Outlook sending |
| 421 4.7.0 [TSS04] | Yahoo reputation defer | Pause Yahoo sending; reduce volume |
| 450 4.2.1 | Mailbox temporarily disabled | Re-attempt — auto-resolves |
| 451 4.4.2 | Local error in processing | Receiver-side problem — usually transient |
| 452 4.2.2 | Mailbox over quota | Sometimes promotes to hard if persistent |
The soft-bounce trap is that a sender reputation event manifests as soft bounces from many recipients simultaneously. If you have a sudden surge of 421 codes, it's almost never a transient receiver-side problem — it's your IP getting throttled. The symptom looks like "deferrals," but the underlying cause is reputation. Pruning the list won't help; pausing volume + investigating reputation will.
Unknown bounces — the FBL bucket
bounce_type = unknown is what Senddera uses for Feedback Loop (FBL) abuse reports — when a recipient clicks "Report Spam," their ISP sends a feedback message in Abuse Reporting Format (ARF), and Senddera's FeedbackLoopHandler ingests it. The constants:
public const FEEDBACK_TYPES = ['abuse', 'fraud', 'virus', 'other', 'not-spam'];
public const EXCLUDED_FEEDBACK_TYPES = ['not-spam'];
The not-spam type is excluded — that's a "not spam" override from the recipient and isn't a complaint at all. Everything else gets logged as a complaint and adds to the customer's complaint rate.
FBL handling differs from hard/soft bounces:
- Auto-action: the recipient is added to the customer's
complaint_list(separate frombounce_list). - Threshold: Gmail tolerates ≤ 0.10 % complaint rate; Outlook ≤ 0.40 %. Above either, ISP-level reputation drops.
- Reading the source: the
rawfield contains the original ARF report —Feedback-Type: abuse,Original-Mail-From:, etc. Useful for verifying the FBL is correctly configured.
What patterns mean what
Once you have a few weeks of bounce log data, the patterns tell you the story. Three distinct shapes:
Pattern A — list hygiene problem
- Symptom: sustained hard bounce rate 3-8 %, mostly
5.1.1 user unknown. - Cause: list contains old addresses, typos, role addresses, single-opt-in junk.
- Action: re-engagement campaign + prune zero-engagement subscribers. Don't pause sending.
Pattern B — reputation event
- Symptom: surge of soft bounces (
421,4.7.0,4.7.1) across many recipients in a short window. - Cause: ISP throttling or grey-listing your IP.
- Action: pause new volume immediately; send only to engaged segment for 7 days; investigate Postmaster Tools / SNDS.
Pattern C — content / FBL spike
- Symptom: complaint rate jumps to 0.5-2 % on a specific campaign.
- Cause: subject line, content, or unsubscribe-link change is triggering reports.
- Action: review the campaign, audit the unsub link, audit the engagement segment.
The pattern matters more than the absolute rate. A 2 % bounce rate with the Pattern A shape is fixable; a 0.5 % rate with the Pattern C shape is more dangerous.
Senddera-specific operations
Two daily checks:
# 1. Bounce-rate-by-cause for the last 24h:
cd /var/www/Senddera
php artisan tinker --execute='
$rows = \App\Model\BounceLog::where("created_at", ">=", now()->subHours(24))
->selectRaw("bounce_type, count(*) as n")
->groupBy("bounce_type")
->get();
foreach ($rows as $r) echo "$r->bounce_type: $r->n\n";
'
# 2. Top-10 5xx codes over the last 24h:
mysql -e "
SELECT SUBSTRING_INDEX(raw, ' ', 2) as code, COUNT(*) c
FROM bounce_logs
WHERE created_at > NOW() - INTERVAL 24 HOUR AND bounce_type = 'hard'
GROUP BY code ORDER BY c DESC LIMIT 10;
" Senddera
Anything outside of 5.1.1 user unknown and a small 5.0.0 / 5.7.1 baseline warrants a closer look.
Related reading
- IP Warmup Schedule for New Sending Servers
- Setting up Feedback Loops (FBL) — for the FBL → unknown-bounce ingestion
- Email List Hygiene — for the Pattern A fix
- Sender Reputation Monitoring Stack — for the Pattern B fix
- Deliverability Incident Runbook — when patterns escalate
FAQ
Should I retry hard bounces?
No. Senddera suppresses hard-bounced addresses; re-sending forces another bounce, which doubles the reputation damage with no upside.
When does a soft bounce get promoted to hard?
After the configured retry budget is exhausted (default 4 retries over ~7 hours). The original soft bounce row stays as soft; a new row is logged as hard if the final retry returns 4xx-then-5xx or all retries 4xx.
What about transient 4.7.0 codes from Gmail specifically?
Gmail's 4.7.0 is "may have something to do with your reputation." It's a soft bounce by category but a reputation signal by content. Treat it like Pattern B (reputation event) regardless of frequency.
Can I bulk-delete bounce records to "reset" a list?
You can delete BounceLog rows but the suppression-list entries (bounce_list, complaint_list) are separate tables that survive bounce-log cleanup. Don't bulk-delete suppressions — re-introducing previously-bounced addresses is the fastest way to tank reputation.