Send a feedback survey after each event
Email attendees a survey link automatically after Northwind workshops or trainings.
Published Oct 24, 2025
Northwind runs a fair number of workshops and training sessions, and the feedback loop on them is almost always broken. Someone means to send the survey, the day fills up, the email goes out three days late if at all, and the response rate suffers because attendees have already moved on.
This script handles the send for you. Once an hour it sweeps the last hour of the calendar for events whose title contains “workshop” or “training”, emails every guest a survey link, and tags the event so the same attendees never get the email twice. The whole loop runs without you opening Gmail.
What you’ll need
- A feedback form (Google Forms or otherwise) with a short URL. Paste it
into the
SURVEY_URLconstant. - Calendar events whose titles include “workshop” or “training” — adjust the regex in the script if you use different keywords.
- Gmail access for the survey emails — sent from the script owner.
- Nothing else — no spreadsheet, no API keys.
The script
// The feedback form to point attendees at. Anonymous responses recommended.
const SURVEY_URL = 'https://forms.gle/NORTHWIND_FEEDBACK';
// Which event titles count as surveyable. Case-insensitive substring match.
const SURVEYABLE_PATTERN = /workshop|training/i;
// How far back to look on each run. One hour matches the hourly trigger.
const LOOKBACK_MS = 60 * 60 * 1000;
// Tag key used to mark events the survey has already been sent for, so the
// same attendees never get the email twice.
const SENT_TAG = 'feedback-sent';
/**
* Sweeps the past hour for finished workshop/training events and emails
* each event's guest list a feedback survey link. Tags the event so the
* next run skips it.
*/
function postEventSurvey() {
const now = new Date();
const window = new Date(now.getTime() - LOOKBACK_MS);
const events = CalendarApp.getDefaultCalendar().getEvents(window, now);
for (const event of events) {
// 1. Skip events that have not finished yet — getEvents returns events
// overlapping the window, including ones still running.
if (event.getEndTime() > now) continue;
// 2. Skip events we have already sent for.
if (event.getTag(SENT_TAG) === 'yes') continue;
// 3. Skip events whose title does not match (regular meetings, calls).
if (!SURVEYABLE_PATTERN.test(event.getTitle())) continue;
// 4. Collect guest emails. Filter out blanks just in case.
const guests = event.getGuestList()
.map((g) => g.getEmail())
.filter(Boolean);
if (!guests.length) {
event.setTag(SENT_TAG, 'yes');
continue;
}
// 5. Send one email to all guests (comma-separated). Anonymous link.
GmailApp.sendEmail(
guests.join(','),
`Two-minute feedback: ${event.getTitle()}`,
`Thanks for attending. Quick feedback (anonymous): ${SURVEY_URL}`
);
// 6. Tag the event so the next run skips it.
event.setTag(SENT_TAG, 'yes');
Logger.log('Sent survey for "' + event.getTitle() + '" to ' + guests.length + ' guests.');
}
}
How it works
postEventSurveybuilds a one-hour window ending now and pulls every event that overlapped it.- For each event, it checks four conditions in order — still running, already sent, wrong title, no guests — and skips early in any of them.
- The title regex (
/workshop|training/i) means “Workshop: lighting” and “Training session — Foley” both match, but “Production brief” does not. Tune the pattern if your naming is different. - It calls
getGuestList, maps to emails, and drops anything falsy (declined guests with no email show up as blanks now and then). - One
sendEmailcall goes to every guest at once. The body keeps it short and notes the survey is anonymous — that matters for response honesty. - Finally,
setTag(SENT_TAG, 'yes')stamps the event so the next hourly run will skip it. Tags persist on the event itself, not in a separate store, so this is durable across script edits and reruns.
Example run
Suppose the calendar this morning held:
- 09:00–10:00 — Production brief (regular meeting)
- 10:00–11:00 — Workshop: editing 101 (3 guests)
- 10:00–11:30 — Training: VFX intro (5 guests)
At 11:30, when the trigger fires:
- The production brief is skipped — title does not match.
- The editing workshop is finished; three guests get an email, the event is tagged.
- The VFX training is finished; five guests get an email, the event is tagged.
A run at 12:30 sees the same events but skips both — they are tagged. New workshops on later in the day pick up their own send when they finish.
Trigger it
Run this on the hour so emails land within an hour of each event ending:
- In the Apps Script editor, open Triggers (the clock icon).
- Add a trigger for
postEventSurvey, time-driven, hour timer, every hour. - Save and approve the calendar and Gmail authorisation prompts.
Watch out for
- The lookback window is one hour. If the trigger fails or skips a run, an
event that finished during the gap will be missed. Widen
LOOKBACK_MSto two or three hours for safety — theSENT_TAGcheck prevents duplicates regardless. - Tags are scoped per calendar. If you scan a different calendar in another script, those tags do not collide — but copying the script to a new calendar will start fresh and may resend.
GmailApp.sendEmailreveals the guest list to every recipient in theToline. To keep attendees private, send one email per guest in a loop, or use thebccoption on the four-argument form.- Daily Gmail send quotas apply (100/day for consumer accounts, 1500/day for Workspace). A workshop with 200 attendees needs the BCC trick to avoid eating the quota with one event.
Related
Build a team-capacity view from calendars
Show how booked the Northwind team is this week — meeting hours per person.
Updated Oct 20, 2025
Flag meetings that could have been emails
Detect short, agendaless, oversized meetings — the smell of bad calendar hygiene.
Updated Oct 12, 2025
Send tiered deadline countdown reminders
Email Northwind teammates at 7, 3, and 1 days out from a Sheet of upcoming deadlines.
Updated Sep 30, 2025
Archive past events to a log sheet
Keep a searchable Northwind meeting history — every event logged with title, attendees, duration.
Updated Sep 26, 2025
Email a clean daily agenda each morning
Send Awadesh a list of today's Northwind events at 7am — no app needed.
Updated Sep 22, 2025