Blog · · 6 min read

How to remind customers before their prepaid session pack expires with n8n and AI

Step-by-step guide so n8n checks your session packs in Google Sheets every morning, spots the ones about to expire and drafts a clear Gmail reminder with AI before unused classes are lost.

In a gym, language school, beauty studio or any business with prepaid session packs (10-class bono, 5-treatment pack, coaching package…) you note the expiry date… and it slips by. The customer is left with unused sessions, you miss the chance to renew the pack and you end up explaining after hours that “it no longer counts”.

In this guide you will build an n8n workflow that every morning checks a register of session packs in Google Sheets, finds the ones expiring in ~14 or ~3 days and drafts a clear Gmail reminder with AI. You review the draft and send it.

This is not the same as a subscription or membership renewal reminder: there the customer pays a recurring plan that renews; here they have a prepaid pack with an expiry date and sessions left. It also does not replace a free-trial ending reminder: that is a trial ending; this is an already-purchased pack about to expire. And it is not an appointment reminder for a booked slot: there the appointment already exists; here you warn that the pack is ending and sessions remain unused.

What you will build

A five-step workflow that runs on its own every day:

  1. Daily trigger: a Schedule Trigger node runs at 09:25.
  2. Read packs: a Google Sheets node reads your “Session packs” sheet.
  3. Filter by expiry and remaining sessions: a Code node keeps rows expiring in ~14 or ~3 days, with remaining sessions > 0, that have not yet had that stage’s reminder.
  4. AI reminder: a Basic LLM Chain node writes a warm email that recalls the pack, the sessions left and the expiry date.
  5. Draft and log: Gmail creates the draft and Google Sheets records the stage in reminder_sent.

What you need

  • An n8n instance (cloud or installed free on your computer).
  • Google Sheets and Gmail connected in n8n.
  • An OpenAI (or other AI) API key, with a monthly spend limit set in the provider’s dashboard.
  • A “Session packs” sheet with these columns: customer, email, product (pack name), sessions_total, sessions_left, expires_on (YYYY-MM-DD), notes and reminder_sent (empty or 1 / 2).

You can fill the sheet by hand when you sell a pack, or with another n8n workflow that writes each sale and decrements sessions_left as sessions are used. This guide assumes the rows are already in Sheets.

Step 1: prepare the session-packs sheet

Keep expires_on in a consistent date format (YYYY-MM-DD). Leave only active packs with sessions left; archive empty or already expired ones. In product use clear names (“10-class yoga pack”, “5-session coaching pack”, “Physio bono 8”). Update sessions_left every time the customer uses a session (by hand or with another workflow). In notes capture useful preferences (“prefers mornings”, “WhatsApp”, “wants to renew the same pack”).

Step 2: trigger and read

Add a daily Schedule Trigger at 09:25 (check the workflow timezone in Settings is Europe/Madrid or your local zone). Connect it to Google Sheets → Get Row(s) pointing at your “Session packs” sheet.

Step 3: filter packs that are about to expire

Add a Code node (Run Once for All Items) with this code:

const today = new Date(); today.setHours(0, 0, 0, 0);
const out = [];
for (const i of $input.all()) {
  const c = i.json;
  if (!c.email || !c.expires_on) continue;
  const left = Number(c.sessions_left);
  if (!Number.isFinite(left) || left <= 0) continue; // pack empty
  const exp = new Date(c.expires_on); exp.setHours(0, 0, 0, 0);
  const days = Math.round((exp - today) / 86400000);
  if (days < 0 || days > 16) continue; // already expired or too far out
  const already = Number(c.reminder_sent || 0);
  let stage = null;
  if (already < 1 && days >= 12 && days <= 15) stage = 1;   // ~14 days
  else if (already <= 1 && days >= 0 && days <= 4) stage = 2; // ~3 days
  if (!stage) continue;
  out.push({ json: { ...c, days, stage, sessions_left: left } });
}
return out;

Each pack gets at most two reminders: one ~two weeks ahead and one in the final days. If sessions_left is 0, the row is skipped (no point warning about an empty pack). If nothing is due, the workflow ends without spending AI credits. You can tweak the windows (12–15 and 0–4) for your industry.

Step 4: draft the reminder with AI

Add a Basic LLM Chain with a small cheap model (for example gpt-4o-mini) and this prompt:

You manage session packs for [BUSINESS NAME]. Write a short email to
{{ $json.customer }} letting them know that their “{{ $json.product }}” pack expires on
{{ $json.expires_on }} ({{ $json.days }} days left).
Sessions total: {{ $json.sessions_total }}. Sessions left: {{ $json.sessions_left }}.
Notes: {{ $json.notes }}
- Warm, professional tone, max 7 sentences.
- Remind them they still have sessions to use and the expiry date; do not alarm or blame.
- Invite them to book the remaining sessions or renew the pack if they want; do not invent prices or discounts.
- If notes include preferences (schedule, channel), take them into account without inventing data.
- Do not invent booking links, amounts or dates that are not in the data.
Return only the email body.

The facts come from your sheet; the AI only sets the tone. If your booking software already sends its own expiry email, use this flow as a warmer second reminder or for packs you manage by hand.

Step 5: create the draft and mark the reminder

Connect a Gmail → Create Draft node with recipient {{ $('Code').item.json.email }}, subject Your pack expires soon · {{ $('Code').item.json.product }} and the AI text as the body. Drafts let you review before sending, just like subscription renewal reminders or free-trial ending reminders.

Then a Google Sheets → Update Row node that looks up by email + expires_on (or product if a customer has several packs) and writes the stage into reminder_sent.

Once you trust the wording, you can switch Create Draft to Send.

How to test it

  1. Add a test row with your own email, an expires_on about 14 days out, sessions_left > 0 and reminder_sent empty.
  2. Run the workflow by hand and check that a draft appears and reminder_sent becomes 1.
  3. Run it again: no new draft should be created (outside the stage-1 window).
  4. Change expires_on so ~3 days remain (leaving reminder_sent at 1) and confirm the second reminder is prepared.
  5. Set sessions_left to 0 and confirm the workflow creates no reminder.

Cost and good practices

  • Cost: each reminder costs well under a tenth of a cent on the AI API. Set a monthly spend limit in the provider’s dashboard.
  • Don’t nag: at most ~2 reminders per pack; if they do not book, log it and later, if it fits, use a win-back inactive customers flow.
  • Keep sessions_left up to date: if you do not decrement on use, you will warn about empty packs or skip packs that still have balance.
  • Don’t invent prices or links: the prompt must not invent renewal offers that are not in your data.
  • Catch failures: add an error workflow so you know if Gmail or Sheets fails, as in n8n error handling.
  • Combine it with appointment reminders once the customer has booked a session from the pack, and with subscription renewal reminders if they also have a separate monthly membership.

Start with ready-made templates

If you’d rather skip the basic n8n setup, download the WhatsApp agent for free or check out the AgentKiosk pack: 8 ready-to-import agents in English and Spanish, each with workflow, prompt and guide, ready to combine with these session-pack expiry reminders.