appointment-reminder-gcal
Reads upcoming events directly from your Google Calendar (no CSV to maintain), sends a 24-hour and 1-hour reminder email to each event's attendees, and tracks per-event state in a Sheet so each event is reminded exactly once per window. Cross-platform: uses the python runtime env which InTouch auto-creates on Linux, macOS, AND Windows.
Use case
Service businesses (salons, repair shops, consultants, contractors, clinics) already maintain appointments in Google Calendar. Maintaining a separate CSV — the model the original appointment-reminder workflow uses — duplicates work and gets out of sync. This variant skips the CSV entirely: the calendar IS the source of truth. Add an event with the customer as an attendee, this workflow handles reminders.
Single-engine reminders (Calendar-resident automatic alerts) ping the user themselves, not the customer. This workflow sends to the customer.
Setup
- Credentials (Credentials view):
-
google-workspace— Google Workspace service-account JSON with domain-wide delegation - Runtime environment (Runtime Environments view):
-
python— InTouch auto-creates this on Linux, macOS, AND Windows from the detected Python 3 install. No platform-specific setup. - Google Calendar — use your
primarycalendar or any calendar you own. Add events with the customer as an attendee (their email is what gets the reminder). The event title becomes the reminder subject; the time becomes the body. - Reminder-state Sheet (one-time):
- Create a Sheet with a tab
ReminderStateand 4 columns:event_id | summary | reminded_24h | reminded_1h- Row 1 is the header; data starts at row 2. - The workflow manages it — do not edit manually. - Copy the spreadsheet ID from the URL. - Edit
workflow.yaml— replace the four placeholders: -<<CALENDAR_ID>>—primaryfor your main calendar, or any calendar ID (looks like[email protected]) -<<REMINDER_STATE_SHEET_ID>>— the state Sheet ID -<<SHOP_NAME>>— your business name (used in the reminder signature) -<<OWNER_PUBLISHER>>— user name linked to your contact, for the "what was sent today" summary - Schedule the workflow every hour. Higher frequency wastes API quota; lower may miss the narrow 0.5–1.5-hour window for the 1-hour reminder.
Pipeline
- process —
runtimeenv(python). Queries Calendar for events in the next 25 hours, joins against theReminderStateSheet, and for any event with a 23–25-hour or 0.5–1.5-hour countdown that hasn't been reminded yet: sends an email to each attendee, then writes back the updated state row. Outputs a plain-text summary of who was reminded. - notify-owner —
message. Sends the summary text to your owner user (so you can see, every hour, what went out — or "No reminders sent.").
Sample reminder
Subject: Reminder: AC Repair tomorrow
Hi,
This is a reminder about your appointment 'AC Repair' scheduled for
Wednesday, April 15 at 10:00 AM PDT.
If you need to reschedule, please reply to this email.
— Acme HVAC
Customization
- Reminder windows — change
23 <= hours_until <= 25and0.5 <= hours_until <= 1.5in the script. Common alternatives: 48-hour pre-booking confirmation, 15-minute "we're on our way" ping. - Multiple calendars — pass multiple
--calflags to theeventscall, or change--cal "$CAL"to--allto span every calendar the service account has access to. - Calendar filter by title — filter events by
event["summary"]regex before sending (skip personal events on a mixed calendar). - Channel — replace the
gmail sendcall with ansms send(Twilio) or other channel if the attendee field carries phone numbers instead. The current pattern uses attendee emails because Google Calendar's attendee model is email-based. - Owner copy of every reminder — add
--cc [email protected]to thegmail sendcall.
Differences from the CSV-based appointment-reminder
appointment-reminder (CSV) |
appointment-reminder-gcal (Calendar) |
|
|---|---|---|
| Source of truth | CSV file you maintain | Google Calendar |
| Delivery channel | SMS / WhatsApp (uses Anthropic to draft messages) | Email to event attendees (templated, no AI) |
| Cost per run | Anthropic Haiku call + SMS provider | Zero AI cost; Gmail send only |
| State tracking | reminded_24h / reminded_1h columns in the same CSV |
Separate ReminderState Sheet keyed by event_id |
| Cross-platform | bash runtime (Linux/macOS; Windows needs Git Bash/WSL) | python runtime (Linux, macOS, Windows out of the box) |
| Best fit | Shops where appointments live in a database or a dedicated CSV | Anyone already running their calendar in Google Workspace |
Use either, not both, against the same set of appointments.
Verified
Flag/command syntax verified against the bundled gog v0.19.0 (2026-06-01). gog calendar events output shape (events return id, summary, start.dateTime, attendees[].email) should be re-verified on first run against your Workspace account. Email sends, Sheet append/update verified separately.
Source
See workflow.yaml.