How to Send Invoice Payment Reminders from Google Sheets (2026)
Once invoices live in a Google Sheet, the next problem is usually collection: which ones are unpaid, which are overdue, and who should get a polite reminder. Highlighting helps when you open the sheet. A daily script can email the client (or you) seven days before the due date, on the due date, and a week later if it is still unpaid.
To create the invoice PDF from each row, use the invoices and certificates guide. This page is only about reminders. For a generic date-column reminder (one email, any kind of date), see automatic email reminders from a date column.
Step 1: columns for unpaid work
Create a tab named Invoices with: Invoice #, Client, Email, Amount, Due date, Status, plus Sent 7d before, Sent on due, and Sent 7d after. Status values such as Draft, Sent, Paid and Overdue are enough. Format Due date as a date and Amount as currency.
In Days overdue (due date in column E, status in F):
=IF(OR(F2="Paid",F2="Draft",E2=""),"",IF(E2<TODAY(),TODAY()-E2,0))
A simple aging label:
=IF(OR(F2="Paid",F2="Draft",E2=""),"",IF(E2>=TODAY(),"Current",IF(TODAY()-E2<=30,"1-30 days",IF(TODAY()-E2<=60,"31-60 days","60+ days"))))
Step 2: highlight what is unpaid and late
Select the data from row 2 and add conditional formatting:
- Paid:
=$F2="Paid"(light green or grey) - Unpaid and overdue:
=AND($E2<TODAY(),$F2<>"Paid",$F2<>"Draft",$E2<>"")(light red) - Due within 7 days and unpaid:
=AND($E2>=TODAY(),$E2-TODAY()<=7,$F2<>"Paid",$F2<>"Draft")(amber)
A filter view named “Unpaid overdue” is enough for a weekly collection pass.
What native notifications will not do
Tools › Notification settings (and conditional notifications, where available) email people when cells are edited. They do not send a reminder because a due date arrived, and TODAY() formulas do not trigger conditional notifications while the sheet is closed. See Google's conditional notifications help.
Step 3: three reminder steps, no duplicates
Open Extensions › Apps Script, paste the script, save, run sendInvoiceReminders once to approve permissions, and add a daily time-driven trigger. Draft and Paid invoices are skipped. Each step has its own sent column so a late invoice can receive the “7 days before” email (if you turned this on while it was already inside the window), the due-date email, and one overdue follow-up, each only once.
/**
* Payment reminders for unpaid invoices: 7 days before due, on the due date,
* and 7 days after if still unpaid.
* Columns: A Invoice # | B Client | C Email | D Amount | E Due date | F Status
* G Sent 7d before | H Sent on due | I Sent 7d after
* Skips Status Draft or Paid (any case). Trigger: daily time-driven on sendInvoiceReminders.
*/
function sendInvoiceReminders() {
const sh = SpreadsheetApp.getActive().getSheetByName('Invoices');
const rows = sh.getDataRange().getValues();
const today = new Date(); today.setHours(0, 0, 0, 0);
const tz = Session.getScriptTimeZone();
const steps = [
{ offset: 7, col: 7, label: 'due in 7 days' },
{ offset: 0, col: 8, label: 'due today' },
{ offset: -7, col: 9, label: '7 days overdue' },
];
for (let r = 1; r < rows.length; r++) {
const inv = rows[r][0], client = rows[r][1], email = rows[r][2];
const amount = rows[r][3], due = rows[r][4], status = String(rows[r][5] || '');
if (!email || !(due instanceof Date)) continue;
const st = status.toLowerCase();
if (st === 'draft' || st === 'paid') continue;
const dueDay = new Date(due); dueDay.setHours(0, 0, 0, 0);
const left = Math.round((dueDay - today) / (24 * 60 * 60 * 1000));
const amountText = (typeof amount === 'number')
? amount.toLocaleString('en-US', { style: 'currency', currency: 'USD' })
: String(amount);
const dueText = Utilities.formatDate(due, tz, 'MMM d, yyyy');
for (const s of steps) {
if (left > s.offset) continue; // not yet at this step
if (rows[r][s.col - 1]) continue; // already sent
if (MailApp.getRemainingDailyQuota() < 1) return;
const subject = 'Invoice ' + inv + ' ' + s.label;
const body = 'Hi ' + client + ',\n\nThis is a reminder that invoice ' + inv +
' for ' + amountText + ' is ' + s.label + ' (due ' + dueText + ').\n\nThank you.';
MailApp.sendEmail(email, subject, body);
sh.getRange(r + 1, s.col).setValue('Sent ' + Utilities.formatDate(new Date(), tz, 'yyyy-MM-dd'));
}
}
}
Edit the message body to match how you already write to clients, and include a payment link or invoice PDF URL if you store one in another column. Keep the tone factual: invoice number, amount, due date.
Caveats
- Daily email limit. Sends come from your account and count against the Apps Script email quota.
- Don't nag paid invoices. Update Status to Paid when payment lands, or the overdue step will still fire.
- Catch-up behavior. If you install this when an invoice is already 10 days late, the first run may send all three steps that are due. Clear a sent cell only if you intend to send that step again.
- Ownership and time zone. The trigger runs as its creator. Set the spreadsheet time zone under File › Settings.
See SheetReminders
Short on time? Watch the 50-second version
Related Google Sheets guides
- How to generate a PDF or Google Doc for each row in Google Sheets
- Best Autocrat alternatives for mail merge to PDF and Docs
- Make invoices or certificates from Google Sheets rows
- Create sales quotes or estimates from Google Sheets
- Generate receipts from Google Sheets rows
- Create purchase orders from Google Sheets
- Make packing slips from Google Sheets orders
- Generate a PDF certificate from a Google Form response
- Issue numbered training completion certificates with expiry dates
- Make a PDF progress report for each student
- Generate offer letters from a Google Sheets hiring tracker
- Email each row’s PDF as an attachment
- Automatic email reminders from a date column
- Contract renewal and expiration alerts from Google Sheets
- Track certificate of insurance (COI) expirations in Google Sheets
- Track employee license and certification expirations
- Track equipment and vehicle maintenance with reminders
- Track warranty expiration dates with reminders
- Birthday and work anniversary reminders from Google Sheets
- Rent due and lease renewal reminders from Google Sheets
- Send invoice payment reminders from Google Sheets
- Highlight overdue tasks and send email reminders
- Follow-up reminders for leads, clients and candidates
- Membership renewal reminders for clubs and associations
- SheetWeave vs Autocrat
- SheetWeave vs Document Studio
- SheetWeave vs RowDocs
Instructions refer to Google Sheets, Google Docs, Google Forms, Google Drive and Apps Script as they worked on November 10, 2026. Not affiliated with Google or any other vendor named here. Google Sheets, Google Docs, Google Forms, Google Slides and Google Drive are trademarks of Google LLC. Features change, so verify in your own account. Questions or corrections: hello@loomwise.app.