SaaS email template

Payment failed email template — recover revenue without custom dunning logic

Fire invoice.payment_failed with the attempt number and the update URL. else.events routes to the right dunning template — first notice, second notice or final warning.

Common mistakes with payment failed emails

Same template for every attempt

The first payment failure should be calm and helpful. The final notice should be urgent. One template for all attempts misses the escalation opportunity.

Generic "update your payment" link

A link to the billing portal homepage is less effective than a deep link that goes directly to the payment update form.

No mention of what happens next

Users want to know: when is the next retry, what happens if it fails again, when will their account be suspended. Answering these reduces support requests.

Hardcoded in the billing service

Dunning email logic buried in the billing handler means every copy change requires a deployment.

Attempt number in the payload — escalation in the rules

Include attempt_number in the event payload

Rules match on attempt_number to route attempt 1 to a calm first notice and attempt 3 to an urgent final warning.

Personalised update URL from payload

Generate the payment update link in your backend (with user session or token). Include it in the payload. The template renders a direct deep link.

Next retry and account status shown in the email

Include next_attempt_at and account_status in the payload. The template renders "Next retry on June 1" and "Your account remains active until June 7."

Managed outside your billing service

Edit dunning copy, change the urgency tone or add a locale without touching the billing service code.

Template variables for the payment failed email

  • {{ user.name }} Recipient name for personalised greeting
  • {{ data.amount }} Invoice amount with currency
  • {{ data.plan }} Plan tier — affects tone and CTA
  • {{ data.attempt_number }} Payment attempt count — used for escalation routing
  • {{ data.update_payment_url }} Personalised link to update payment method
  • {{ data.next_attempt_at }} Next retry date — shown in the email

Frequently asked questions

What subject lines work for payment failed emails?
"Action required: payment failed for your [App] account", "We could not process your payment — update your card", "Final notice: payment failed [Attempt 3 of 3]". Escalate urgency with attempt number.
How do I route different templates for different attempts?
Include attempt_number in the event payload. Create a rule in else.events matching attempt_number = 1, another for attempt_number = 2, another for attempt_number = 3. Each routes to a different template.
How do I create a personalised payment update link?
Generate the link in your backend — for Stripe, use the billing portal session URL. Include the full URL in the event payload as data.update_payment_url. The template renders it as the primary CTA.
What if the payment succeeds on retry?
Your backend should detect the successful payment and fire invoice.paid instead. else.events sends a receipt email. No dunning email fires for successful payments.

Dunning emails that escalate automatically

Attempt-based routing, personalised update URL, clear next-step messaging. No custom dunning service.

  • Attempt-based template routing via rules
  • Personalised update URL from payload
  • Edit copy without touching the billing service