Many years ago, before the modern age of using online calendars provided by products like G-Suite and Office 365, I blogged about how to send calendar invites as attachments using Visualforce email templates.

The old solution using Visualforce attachments

The solution worked ok at the time for my company. Back then, we didn’t use online calendar programs, but rather had Microsoft Outlook installed on our desktop machines. We were able from our inbox to open the .ics attachment in Outlook and it implicitly understood how to add it to the calendar.

But times have changed. And although the need for sending calendar invites through email remains, the calendar programs we use and how we format those invites can be much simpler. Read: no attachments or Visualforce needed. Nowadays, we can provide links to our calendar service of choice.

Table of Contents

Start with the base url https://calendar.google.com/calendar/r/eventedit? then append one or more of the following parameters.

Parameter Description
text Event title.
details Event description.
location Event location.
dates Event start and end date/times.

Use YYYYMMDDTHHmmSSZ format.

Separate the start date/time from the end date/time with a /.

For all day events, use the YYYYMMDD format (no time). Depending on the recipient’s time zone, you may need to shift the start or end date by 1 day. Your mileage may vary.
ctz Event timezone. Can specify an hour offset, like -0600, or a time zone abbreviation, like CDT, if your dates are not in UTC time zone.
uid Event unique identifier.

Examples

These examples start on November 19th, 2019 at 8:00 AM Central Time through November 22nd, 2019 at 5:00 PM Central Time.

Example 1: This first example specifies the times in UTC.

https://calendar.google.com/calendar/r/eventedit?
text=My+Title
&details=My+Description
&location=My+Location
&dates=20191119T140000Z/20191122T230000Z

Example 2: This is the same example but this time explicitly specifying the time zone offset for Central Standard Time (UTC-0600).

https://calendar.google.com/calendar/r/eventedit?
text=My+Title
&details=My+Description
&location=My+Location
&dates=20191119T080000/20191122T170000
&ctz=CST

Example 3: This is the same example but this time specifying the event is all day. I needed to shift the end date to the next day to render correctly. Depending on the recipient’s time zone, you may need to shift the start or end date by 1 day. Your mileage may vary.

https://calendar.google.com/calendar/r/eventedit?
text=My+Title
&details=My+Description
&location=My+Location
&dates=20191119/20191123

Start with the base url https://outlook.live.com/owa/?path=/calendar/action/compose# then append one or more of the following parameters.

Parameter Description
subject Event title.
body Event description.
location Event location.
startdt Event start date/time.

Use YYYYMMDDTHHmmSSZ format.
enddt Event end date/time.

Use YYYYMMDDTHHmmSSZ format.
allday Is event all day? Specify true or false.

Depending on the recipient’s time zone, you may need to adjust the start or end date/time. Your mileage may vary.
uid Event unique identifier.

Examples

These examples start on November 19th, 2019 at 8:00 AM Central Time through November 22nd, 2019 at 5:00 PM Central Time.

Example 1: This first example specifies the times in UTC.

https://outlook.live.com/owa/?path=/calendar/action/compose#
subject=My+Title
&body=My+Description
&location=My+Location
&startdt=20191119T140000Z
&enddt=20191122T230000Z
&allday=false

Example 2: This is the same example but this time explicitly specifying the time zone offset for Central Standard Time (UTC-0600).

https://outlook.live.com/owa/?path=/calendar/action/compose#
subject=My+Title
&body=My+Description
&location=My+Location
&startdt=20191119T080000-0600
&enddt=20191122T170000-0600
&allday=false

Example 3: This is the same example but this time specifying the event is all day. I needed to specify my time zone in the start/end dates to render correctly. Depending on the recipient’s time zone, you may need to shift the start or end date, too. Your mileage may vary.

https://outlook.live.com/owa/?path=/calendar/action/compose#
subject=My+Title
&body=My+Description
&location=My+Location
&startdt=20191119T000000-0600
&enddt=20191122T000000-0600
&allday=true

πŸ”— URL Encoding

If your parameter values contain spaces or special characters they need to be encoded so that the url is valid.

Salesforce provides the URLENCODE function in formula fields and email templates. For example, {!URLENCODE(MyTextField__c)}.

In Apex you can use the EncodingUtil.urlEncode() method. For example, EncodingUtil.urlEncode( evt.Description, 'UTF-8' );

🌎 Time Zones

When referencing date/times in formula fields and in Apex, Salesforce provides you the values in UTC time zone. ⏰

Thankfully, both Google Calendar and Microsoft Outlook will automatically, and conveniently, convert the date/time from your link to the recipient’s local time zone per their calendar’s settings. πŸ™Œ

So whenever possible, standardize on putting your date/times in UTC.

πŸ“§ Add Invite Links to Salesforce Email Templates

Now that you know the URL formats for adding events to Google Calendar and Microsoft Outlook, it’s time to begin using them in your Salesforce email templates.

I recommend adding formula fields on your objects you’ll be sending emails from to make it easier to create the links. I’ve included some formulas that you might find helpful.

Calculate Event Start Date Time in UTC

Given an event start time of November 19th, 2019 at 8:00 AM CST, this formula will output 20191119T140000Z.

TEXT( YEAR( ActivityDate ) ) &
LPAD( TEXT( MONTH( ActivityDate ) ), 2, '0' ) &
LPAD( TEXT( DAY( ActivityDate ) ), 2, '0' ) &
'T' &
LPAD( TEXT( HOUR( TIMEVALUE( ActivityDateTime ) ) ), 2, '0' ) &
LPAD( TEXT( MINUTE( TIMEVALUE( ActivityDateTime ) ) ), 2, '0' ) &
LPAD( TEXT( SECOND( TIMEVALUE( ActivityDateTime ) ) ), 2, '0' ) &
'Z';

Calculate Event End Date Time in UTC

Events in the Salesforce UI let the user select a start and end time. But in the database, it stores only the ActivityStartTime and a DurationInMinutes. To calculate the end date/time, we need to do some math.

Given an event start time of November 19th, 2019 at 8:00 AM CST and a duration of 540 minutes (9 hours.. until 5:00 PM) this formula will output 20191119T230000Z.

/* 1440 minutes in a day */
TEXT( YEAR( ActivityDate + DurationInMinutes / 1440 ) ) &
LPAD( TEXT( MONTH( ActivityDate + DurationInMinutes / 1440 ) ), 2, '0' ) &
LPAD( TEXT( DAY( ActivityDate + DurationInMinutes / 1440 ) ), 2, '0' ) &
'T' &
LPAD( TEXT( HOUR( TIMEVALUE( ActivityDateTime + DurationInMinutes / 1440 ) ) ), 2, '0' ) &
LPAD( TEXT( MINUTE( TIMEVALUE( ActivityDateTime + DurationInMinutes / 1440 ) ) ), 2, '0' ) &
LPAD( TEXT( SECOND( TIMEVALUE( ActivityDateTime + DurationInMinutes / 1440 ) ) ), 2, '0' ) &
'Z';

Lastly, put it all together:

https://calendar.google.com/calendar/r/eventedit?text={!URLENCODE(Event.Subject)}&details={!URLENCODE(Event.Description)}&location={!URLENCODE(Event.Location)}&dates={!Event.Start_Date_Time_UTC__c}/{!Event.End_Date_Time_UTC__c}

πŸ“š Resources