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.
SaaS email template
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.
The first payment failure should be calm and helpful. The final notice should be urgent. One template for all attempts misses the escalation opportunity.
A link to the billing portal homepage is less effective than a deep link that goes directly to the payment update form.
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.
Dunning email logic buried in the billing handler means every copy change requires a deployment.
Rules match on attempt_number to route attempt 1 to a calm first notice and attempt 3 to an urgent final warning.
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.
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."
Edit dunning copy, change the urgency tone or add a locale without touching the billing service code.
{{ 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 Attempt-based routing, personalised update URL, clear next-step messaging. No custom dunning service.