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 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
- Invite Links for Google Calendar
- Invite Links for Microsoft Outlook
- URL Encoding
- Time Zones
- Add Invite Links to Email Templates
- Resources
π Invite Links for Google Calendar
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

π Invite Links for Microsoft Outlook
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
- GitHub: InteractiveDesignFoundation/add-event-to-calendar-docs
- Google Calendar Help: Add a Google calendar to your website
- Kalinka: Make a link for Google Calendar
- AddEvent: Add to Calendar button
- StackOverflow: Link to add all day event to Google Calendar
- Wikipedia: Timezone Abbreviations
- Formula Functions: URLENCODE
- Apex Developer Guide: EncodingUtil
- Trailhead: Manage Your Tasks, Events, and Email
- Documentation: Email Templates in Lightning Experience
Hi, Douglas – great info! I’m trying to get this to work for Office365 but doesn’t seem to pick up the parameters for Title, etc. Using this as my base URL: https://outlook.office365.com/calendar/action/compose#subject=My+Title&body=My+Description&location=My+Location&startdt=20191119T000000-0600&enddt=20191122T000000-0600&allday=true
LikeLiked by 1 person
Hi Randy,
The format of your URL is incorrect. It must be https://outlook.live.com/owa/?path=/calendar/action/compose# per the instructions.
Your domain, the βoutlook.live.comβ, might be different with a business Office365 account, but the rest of the URL likely must be what Iβve shared.
LikeLike
Hi Douglas,
Great tutorial, but I can’t seem to get the html tag to output correctly on the HTML template, it’s showing the full url instead of the hyoerlink shortlink, ie. calendar,google.com/…. instead of Add to Google Calendar. Any suggestions?
Jose
LikeLiked by 1 person
Hi JosΓ©,
What HTML markup have you tried?
For links, you use the <a> tag. Learn more at W3 Schools.
Doug
LikeLike
Also, comments on my site support markdown so they try to render HTML. To share your code without it being rendered as HTML then put the code in a code block.
LikeLike
I’ve used the tag but the html doens’t render properly when I send the test email. It renders with the entire tag showing up.
LikeLike
Email Templates have two content sections, the HTML Body and the Plain Text Body. Make sure your HTML content is only in the HTML Body of the email template.
The recipient of the email, their email program will determine if they see the HTML vs. Plain Text version of your email.
Make sure your link tag looks like:
Beyond that, you’re really just troubleshooting Email Templates and HTML code and not how to create the link for adding a calendar invite. If you still have issues, I recommend reaching out to one of the groups on the Trailblazer Community or Salesforce Support.
Good luck!
LikeLike
the a tag
LikeLike
Hi Douglas
This link will open calendar in outlook web app, can i enforce it to open with o365 by default ?
LikeLiked by 1 person
Hi Chetna, I donβt know what the difference is between outlook web app and office 365.
LikeLike
Hi Douglas
I want the code for “Add to calender” functionality in salesforce or detailed procedure.
I want to do it using a template
LikeLike
Hi Douglas,
Thank you for this code but I am not sure if I truly understand how this works. When I set this up it takes me to the Microsoft OWA website and asks me to log in or create an account. I presume this would also not work as a normal meeting invite where the recipient would accept of decline the invite?
In the end I am looking to be able to add a “Add to Calendar” button on an email that I can send to customers. Should this process above work in that way?
Nick
LikeLike
Will this solution take Daylight Savings time into account? Or does the previously published solution take Daylight Savings time into account?
LikeLiked by 1 person
Hi Kelly, if you specify the date/times in UTC then I would hope the userβs calendaring system would adjust for whatever time zone they use when they open the event.
LikeLike
Hi Doug, thanks for the instruction. I tried to use the Outlook link, it opened my calendar in web but did not populate the parameters as expected. Do you know if this is still supported in Outlook?
LikeLiked by 1 person
Hi Jackie, did you find a solution for this? I’m having the exact same problem. Thanks in advance for the help
LikeLike
Hi Doug, same with Jackie, I too find myself stuck with getting the fields to populate on outlook, but works great on Google.
LikeLike
Hi Doug. Have you tested outlook links? They don’t seem to be working. Outlook only opens a new event but does not populate the parameters provided.
LikeLike
This one seem to work
https://outlook.live.com/owa/?path=/calendar/action/compose&rru=addevent&startdt=2018-05-24T12%3A00%3A00-05%3A00&enddt=2018-05-24T12%3A30%3A00-05%3A00&subject=Test One&body=Test Body
LikeLiked by 1 person
Hi Doug,
Nice article and I was able to get new calendar invite functionality going through your code. Thank you for helping me with your experience.
However, I was not able to cancel existing meetings through my SF emails.Please suggest a way to cancel an existing meeting that can be automated through SF?
LikeLike
Awesome!!! Might be helpful to add that ‘%0A’ will add a line break if required in the description. Was a requirement from our business in sending these out. Thanks!
LikeLike
Maneaged to make it work in the web but not in the outlook app. Any advice?
LikeLike
I’m trying to use this formula in Flow, but I keep getting an error message that says: The formula expression is invalid: Syntax error. Found ‘/’. This is my formula: https://calendar.google.com/calendar/r/eventedit?text={!URLENCODE(EmployeeEventName)}&details={!URLENCODE(AdmissionsEmailBody)}&location={!URLENCODE(Admissions_Location)}&dates= {!URLENCODE(Admissions_Time)}/{!URLENCODE(Admissions_Time)}
What am I doing wrong?
LikeLike
Hi Doug,
This was really helpful. However, could you please correct and what we are doing here. We have an email alert that gets sent from a custom object. We are only assigning the date for the follow-up action. No timing is set. We just need to set it as an all-day event but can’t seem to do it.
The date doesn’t seem to populate correctly, here’s the code snippet we are using
Add To Google Calendar
And for the outlook instead of opening the outlook site is it possible to direct to the Calendars tab in the Outlook application itself. As most of our users use the outlook application instead and may not have actual email on Microsoft, but different email client set on the outlook
LikeLike
here’s the code
https://calendar.google.com/calendar/r/eventedit?text=!URLENCODE(Interaction_Log__c.Name)&details=
{!URLENCODE(Interaction_Log__c.Related_To_Aircraft__c)}&dates={!Interaction_Log__c.Follow_Up_Due_Date__c}&allday=true
I added with the tag earlier, sorry about that
LikeLike
In this case, are we sending an email with the link where the user has to click to accept the meeting right? Not directly the meeting invite. Please confirm.
LikeLiked by 1 person
Hi, Doug
I am trying to add an outlook live event to my clients calendar on click of a button.
Which works fine for smaller event description
But when Iβm trying to get this to work for longer length of description as much as 1000+ characters, it breaks
Using this URL:
“https://outlook.live.com/owa/?path=/calendar/action/compose&rru=addevent&startdt=2021-08-20T22:00:00Z&enddt=2021-08-21T02:00:00Z&subject=test+add+to+outlook+long+event+description&body=fdsgfdksbng%3Cbr%2F%3Efjds+gjf%3Cbr%2F%3EdAJGLFDSJGLFDSLGNFKL+DSBNKL+FDsk+fj+jh.+%3Cbr%2F%3E+%3Cbr%2F%3E0881293340+1976681527+0936259047+9715502401+6481451133+3056138569+7677935584+8645095099+0721622489+0657023175+1733104983+1599522550+1472955612+6819228442+2264777794+6271429944+8354641062+9700918986+%3Cbr%2F%3Esgfjhf%3Cbr%2F%3Ehbfsjk++fdsgfdksbng%3Cbr%2F%3Efjds+gjf%3Cbr%2F%3EdAJGLFDSJGLFDSLGNFKL+DSBNKL+FDsk+fj+jh.+%3Cbr%2F%3E+%3Cbr%2F%3E0881293340+1976681527+0936259047+9715502401+6481451133+3056138569+7677935584+8645095099+0721622489+0657023175+1733104983+1599522550+1472955612+6819228442+2264777794+6271429944+8354641062+9700918986+%3Cbr%2F%3Esgfjhf%3Cbr%2F%3Ehbfsjkfdsgfdksbng%3Cbr%2F%3Efjds+gjf%3Cbr%2F%3EdAJGLFDSJGLFDSLGNFKL+DSBNKL+FDsk+fj+jh.+%3Cbr%2F%3E+%3Cbr%2F%3E0881293340+1976681527+0936259047+9715502401+6481451133+3056138569+7677935584+8645095099+0721622489+0657023175+1733104983+1599522550+1472955612+6819228442+2264777794+6271429944+8354641062+9700918986+%3Cbr%2F%3Esgfjhf%3Cbr%2F%3Ehbfsjk++fdsgfdksbng%3Cbr%2F%3Efjds+gjf%3Cbr%2F%3EdAJGLFDSJGLFDSLGNFKL+DSBNKL+FDsk+fj+jh.+%3Cbr%2F%3E+%3Cbr%2F%3E0881293340+1976681527+0936259047+9715502401+6481451133+3056138569+7677935584+8645095099+0721622489+0657023175+1733104983+1599522550+1472955612+6819228442+2264777794+6271429944+8354641062+9700918986+%3Cbr%2F%3Esgfjhf%3Cbr%2F%3Ehbfsjk%3Cbr%2F%3E%3Cbr%2F%3Efdsgfdksbng%3Cbr%2F%3Efjds+gjf%3Cbr%2F%3EdAJGLFDSJGLFDSLGNFKL+DSBNKL+FDsk+fj+jh.+%3Cbr%2F%3E+%3Cbr%2F%3E0881293340+1976681527+0936259047+9715502401+6481451133+3056138569+7677935584+8645095099+0721622489+0657023175+1733104983+1599522550+1472955612+6819228442+2264777794+6271429944+8354641062+9700918986+%3Cbr%2F%3Esgfjhf%3Cbr%2F%3Ehbfsjk++fdsgfdksbng%3Cbr%2F%3Efjds+gjf%3Cbr%2F%3EdAJGLFDSJGLFDSLGNFKL+DSBNKL+FDsk+fj+jh.+%3Cbr%2F%3E+%3Cbr%2F%3E0881293340+1976681527+0936259047+9715502401+6481451133+3056138569+7677935584+8645095099+0721622489+0657023175+1733104983+1599522550+1472955612+6819228442+2264777794+6271429944+8354641062+9700918986+%3Cbr%2F%3Esgfjhf%3Cbr%2F%3Ehbfsjkfdsgfdksbng%3Cbr%2F%3Efjds+gjf%3Cbr%2F%3EdAJGLFDSJGLFDSLGNFKL+DSBNKL+FDsk+fj+jh.+%3Cbr%2F%3E+%3Cbr%2F%3E0881293340+1976681527+0936259047+9715502401+6481451133+3056138569+7677935584+8645095099+0721622489+0657023175+1733104983+1599522550+1472955612+6819228442+2264777794+6271429944+8354641062+9700918986+%3Cbr%2F%3Esgfjhf%3Cbr%2F%3Ehbfsjk++fdsgfdksbng%3Cbr%2F%3Efjds+gjf%3Cbr%2F%3EdAJGLFDSJGLFDSLGNFKL+DSBNKL+FDsk+fj+jh.+%3Cbr%2F%3E+%3Cbr%2F%3E0881293340+1976681527+0936259047+9715502401+6481451133+3056138569+7677935584+8645095099+0721622489+0657023175+1733104983+1599522550+1472955612+6819228442+2264777794+6271429944+8354641062+9700918986+%3Cbr%2F%3Esgfjhf%3Cbr%2F%3Ehbfsjk%3Cbr%2F%3E&location=”
Is there any limit to the length?
LikeLike
The maximum number of characters in the URI seems to be 2048 characters.
LikeLiked by 1 person