Skip to main content
Subscription businesses lose customers to involuntary churn — expired cards, forgotten renewals, surprise charges that trigger refund requests. A tiered reminder sequence gives users time to update payment info, adjust their plan, or confirm they want to stay. Done well, it also becomes your highest-opened email of the month.
Before you start: you’ll need a subscriptions or customers table with a renewal_date or current_period_end column, and an email service configured. See Send Emails.

The Flow at a Glance

7 days out

Gentle heads-up

3 days out

Upgrade/downgrade options

1 day out

Last chance to change

Day of

Receipt or payment retry

Step 1: Create the Workflow

1

Open Workflows

In your project, go to Workflows > New Workflow. Name it Subscription Renewal Reminders.
2

Add a Schedule trigger

Click Add Trigger > Schedule. Set it to run daily at 8 AM UTC (or whatever matches your audience’s morning).
Pick a time when customers are likely to open email but before support staff clock in — gives them a chance to handle issues themselves first.

Step 2: Query Upcoming Renewals

Each tier uses a separate query so you can send different messaging. Here’s the 7-day query as a template:
SELECT id, user_email, plan_name, renewal_date, amount
FROM subscriptions
WHERE renewal_date BETWEEN now() + interval '6 days 23 hours'
                       AND now() + interval '7 days'
  AND renewal_reminder_7d_sent IS NULL
  AND status = 'active'
Add three more blocks with adjusted date intervals and sent-flag columns for the 3-day, 1-day, and day-of tiers.
Always check a renewal_reminder_*_sent flag in the query. Without it, a single user can get the same reminder multiple times if the workflow runs more than once a day or is re-enabled mid-window.

Step 3: Send Tiered Reminder Emails

Different days, different tone:
  • 7 days out: “Your plan renews next week” — casual, reassuring. Include the plan name and renewal amount. One soft CTA: “Manage your subscription.”
  • 3 days out: “Renewing in 3 days” — introduce upgrade/downgrade options. Highlight what they get on a higher tier.
  • 1 day out: “Your subscription renews tomorrow” — last chance to change anything. Include a link to update payment method prominently.
  • Day of: Either a “Thanks for renewing” receipt, or a “Renewal failed — update payment” notice depending on charge result.
1

Add a Send Email action per tier

After each query, add a Send Email action scoped to that query’s results.
2

Personalize per plan

Monthly customers get different messaging than annual. High-tier customers deserve a more personal touch. Use conditionals in your email template or split into multiple workflows.
3

Add a database update action

After each send, update the sent flag:
UPDATE subscriptions
SET renewal_reminder_7d_sent = now()
WHERE id = {{row.id}}

Step 4: Handle Failed Renewals

Failed payments are recoverable — most are card expirations, not intentional cancellations. Build a second workflow for this:
1

Create a new workflow

Name it Renewal Recovery.
2

Add a Stripe webhook trigger

Listen for invoice.payment_failed. See Webhook Patterns.
3

Send a recovery email

Subject: “Your payment didn’t go through.” Body: plain and calm. Explain what happened, link to update payment method, mention what happens if they don’t.
4

Schedule retry reminders

Add delays for day 2, day 3, and day 5. Each sends another reminder with increasing urgency. After the final retry, cancel the subscription (or pause it if your product supports that).
Renewal emails are some of the most-opened emails you’ll send. Use the opportunity to share what’s new since their last billing cycle, highlight features they haven’t tried, or tease an upcoming release. Don’t waste the attention.

Loyalty Incentives

Tenure is a retention lever. Pull it in your renewal emails:
  • “You’ve been with us 1 year — here’s 10% off next month”
  • “Celebrating 6 months — unlocked: priority support”
  • “Year 2 with Acme — we upgraded you to the new Pro features at no extra cost”
Calculate tenure from created_at in your subscription record and branch the email template based on thresholds.

Personalize by Plan

One-size-fits-all reminders get unsubscribes. Branch your messaging:
  • Monthly vs annual: annual customers need less hand-holding but bigger-deal framing (“your annual plan renews in 30 days”)
  • Free trial converting to paid: emphasize what they’ll lose if they cancel vs what they’ve already set up
  • High-tier: consider a personal email from a human, not a templated one
  • At-risk (low usage): combine renewal reminder with a “need help getting started?” offer

Verify It Worked

1

Create a test subscription

Insert a test row with renewal_date = now() + interval '7 days'.
2

Trigger the workflow manually

Go to Workflows > Runs > Run Now.
3

Confirm the email arrives

Check the test email inbox. Verify the subject, tone, and CTAs render correctly. Confirm the renewal_reminder_7d_sent flag was set.
4

Reset and test other tiers

Update the test row to now() + interval '3 days', clear the flag, run again.

Troubleshooting

Check the workflow is Enabled (toggle in top right). Then check the renewal_reminder_*_sent flag on the target row — if it’s already set, the query filters the row out. To re-test, clear the flag and re-run.
Date math is tricky. Make sure your BETWEEN ranges don’t overlap — the 7-day window should end exactly where the 3-day window begins. Also check your database timezone matches the workflow’s schedule timezone.
The 7-day email is the most commonly overlooked — spam folder, busy week, address change. Always send a day-of confirmation email too, even for successful renewals. That way they have at least one touchpoint they can search their inbox for.
If the email workflow runs but Stripe payments aren’t going through, the issue is at the payment layer, not the email layer. Decouple email sending from payment retry — each should succeed or fail independently. Check your Stripe API logs and webhook configuration.
Usually a sent-flag race condition. Make sure the flag update happens before the next workflow tick — or use a uniqueness constraint like UNIQUE(subscription_id, reminder_tier, date) on a reminders log table.

What’s Next?

Add Stripe

Wire up subscriptions and payment processing

Webhook Patterns

Handle Stripe and other third-party webhooks reliably