High email bounce rate
Verification / recovery emails are bouncing
You're seeing > 5% of emails bounce. This is a deliverability problem.
Categorize bounces
Hard bounces
Email address doesn't exist or domain doesn't resolve. Permanent. Causes:
- Typo at signup (
@gmial.com). - User left company (still using old corporate email).
- Throwaway / disposable address service shut down.
Soft bounces
Temporary failures: inbox full, server unavailable, etc. Usually resolve themselves.
Spam-flagged
Your email landed in spam (technically delivered, but bounced from view). Different metric: open rate.
Diagnose
Pull bounce events from your ESP:
-- Postmark / SendGrid / Mailgun typically have a bounce webhook
SELECT
bounce_type,
COUNT(*) as count,
array_agg(DISTINCT email_domain) as domains
FROM email_events
WHERE event_type = 'bounce'
AND created_at > NOW() - INTERVAL '7 days'
GROUP BY bounce_type
ORDER BY count DESC;Top domains tell you a lot:
- All
@yopmail.com,@mailinator.com, etc. → users registering with disposable. Maybe block. - Single corporate domain → DNS or DKIM issue on that domain.
- Mixed → general deliverability problem.
Fix: Sender reputation
SPF, DKIM, DMARC
These DNS records prove you're authorized to send from your domain. Without them, mail servers reject or spam-folder you.
Check:
dig TXT your-domain.com | grep -i "spf\|dmarc"
dig TXT default._domainkey.your-domain.com # if DKIM selector is "default"Should see:
v=spf1 include:_spf.your-esp.com -allv=DKIM1; k=rsa; p=...v=DMARC1; p=quarantine; rua=mailto:dmarc@your-domain.com
If any missing, your ESP's docs explain how to add. Wait 24h for DNS propagation.
From address
Use a real address on YOUR domain, NOT a free-mail (e.g., noreply@your-domain.com not your-app@gmail.com). Free-mail "from" addresses go straight to spam.
Reverse DNS
host <your-sending-IP>Should resolve to a name in your domain. ESPs handle this for you, if you self-host SMTP, configure rDNS.
Fix: Content
Avoid:
- ALL CAPS subjects
- Excessive emoji
[URGENT]or similar- Lots of links
- Image-heavy emails with little text
Add a plain-text alternative to every HTML email.
Fix: Bounce list
Stop sending to addresses that bounced. ESPs usually do this automatically (suppression list). If you're rolling your own:
-- Mark bounced
UPDATE identities
SET email_status = 'bounced'
WHERE traits->>'email' IN (
SELECT email FROM email_events WHERE bounce_type = 'hard'
);
-- In Kratos courier, before sending, check this:
-- (via pre-courier webhook, or filter at send time)Fix: Engagement
Mailbox providers (Gmail, Outlook) downgrade senders whose recipients don't open. Audit:
- Are you sending too many emails? (Notification preferences, frequency caps)
- Are your subject lines clear?
- Are recipients engaging with the link?
Low engagement → reputation drops → bouncing increases over time.
Verification-time email check
To reduce typo-driven bounces, validate at registration:
import { validate as isEmail } from "email-validator";
if (!isEmail(traits.email)) {
return Response.json({ reject: true, error: "invalid_email" });
}For deeper check, use a real-time email-validation API (Kickbox, ZeroBounce, Hunter):
const result = await kickbox.verify(traits.email);
if (result.result === "undeliverable") {
return Response.json({ reject: true, error: "undeliverable_email" });
}Cost: USD 0.005/check. Worth it for paid signups; debatable for free tier.
Monitor
Dashboard for:
- Bounce rate (target: < 2%).
- Complaint rate (target: < 0.1%).
- Open rate of transactional (target: > 80%, these are expected emails).