High-impact SaaS email

Payment failed emails that recover revenue — without custom dunning logic

A failed payment event from your billing provider should trigger the right email automatically. No custom dunning service, no brittle retry logic, no hardcoded templates.

Why payment failed emails are harder than they look

Multiple dunning scenarios require multiple templates

First attempt, second attempt, final notice — each needs a different tone, CTA and urgency level.

Plan-specific messaging is brittle

A Free-tier user getting a payment failed email is unusual. A Pro-tier user needs a different CTA than an Enterprise customer.

Retry timing is its own problem

When to send the first reminder, when to follow up, when to warn about cancellation — this logic ends up in your application or a custom job.

Update link must be personalised

The "update payment method" URL must be per-user or per-session to be useful. Generic links hurt conversion.

Fire the event. else.events handles dunning routing.

Event fires on payment failure

Your billing provider (Stripe, Paddle, LemonSqueezy) fires a webhook. You forward it as an event to else.events.

Rules determine the right template

First attempt vs final notice, Pro vs Enterprise, English vs German — rules select the correct template automatically.

Personalised update URL from payload

Include the payment update URL in the event payload. The template renders it directly — no generic link.

Structured logs per payment event

Every invoice.payment_failed event and its resulting email delivery logged together. Useful for support and compliance.

// stripe webhook → else.events event

From Stripe webhook to dunning email in one step

{
  "type": "invoice.payment_failed",
  "user": { "email": "customer@example.com", "name": "Alex" },
  "data": {
    "plan": "Pro",
    "attempt_number": 1,
    "amount": "29.00",
    "currency": "EUR",
    "update_payment_url": "https://app.example.com/billing/update?token=abc123",
    "next_attempt_at": "2026-06-01T10:00:00Z"
  }
}

else.events matches the rule for plan = Pro and attempt_number = 1, renders the first-attempt dunning template and delivers it through your provider.

Template variables for payment failed emails

  • {{ user.name }} Recipient display name for personalisation
  • {{ data.amount }} Invoice amount with currency
  • {{ data.plan }} Plan tier — affects tone and CTA copy
  • {{ data.update_payment_url }} Personalised link to update payment method
  • {{ data.attempt_number }} Payment attempt count — used to escalate urgency
  • {{ data.next_attempt_at }} Next retry date, rendered in the email

Frequently asked questions

How do I connect Stripe webhooks to else.events?
Create a webhook handler in your backend that receives the Stripe invoice.payment_failed event and forwards it as an event POST to else.events. The payload maps Stripe fields to your event schema.
Can I send different emails for first vs second payment failure?
Yes. Include an attempt_number field in your event payload. Rules match on it to route to different templates with escalating urgency.
How do I personalise the payment update URL?
Generate the URL in your webhook handler and include it in the event payload data. The template renders it as {{ data.update_payment_url }}.
Does else.events handle retry scheduling?
No. Retry scheduling is handled by your billing provider (Stripe smart retry, etc.) or a custom job in your application. else.events handles the email for each payment failure event it receives.

Automate your payment failed emails today

Fire invoice.payment_failed. else.events routes the dunning email. No custom logic required.

  • Free during public beta
  • Works with Stripe, Paddle, LemonSqueezy
  • Attempt-based routing via rules