How do I send the standard invitation email when calling addGuest on a CalendarEvent?

Whenever I add a guest via the Google Calendar UI, the following dialog pops up:

enter image description here

If I choose "Send" it sends a nicely formatted email to the user with an option to respond to the calendar event too:

enter image description here

This works flawlessly when you're manually using the Google Calendar UI. Problem is I'm trying to use Google Apps Scripts to automate adding people to events.

I'm programmatically adding guests to a CalendarEvent by using addGuest():

event.addGuest("[email protected]");

However, there doesn't seem to be an option to send an email.

The closest I could find is that when you programmatically create an event, you can set sendInvites:

  var event = CalendarApp.getDefaultCalendar().createEvent(
    'Test',
    new Date('April 5, 2029 20:00:00 UTC'),
    new Date('April 5, 2029 21:00:00 UTC'),
    {sendInvites: true, guests:"[email protected]"});
  Logger.log(event.getId());

This sends a nicely formatted email correctly.

However, the sendInvites option only works when the event is newly created. If at a later time I call:

  var event = CalendarApp.getEventById("insert_id_here");
  event.addGuest("[email protected]");

... it does not send an email update (even though the event was created with sendInvites=true). This means sendInvites is transient and doesn't persist on the event.

Is there any way to sendInvites when calling addGuest() on an event? E.g. event.addGuest("[email protected]", {sendInvite: true})?

Are there any other workarounds that will produce the same email that is sent when hitting that "Send" button in the UI above?

Note: I do not want to use MailApp to send an email because it won't be nicely formatted like the one Google automatically sends out (e.g. with embedded calendar invite, attendees, description, response links, etc, etc, etc).


Update:

  • I just saw getAllTagKeys in the API and was hoping I could use that to get the sendInvites key, but that's not the case. It is empty even for events that have sendInvites set to true.

As tehhowch mentioned, the key is you must use the Advanced Google API for this. However, the text on this page that says:

This sends an invitation email to the attendees and places the event on their calendar.

... is very misleading. The only way it'll send email is if you set sendUpdates to all for the request.


First, you can verify that sendUpdates is the key piece to sending email for new events via the advanced API:

  1. Go to this link.
  2. Hit the Try it now button up top.

    This should show you a form with the following info populated:

    • calendarId: primary
    • sendUpdates: all
    • Request body:

      {
        "start": {
          "date": "2029-04-04"
        },
        "end": {
          "date": "2029-04-04"
        },
        "summary": "Test",
        "attendees": [
          {
            "email": "[email protected]"
          }
        ]
      }
      
  3. Change the [email protected] to your email address.

    Note that this cannot be your exact email address that you are logged in with. Otherwise the script will notice that you're trying to send an email to yourself and not send it. Instead, if you have a Google email account, you should use a plus address instead.

  4. Hit the Execute button.

    After giving it permissions, you will receive an email to your inbox with the calendar event fully populated just as it is sent when using Google Calendar's UI.

  5. If you want to definitively prove that sendUpdates is important, set it to blank instead of all. Send the invite. Notice that it didn't arrive in your inbox.

If it's not working, make sure that you follow these caveats:

  1. You must not send an email to the same logged in Google account. E.g. either use a plus address, or send it to a different account.
  2. Ensure that sendUpdates is set to all.
  3. Ensure that the event is some time in the future. Google will never send email for invites sent to events in the past. This is true even if you manually use Google Calendar's interface. It'll ask you if you want to send updates to the user(s), you choose "yes", but because the event is in the past, it won't actually send email.

Since the original question already shows how to use the standard CalendarApp to do what we did above, we didn't accomplish much, yet. Now that we know that sendUpdates is important, though, it's time to look at adding a guest.

As the original question points out, there is no way to specify sendInvite (as we would with the standard Calendar API) or sendUpdates (as we would with the advanced Calendar API) when using CalendarApp. The only method we have is addGuest().

Luckily, we can use the Advanced Calendar API similar to how we did above and send an update (aka PATCH) to the event. Rather than interfacing with raw JSON and the Advanced Calendar API, we can use Google's nice wrapper around the advanced API (aka Calendar).

However, since we're using the advanced Calendar API, we must abide by this note:

Note: This is an advanced service that must be enabled before use.

This means there are some prerequisites before jumping into code:

  1. First, enable Google Calendar API in your Cloud Platform project:

    1. In your script, navigate to Resources > Cloud Platform project...
    2. Do one of the following:

      • If you see This script has an Apps Script-managed Cloud Platform project., congratulations, you're done with this step!
      • If you see This script is currently associated with project:, do the following:

        1. Click on the link underneath This script is currently associated with project:

          This will take you to the current project on Google Cloud Platform.

        2. APIs & Services > Dashboard
        3. Enable APIs and Services
        4. Add Google Calendar API
        5. Hit the Enable button.
        6. You can safely ignore the warning: To use this API, you may need credentials. Click 'Create credentials' to get started.
      • If both of the above fail, you can try the nuclear route and recreate your spreadsheet/doc/script whatever.
  2. Next, enable Google Calendar API for the script:

    1. Back in your script, Resources > Advanced Google services
    2. Hit "On" next to Google Calendar API.

      You're now ready to use the advanced API in a script.

With those prerequisites out of the way, you can now create a function:

// Note: requires advanced API
function addGuestAndSendEmail(calendarId, eventId, newGuest) {
  var event = Calendar.Events.get(calendarId, eventId);
  var attendees = event.attendees;
  attendees.push({email: newGuest});

  var resource = { attendees: attendees };
  var args = { sendUpdates: "all" };

  Calendar.Events.patch(resource, calendarId, eventId, args);
}

Some caveats:

  1. When you pass an eventId, you will need to remove the @google.com at the end of the eventId.
  2. You must call get first to get the current list of invitees. If you don't, you'll accidentally remove all the people that were on the event originally. See this answer for more info.

    Note: patch is smart and will only send email updates to the people that were actually added. E.g. if the current people on an event are [alice, bob], and you send a patch with [alice, bob, charlie], only charlie will receive an email. This is exactly what you want!

  3. All the previous caveats in the list above apply.

Again, the key is knowing how to pass in sendUpdates to the insert() method. I couldn't find any documentation about the patch method1, but the auto-complete revealed that there is an optionalArgs parameter that can be added. I randomly tried the format you see above, and it worked!

If it's not working, make sure you read all caveats above.

Note: I'm glad this worked with Google's API, because if it didn't, it likely meant needing to manually send the email(s), and look into how to add calendar metadata to a message so that Gmail parses it properly.


1 We have the general patch API, but this is only useful when sending the raw JSON. We're using Google's Calendar wrapper, which doesn't map exactly the same.