FlowKit

Automating follow-ups for incomplete case files with n8n: cron, Supabase and AI

Published 18 July 2026 · 6 min read

In an audit firm, a compliance team, or an HR department collecting supporting documents, the pattern repeats itself: a case file opens, half the documents arrive within 48 hours, and the rest drags on for weeks. Not out of bad faith — simply because no one internally has time to methodically chase every lagging file. Internal studies from firms that track this metric converge on the same rough figure: 30 to 50% of started case files never reach completion without an active follow-up. It's one of the most profitable dead zones to automate, and also one of the most neglected.

n8n lets you build this safety net in a single afternoon: a workflow that runs every weekday morning, identifies incomplete files, has an LLM draft a personalized reminder, sends it, logs the date, and posts a Slack summary of the run. Here's the full architecture, node by node.

Why manual follow-up always breaks down

Two problems compound each other. First, the mental overhead: chasing files means remembering who was contacted, when, and about what — a list that grows faster than it shrinks in an already full schedule. Second, the tone: naive automation (a generic email looped by a basic cron) irritates more than it helps, precisely because it's identical for everyone and gets spotted in a second.

The fix isn't choosing between careful-but-irregular human follow-up and regular-but-robotic automation — it's automating the regularity while handing the drafting to a language model that has access to the file's actual context.

Workflow architecture

The pipeline fits in six steps, all triggered automatically:

  1. Cron trigger — every weekday morning at 9am.
  2. Supabase read — fetch files with status incomplete.
  3. Loop (Split In Batches) — process files one at a time.
  4. AI drafting — an LLM composes the email from the file's context.
  5. Send + logging — SMTP email, then update last_reminder_at.
  6. Slack summary — a wrap-up message once the run finishes.

Step 1: a cron that respects business days

The Schedule Trigger node uses the cron expression 0 9 * * 1-5: every weekday at 9am, never on weekends. This matters more than it looks — a reminder landing on a Sunday morning undercuts the message and signals a careless process, even when the wording itself is flawless.

Step 2: fetch incomplete files from Supabase

A Supabase node queries the case_files table filtered on status = 'incomplete'. Starting from scratch, a minimal schema looks like this:

create table case_files (
  id bigserial primary key,
  name text not null,
  email text not null,
  status text default 'incomplete',
  missing_documents text,
  created_at timestamptz default now(),
  last_reminder_at timestamptz
);

To space reminders out instead of nagging the same file every morning, add a filter on last_reminder_at (for example last_reminder_at is null or last_reminder_at < now() - interval '3 days') directly in the Supabase query — the node then only returns files that are actually due for another reminder.

Step 3: handle one file at a time

The Split In Batches node (batch size 1) turns the file list into a sequential loop: drafting, sending, and logging happen one file at a time, looping back until the list is exhausted. This guarantees that one failed email doesn't block the rest of the run.

Step 4: AI drafting, the heart of the workflow

A Chain LLM node (wired to a chat model sub-node, e.g. lmChatOpenAi) receives the file's context — name, age, missing documents, how many reminders were already sent — and drafts the email. A simple but effective system prompt:

Draft a courteous, brief follow-up email for an incomplete case file.
Context: {{ $json.name }}, file opened on {{ $json.created_at }},
missing documents: {{ $json.missing_documents }},
number of previous reminders: {{ $json.reminder_count }}.

Guidelines:
- Professional, friendly tone, never guilt-tripping.
- State precisely what's missing, without listing the full history.
- If reminder_count >= 2, be slightly more direct without becoming curt.
- A generic sign-off, no filler.

This personalization is what changes the outcome: two recipients never get the same text, whereas a classic fill-in-the-blank email is spotted at a glance and gets ignored. For the basics of wiring n8n to a model provider, our guide on connecting Claude or GPT to n8n covers credential setup and model choice.

Step 5: send and log

A Send Email (SMTP) node sends the generated message from an address on your own domain — deliverability and professional image depend directly on it (make sure SPF/DKIM are configured on your DNS). Right after, a second Supabase node updates last_reminder_at on that file: this field, combined with the step 2 filter, is what prevents duplicate reminders and provides the full audit trail.

Step 6: a summary, not a per-file notification

Once the loop finishes (the done branch of Split In Batches), a Slack node posts a wrap-up: number of reminders sent, any failures. One message per morning, not one per file — oversight should stay readable, not become a new source of noise.

Taking it further

A few tweaks turn a good workflow into a great one:

  • Progressive tone escalation. Passing the reminder count into the prompt lets the third reminder be legitimately more direct than the first, without ever turning aggressive — exactly the kind of nuance a language model handles far better than a static email template.
  • A fallback channel for email-unresponsive recipients. Switching a reminder to SMS or WhatsApp after two unanswered email attempts noticeably improves response rates for some audiences.
  • A dedicated alert for send failures. A separate Error Workflow, triggered only when a send genuinely fails, prevents discovering an SMTP issue three weeks later. Our guide on handling errors in n8n explains how to wire it up cleanly, with retries and a Slack alert.
  • Self-hosting when the file volume is sensitive. For GDPR-sensitive data (HR files, ID documents), keeping n8n on your own infrastructure rather than a managed cloud can be a compliance requirement — our comparison of n8n self-hosted vs cloud helps you decide.

Mistakes that cost an evening of debugging

  • Forgetting the last_reminder_at filter: without it, the same file gets an identical reminder every morning, which instantly kills the credibility of the whole system.
  • A prompt that's too generic: without the file's precise context (missing documents, reminder count), the LLM produces plausible but insufficiently targeted text — personalization is the entire point of this approach.
  • No error handling on the SMTP send: a credential or quota issue that goes unnoticed for days, when an immediate Slack alert would let you fix it within the hour.
  • A loop with no audit trail: update last_reminder_at after the send actually succeeds, never before — otherwise a silent failure means a file you believe was followed up on, when it wasn't.

Save yourself an afternoon

Building this pipeline from scratch — Supabase table, cron, loop, a properly tuned prompt, logging, Slack summary — easily takes half a day when you're new to the relevant n8n nodes. The Compliance & Audit Pack ships this reminder workflow ready to import, alongside a questionnaire bot, a Supabase audit-trail logger, and an AI-generated summary report — the four building blocks that cover file collection end to end. Connect your credentials, adapt the prompt to your brand's tone, and the first reminder run goes out the next business morning.

Once it's running, this kind of automation improves in small increments: a refined filter, an added channel, better-tuned escalation. It's exactly the kind of repetitive, detail-sensitive task where n8n and an LLM, combined, save hours every week without ever sacrificing the quality of the client relationship.

FAQ

Frequently asked questions

How long should you wait before a second reminder?

There's no universal rule, but spacing reminders 3 to 5 business days apart avoids feeling spammy while keeping the case active. Filter on last_reminder_at to enforce it: the Supabase node only returns files whose last reminder is older than N days.

Is the AI-generated tone actually different every time?

Yes, as long as you feed the case's context into the prompt (name, age of the file, how many reminders were already sent). The model then drafts an email specific to that recipient rather than a fill-in-the-blank template — two people never receive the same wording, while staying consistent with your brand's tone.

What happens if an email send fails mid-loop?

Without extra care, Split In Batches simply moves to the next file and the failed file's last_reminder_at is never updated — so it gets retried the next morning, which is a reasonable default. To get notified of the failure instead of discovering it later, wire up a dedicated Error Workflow (see our guide on handling errors in n8n).

Bundle FlowKit Complet

€269