Why Stripe's default payment failure emails underperform
Stripe does send a payment failure notification to customers — but it's plain-text, generic, and often lands in spam. Most SaaS businesses see open rates below 15% on these default emails.
The core problem: Stripe's default email doesn't tell the customer how to fix it. It notifies them of the failure but doesn't include a direct link to update their payment method. Customers have to log in, find their settings, and figure it out themselves — and most don't.
The templates below are designed to do three things that Stripe's defaults don't:
- Get opened (subject lines designed for high open rates)
- Make the fix obvious (one-click card update link via Stripe's customer portal)
- Escalate urgency appropriately (different tone for D+1 vs D+7)
The most important rule: stop when payment succeeds
If you send a "final warning" after the customer has already updated their card, you destroy trust. Your recovery sequence must listen to invoice.payment_succeeded and stop immediately. This is the hardest part of DIY implementations — and why most break in production.
Where to get the card update link
Every template below uses a [CARD_UPDATE_LINK] placeholder. This is a link to Stripe's Customer Portal, pre-loaded for the specific customer.
Generate it via the Stripe API:
This link is unique to each customer and expires. Generate it fresh for each email send — don't store it.
Template 1: Day 1 — First alert (send within 2 hours of failure)
Keep it short and helpful. Don't alarm the customer — most payment failures are simple card issues they can fix in 60 seconds.
Why it works: No blame, no urgency pressure. Just a friendly heads-up with one clear action. The "60 seconds" framing reduces perceived effort.
Template 2: Day 3 — Gentle reminder (if D+1 had no action)
Slightly more direct. Acknowledge this is the second note, but keep the tone supportive. Mention what's at stake.
Why it works: "Your account is still active for now" creates mild urgency without panic. The offer to help reduces friction for customers who might have a more complex issue.
Template 3: Day 7 — Final warning before access pause
Be specific and concrete. State exactly when access will be paused. This email has the highest conversion rate because the urgency is real — use it honestly.
Only send this if you'll actually pause access
If you threaten to pause and don't follow through, customers learn to ignore your warnings. This email converts well precisely because the consequence is real. If you're not ready to pause access, don't send a D+7 — modify your D+3 instead.
Template 4: Payment updated — confirmation email
Send this immediately when invoice.payment_succeeded fires after a failed payment sequence. This email stops churn anxiety and closes the loop.
Why it matters: Customers who received failure emails may feel anxious about their account status. This confirmation email restores confidence and reduces support tickets. Keep it short — don't over-thank.
Template 5: Card error-specific version (for expired_card)
If Stripe's webhook payload tells you why the payment failed, you can personalise the message. The card_error / expired_card decline code is the most common — here's a version optimised for it.
The Stripe webhook payload for a failed charge includes last_payment_error.decline_code and last_payment_error.code. Check for expired_card, insufficient_funds, and card_declined to personalise your messages.
How to wire these up in code
The technical implementation requires four pieces:
- Webhook endpoint — listen for
invoice.payment_failedandinvoice.payment_succeeded - Database tracking — store which customers are in recovery and at what stage
- Cron job — run hourly to check who needs a D+1, D+3, or D+7 email
- Stop condition — mark customer as recovered on
invoice.payment_succeeded, before the next email fires
The hardest part isn't the emails — it's the stop condition. A cron job that doesn't check the latest payment status before sending will email customers who already paid. This is the most common failure mode in DIY dunning implementations.
See our full technical guide: Stripe Failed Payment Recovery: The Complete Guide.
Skip the build entirely
RecoverKit handles the entire sequence — webhooks, timing, stop conditions, and personalisation — without writing code. Connect your Stripe account via OAuth (read-only access) and the D+1/D+3/D+7 sequence runs automatically. Free during beta.
Open rate benchmarks by subject line type
Based on aggregated data from transactional email providers sending payment failure messages:
- 35–45% open rate — "Your [Product] payment didn't go through" (clear, specific)
- 30–40% open rate — "Quick note about your [Product] payment" (low-pressure framing)
- 25–35% open rate — "Action required: update your payment method" (imperative, slightly alarming)
- <20% open rate — Generic: "Payment failure notification" (Stripe's default style)
The highest-performing D+7 subject lines reference a specific consequence: "Your [Product] account will be paused tomorrow" consistently outperforms "Final notice: update your payment." Specificity signals authenticity — customers know it's a real deadline, not a template.