Skip to content
Groundmail

Free email template

Subscription renewal email template

An upcoming-renewal reminder with the amount, date and card, sent before the charge. Free and MIT-licensed, in React Email, MJML, HTML and plain text, with light and dark mode built in.

  • MIT license
  • Works with any email provider
  • Light and dark mode

What every subscription renewal email needs.

This template does all six on the page. Point 1 is about when you send it.

  1. Enough notice to act

    Send it early enough that people can change plans or cancel before the charge: days ahead for monthly plans, weeks for annual ones.

  2. The exact amount

    With the currency. If the price is changing at this renewal, say so here, not after the charge.

  3. The date

    When the charge happens. The template puts it in the subject and the details, so nobody has to open it to know.

  4. Which card

    Brand and last four digits. An expiring card gets updated now instead of turning into a failed payment later.

  5. An easy way to change or cancel

    One button to manage the subscription. If cancelling is hard to find, some people dispute the charge with their bank instead.

  6. Nothing to do to keep it

    Most people want to renew. The template says they don't need to do anything, so the email reads as a heads-up, not a demand.

The code. Copy the format your stack uses.

Change the brand name, logo and colors once in theme.ts and every template follows.

import * as React from 'react'
import { Button, Details, Layout, P, Small, Title } from '../../components'
import type { TemplateMeta } from '../../components/meta'
import { plainText, textDetails } from '../../components/text'

export type SubscriptionRenewalProps = {
  name: string
  planName: string
  amount: string
  renewalDate: string
  paymentMethod: string
  manageUrl: string
}

export const meta: TemplateMeta = {
  name: 'Subscription renewal',
  description: 'An upcoming-renewal reminder with the amount, date and card, sent before the charge.',
  group: 'Billing',
  subject: 'Your {{plan_name}} plan renews on {{renewal_date}}',
}

export default function SubscriptionRenewal(props: SubscriptionRenewalProps) {
  const { name, planName, amount, renewalDate, paymentMethod, manageUrl } = props
  return (
    <Layout
      preview={`Your ${planName} plan renews on ${renewalDate} for ${amount}.`}
      footerNote="You're receiving this because you have an active subscription."
    >
      <Title>Your subscription renews soon</Title>
      <P>
        Hi {name}, your {planName} plan renews automatically on {renewalDate}. You don't need to do anything to
        keep it.
      </P>
      <Details
        rows={[
          ['Plan', planName],
          ['Amount', amount],
          ['Renews on', renewalDate],
          ['Payment method', paymentMethod],
        ]}
      />
      <Button href={manageUrl}>Manage subscription</Button>
      <Small style={{ margin: 0 }}>
        To change plans or cancel, do it before {renewalDate} and you won't be charged for the next period.
      </Small>
    </Layout>
  )
}

SubscriptionRenewal.PreviewProps = {
  name: 'Ada',
  planName: 'Pro (annual)',
  amount: '$480.00',
  renewalDate: 'November 1, 2026',
  paymentMethod: 'Visa ending in 4242',
  manageUrl: 'https://example.com/billing',
} satisfies SubscriptionRenewalProps

export function text(props: SubscriptionRenewalProps) {
  const { name, planName, amount, renewalDate, paymentMethod, manageUrl } = props
  return plainText(
    'Your subscription renews soon',
    `Hi ${name}, your ${planName} plan renews automatically on ${renewalDate}. You don't need to do anything to keep it.`,
    textDetails([
      ['Plan', planName],
      ['Amount', amount],
      ['Renews on', renewalDate],
      ['Payment method', paymentMethod],
    ]),
    `Manage your subscription: ${manageUrl}`,
    `To change plans or cancel, do it before ${renewalDate} and you won't be charged for the next period.`,
  )
}

subscription-renewal.tsx, 73 lines, shown in full (scroll inside the panel). Typed props. Copy it with theme.ts and components/ from the repo. View on GitHub

Send it with Groundmail

Create the template in your account once, then send it by alias from your app.

1Terminal
npx -y --package=groundmail-cli -- groundmail templates push templates/subscription-renewal/subscription-renewal.html \
  --alias subscription-renewal \
  --name "Subscription renewal" \
  --subject "Your {{plan_name}} plan renews on {{renewal_date}}" \
  --text templates/subscription-renewal/subscription-renewal.txt \
  --publish
2Node.js
import { Groundmail } from 'groundmail'

const groundmail = new Groundmail(process.env.GROUNDMAIL_API_KEY!)

await groundmail.emails.send({
  from: 'Acme <noreply@yourdomain.com>',
  to: 'ada@example.com',
  template: {
    id: 'subscription-renewal',
    variables: {
      name: 'Ada',
      plan_name: 'Pro (annual)',
      amount: '$480.00',
      renewal_date: 'November 1, 2026',
      payment_method: 'Visa ending in 4242',
      manage_url: 'https://example.com/billing',
    },
  },
})

The CLI command and the Node.js send from the template's README, which also has Python, PHP and cURL. View on GitHub

Subject lines

Put the plan and the date in the subject so people know what's coming without opening it.

  • Your {{plan_name}} plan renews on {{renewal_date}}DefaultPlan and date, readable from the inbox list.
  • Your Acme {{plan_name}} plan renews on {{renewal_date}}GoodAdds the product, for people who pay for several tools.
  • Upcoming Acme renewal: {{amount}} on {{renewal_date}}GoodShows the amount up front, which is what annual customers check.
  • Don't miss out: renew nowAvoidIt renews automatically, so telling people to act is misleading, and it reads as marketing.

A renewal notice nobody saw turns into a refund request

If the reminder never reached the inbox, the first thing people see is the charge. Getting this one delivered saves support time later.

Google, Yahoo and Microsoft sender rules →
  • Keep it on a transactional stream, apart from newsletters and marketing.
  • Send from your own domain with SPF, DKIM and DMARC set up.
  • Send it at the same point before every renewal and log it, so support can show it went out.
  • Groundmail sends this template by alias from your own domain, on our own mail servers. Send it with Groundmail

Questions

Is it free to use?

Yes. The templates are MIT-licensed: use them in commercial products and change them however you like.

Do I need Groundmail to use it?

No. The HTML and text files use plain placeholders that work with most providers' template engines and with Handlebars or Mustache. Sending through Groundmail just saves a step.

Does it work in dark mode and Outlook?

Yes. The full HTML file carries dark-mode styles for Apple Mail and Outlook.com, and the extra markup desktop Outlook needs to draw the button.

How do I change the colors and logo?

Edit theme.ts once (name, logo, address and colors for light and dark) and rebuild. Every template in the set picks it up.