Appointment reminder, 24 hours ahead
Each morning, the script emails clients whose booking is tomorrow and who have not already been reminded.
What the sheet looks like
| Name | Date | Time | Reminder sent | |
|---|---|---|---|---|
| Ana Pop | ana@example.com | 2026-10-26 | 10:00 |
Setup, about 5 minutes
- Put bookings on a sheet with columns Name, Email, Date, Time, and Reminder sent.
- Paste the code into Apps Script.
- Add a time trigger: sendAppointmentReminders, daily, in the morning.
- Dates can be real date cells or yyyy-MM-dd text.
- After sending, Reminder sent gets the date, so a second email does not go out.
Apps Script
/**
* Emails bookings dated tomorrow that do not yet have "Reminder sent".
* Add a time-driven trigger: sendAppointmentReminders, day timer, any morning hour.
* Date cells may be real dates or yyyy-MM-dd text.
*/
function sendAppointmentReminders() {
var sheet = SpreadsheetApp.getActive().getSheetByName('Bookings') || SpreadsheetApp.getActiveSheet();
var data = sheet.getDataRange().getValues();
if (data.length < 2) return;
var headers = data[0].map(function (h) { return String(h).trim(); });
var dateCol = headers.indexOf('Date');
var emailCol = headers.indexOf('Email');
var nameCol = headers.indexOf('Name');
var sentCol = headers.indexOf('Reminder sent');
if (dateCol < 0 || emailCol < 0 || nameCol < 0 || sentCol < 0) {
throw new Error('Need columns Name, Email, Date, and Reminder sent.');
}
var tz = Session.getScriptTimeZone();
var tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
var target = Utilities.formatDate(tomorrow, tz, 'yyyy-MM-dd');
for (var r = 1; r < data.length; r++) {
var email = String(data[r][emailCol] || '').trim();
var sent = String(data[r][sentCol] || '').trim();
if (sent || email.indexOf('@') < 0) continue;
if (asYmd_(data[r][dateCol], tz) !== target) continue;
MailApp.sendEmail({
to: email,
subject: 'Reminder: appointment on ' + target,
body: 'Hello ' + data[r][nameCol] + ',\n\nThis is a reminder for your appointment on ' + target + '.\n'
});
sheet.getRange(r + 1, sentCol + 1).setValue(new Date());
}
}
function asYmd_(value, tz) {
if (Object.prototype.toString.call(value) === '[object Date]' && !isNaN(value.getTime())) {
return Utilities.formatDate(value, tz, 'yyyy-MM-dd');
}
return String(value || '').trim().slice(0, 10);
}