appscript.dev
Automation Intermediate Calendar Sheets

Apply attendee rules by event type

Auto-invite the right Northwind people from a Sheet — design reviews get design, client calls get account leads.

Published Oct 4, 2025

Whoever books a meeting at Northwind knows the topic but not always the cast. A design review needs the design team. A client call needs the account lead. The booker remembers the obvious people and forgets the rest, so reviews happen without a reviewer and someone gets pulled in at the last minute.

This script reads a small Sheet of rules — a keyword and the people that keyword should pull in — and applies them to the week ahead. Title an event “Design review: Castle rebrand” and the design team appears on the invite automatically. The booker only has to name the meeting sensibly; the right attendees follow from the title.

What you’ll need

  • An Attendee rules sheet with two columns: keyword (a word or phrase to look for in event titles) and attendees (a comma-separated list of email addresses to invite when that keyword matches).
  • Events created on your default Google Calendar with descriptive titles — the script matches on title text, so “Design review” works and “Meeting” does not.

The script

// The sheet of keyword -> attendees rules.
const ATTENDEE_RULES = '1abcAttendeeRulesId';

// How many days ahead to apply rules to.
const WINDOW_DAYS = 7;

// Event tag used to mark events we have already processed.
const APPLIED_TAG = 'attendees-applied';

/**
 * Reads the attendee rules and applies them to upcoming events:
 * any event whose title contains a rule's keyword gets that rule's
 * attendees added as guests.
 */
function applyAttendeeRules() {
  // 1. Load the rules from the Sheet.
  const rules = readSheet(ATTENDEE_RULES);
  if (!rules.length) {
    Logger.log('No attendee rules defined — nothing to do.');
    return;
  }

  // 2. Look at events from now to WINDOW_DAYS ahead.
  const start = new Date();
  const end = new Date(start.getTime() + WINDOW_DAYS * 86400000);
  const events = CalendarApp.getDefaultCalendar().getEvents(start, end);

  for (const event of events) {
    // Skip events we have already handled on a previous run.
    if (event.getTag(APPLIED_TAG) === 'yes') continue;

    // 3. Test the event title against every rule's keyword.
    for (const r of rules) {
      if (event.getTitle().toLowerCase().includes(r.keyword.toLowerCase())) {
        // 4. Add each attendee listed for the matching rule.
        String(r.attendees).split(',').map((s) => s.trim()).filter(Boolean)
          .forEach((g) => event.addGuest(g));
        // 5. Tag the event so it is not processed again.
        event.setTag(APPLIED_TAG, 'yes');
      }
    }
  }
}

/**
 * Reads the first tab of a spreadsheet into an array of objects,
 * one per row, keyed by the header cells.
 */
function readSheet(id) {
  const [h, ...rows] = SpreadsheetApp.openById(id).getSheets()[0].getDataRange().getValues();
  return rows.map((r) => Object.fromEntries(h.map((k, i) => [k, r[i]])));
}

How it works

  1. applyAttendeeRules loads the rules sheet with readSheet, which turns each row into an object keyed by the header — { keyword, attendees }. If there are no rules, it stops.
  2. It asks the default calendar for every event from now to WINDOW_DAYS ahead (a week by default).
  3. For each event it skips any already carrying the attendees-applied tag, so a re-run does not re-invite people.
  4. It tests the lower-cased event title against each rule’s lower-cased keyword. A match means the keyword appears anywhere in the title.
  5. On a match it splits the rule’s attendees cell on commas, trims each address, and adds every one as a guest.
  6. It then tags the event with attendees-applied so the next run leaves it alone.

Example run

Say the Attendee rules sheet holds:

keywordattendees
design review[email protected], [email protected]
client call[email protected]

And the week ahead has these events:

Event titleGuests added
Design review: Castle rebrandmaya, leo
Client call — Brightlinepriya
Sprint planningnone (no keyword matches)

After the run, the design review and the client call both have the right people on the invite, and each is tagged so the next run skips it.

Trigger it

Run this on a daily timer so events booked through the day pick up their attendees overnight:

  1. In the Apps Script editor open Triggers and click Add Trigger.
  2. Choose applyAttendeeRules, set the event source to Time-driven, and pick a Day timer for early morning.

It will only ever touch events inside the next WINDOW_DAYS, and the tag means each event is processed once.

Watch out for

  • Adding a guest sends them a calendar invitation. Run this with care while testing — point it at a test calendar first so you do not spam real people.
  • Keyword matching is a plain substring check, so a rule keyword of review also fires on “code review” and “peer review”. Make keywords specific.
  • An event can match more than one rule and collect every matching rule’s attendees — usually what you want, but worth knowing.
  • Event tags survive on the event itself. If you change a rule and want it re-applied to an already-tagged event, remove the attendees-applied tag from that event by hand.
  • getEvents returns recurring events as individual instances within the window — each instance is tagged separately.

Related