UPDATE: A new solution is available.
To skip the backstory and jump straight to the solution, click here. Otherwise, read on!
At my company, we have a custom object with start and end datetime fields which represent a window of time some work will be done, such as an IT implementation like a server upgrade. These records get submitted for approval then completed by the users on or around the scheduled dates. Since the work request may not occur for a few days in the future, people began asking for the system to remind them that they were coming due. Ideally, they wanted to see where these events fit into their normal work calendar (e.g. Outlook).
There are multiple ways in Salesforce to provide a reminder, I’ll detail the ones we considered:
- Workflow Rule with Timed-Dependent Email Alert some hours before start date
- Trigger or Flow to create a Salesforce Event related to the object and use its reminder feature (i.e. leverage Salesforce’s calendar system)
- Approval Process Email Alert Action that includes iCal attachment users can, if desired, add to any calendar (i.e. delegate to whatever calendar system the recipient desires to use)
I opted for option 3, here’s why:
- Timed email alert assumes all users wanted to receive the reminder, which wasn’t the case for us. People wanted the option to receive the reminder or not. Also, the events still wouldn’t show on the employee’s work calendars. I also didn’t want to clutter the page layout by adding a checkbox field purely to indicate if the person wanted a reminder email or not.
- Trigger or Flow to create Salesforce Events has same problem, not everyone wanted to be reminded. This also involved more development than I wanted to put into the solution. Benefit though, since our company uses Office 365, if users had Salesforce for Outlook add-in installed then these events would have auto-synced to their Outlook calendar.
- Since the users doing the work already get an email alert as soon as the record gets approved, rather than sending users another email like option 1, we can piggy back on this email by including an iCal attachment with it. Now anyone can choose whether to add the event to their work calendar (e.g. Outlook or Gmail) and setup any reminder settings they wish, if any at all!
The Solution
Create a new Visualforce Email Template (Setup | Communication Templates | Email Templates). This allows us to use the <messaging:attachment> tag to define arbitrary content as an attachment in the email. In our case, we will use iCal markup to define a calendar event.
Configure the email template like normal (subject, recipient, relatedTo, body) then at the bottom add <messaging:attachment filename=”reminder.ics”> and closing tag </messaging:attachment>. Between the two attachment tags, include the iCal markup to define your event as shown in this gist. This actually builds off a previous proof-of-concept I had done several months ago for @gnatrae, you can read the conversation thread on twitter.
(note, to simplify and make the example more globally accessible, I’m using standard Opportunity and its CloseDate field instead in the sample code)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<messaging:emailTemplate subject="Close Opportunity" | |
recipientType="User" | |
relatedToType="Opportunity"> | |
<messaging:htmlEmailBody > | |
<html> | |
<body> | |
Opportunity: <a href="https://test.salesforce.com/{!relatedTo.id}"><apex:outputText value="{!relatedTo.name}"/></a> | |
<br/> | |
<!– | |
Visualforce dateformat trick, put a whitespace character before the date expression and it will format in org's locale, not GMT | |
https://douglascayers.com/2014/05/27/salesforce-displaying-datetime-field-in-visualforce-in-users-timezone/ | |
–> | |
Close Date: <apex:outputText value=" {!relatedTo.CloseDate}"/> | |
<br/> | |
</body> | |
</html> | |
</messaging:htmlEmailBody> | |
<messaging:attachment filename="reminder.ics"> | |
BEGIN:VCALENDAR | |
METHOD:PUBLISH | |
VERSION:2.0 | |
PRODID::-//hacksw/handcal//NONSGML v1.0//EN | |
BEGIN:VEVENT | |
ORGANIZER:mailto:{!recipient.Email} | |
DTSTAMP;TZID=GMT:<apex:outputText value="{0,date,yyyyMMdd'T'HHmmssZ}"><apex:param value="{!relatedTo.CloseDate}"/></apex:outputText> | |
UID:<apex:outputText value="{!relatedTo.id}"/> | |
DTSTART;TZID=GMT:<apex:outputText value="{0,date,yyyyMMdd'T'HHmmssZ}"><apex:param value="{!relatedTo.CloseDate}"/></apex:outputText> | |
DTEND;TZID=GMT:<apex:outputText value="{0,date,yyyyMMdd'T'HHmmssZ}"><apex:param value="{!relatedTo.CloseDate}"/></apex:outputText> | |
SUMMARY:<apex:outputText value="Close Opportunity {!relatedTo.name}"/> | |
DESCRIPTION:<apex:outputText value="{!JSENCODE(relatedTo.description)}" escape="false"/>\n\n<apex:outputText value="https://test.salesforce.com/{!relatedTo.id}" escape="false"/> | |
BEGIN:VALARM | |
TRIGGER:-PT1D | |
ACTION:DISPLAY | |
DESCRIPTION:Reminder | |
END:VALARM | |
END:VEVENT | |
END:VCALENDAR | |
</messaging:attachment> | |
</messaging:emailTemplate> |
Now, test and preview the email and send it to yourself. You should have a reminder.ics attachment like this:
Double-click the attachment and it opens up in your Outlook calendar, yippee!
Google Calendar
If you want to integrate with Google Calendar, check out Raviteja Vaddi‘s post at https://teamforcesite.wordpress.com/2016/05/18/creating-google-calender-events-from-salesforce-without-integartion/.
This is very cool! And VERY useful! Great job!
LikeLiked by 1 person
Thanks!
LikeLike
How to add it to Google Calendar?
LikeLike
Thanks for the post, works well!
One issue I have is that the invite is not recognised by Gmail as a valid calendar invite. So normally, gmail sees an attached invite and gives an option to “Add to Calendar”. However, in this instance the attachment is there but gmail doesn’t “see” it as an invite.
Any idea how to fix this?
Thanks
LikeLiked by 1 person
Hi Ben,
Thanks for the feedback. To be honest, I haven’t tried this with Gmail yet, only Outlook. I’ll have to do some more research and follow up, though not sure when I’ll have time to get to it.
Thanks!
LikeLike
No worries Doug. Let us know how you go!
LikeLike
you are my favorite person right now
LikeLiked by 1 person
Hi Alex, glad to have been of service!
LikeLike
Hi Doug,
We are facing a similar issue where the email invite sent from Salesforce is not converted in Gmail’s standard format where the user can view the standard buttons ‘Yes, Maybe, No’ in the invite itself.
Instead the email invite is sent as an attachment ‘meeting.ics’. The user is not using Outlook so they can’t open the attachment in their laptop / desktop.
Is there anyway, we can control in Salesforce to ensure when we send an email invite from Salesforce to Gmail, the invite is viewed as standard email invite where we can view the buttons ‘Yes, maybe, no’ in the invite itself?
This is very critical for go-live of our customer and any inputs / pointers in this regard / matter will be highly appreciated.
Thank you,
Krishna
LikeLiked by 1 person
I’ve received a lot of positive feedback on this post, and one of the biggest questions is how to support Gmail. I haven’t had the time to dig into this, but I have come across another service, “Add This Event” https://addthisevent.com/, that provides an API and buttons to integrate with many of the popular calendar services. This may be a good avenue to pursue if you’re needing Gmail integration.
Thanks!
LikeLike
FYI, if anyone using this wants the attachment to come through as an all-day event in Outlook, I was able to do so using the following:
DTSTART;VALUE=DATE:
DTEND;VALUE=DATE:
In short, replace DTSTART;TZID=GMT: with DTSTART;VALUE=DATE: for the start and end
LikeLiked by 1 person
Great post Doug – regarding Gmail, things look much simpler than iCal! Check out the google docs on microdata markup into your visualforce or html templates https://developers.google.com/gmail/markup/getting-started#your_first_markup
LikeLiked by 1 person
Thanks, Carl! I’ll have to try that out! Do you already have any examples to share using visualforce?
LikeLike
Sorry for delay responding – no working samples yet 🙂
LikeLike
For GMail / Google Calendar integration, check out Raviteja Vaddi‘s post at https://teamforcesite.wordpress.com/2016/05/18/creating-google-calender-events-from-salesforce-without-integartion/. This looks promising!
LikeLike
Awesome article!!
LikeLiked by 1 person
Thanks for the kind feedback, Shekhar!
LikeLike
Hi,
I’m in the process of debugging my meeting invite code where everything seems to be functional minus this code block. The message does get sent, can be read but when i go to open the meeting invite, outlook spits out a general error message. Can you help me figure out how to fix it?
BEGIN:VCALENDAR
VERSION:2.0
PRODID::-//hacksw/handcal//NONSGML v1.0//EN
BEGIN:VEVENT
DTSTAMP;TZID=GMT:
UID: {!relatedTo.id}
DTSTART;TZID=GMT:
DTEND;TZID=GMT:
SUMMARY: Upcoming WI Conference – {!relatedTo.name}
DESCRIPTION:{!relatedto.Name} occurs during “{!relatedto.Conference_Start__c}” and “{!relatedTo.Conference_End__c)”
BEGIN:VALARM
TRIGGER:-PT1D
ACTION:DISPLAY
DESCRIPTION:Reminder
END:VALARM
END:VEVENT
END:VCALENDAR
LikeLiked by 1 person
Hello,
Could you provide a gist (https://gist.github.com/) of your visualforce email template?
What error message are you receiving?
Thanks,
Doug
LikeLike
In the VCALENDAR snippet you provided, the
DESCRIPTION
line includes a typo with“{!relatedTo.Conference_End__c)”
. AfterEnd__c
it should be a}
instead of)
.When I tried to copy & paste that example into my visualforce email template the page wouldn’t save it because of the syntax error. Is that your error?
LikeLike
Hi,
I am not able to open the attachment after double click please help
LikeLike
Hi Surbhi, that sounds like it may be an issue with your email client and not necessarily what this blog post is covering.
How are you accessing your email? Can you provide link to screen shots?
LikeLike
Hey Doug, I am unable to open .ics file in lotus notes, Any specific constraints?
LikeLiked by 1 person
Not sure, I don’t have Lotus Notes to test with, sorry.
LikeLike
Thanks for you response.
I tried but facing below error:
Notes cannot process your fle. The content of this URL does not conform to the icalendar parsing specifications.
Any idea?
LikeLiked by 1 person
Hi Deepak,
Unfortunately, no. I don’t have Lotus Notes to test with so not sure what part of the iCal message being generated it doesn’t like. I have had no issues with GMail or Outlook.
I’m also sorry you have to use Lotus Notes… =(
Doug
LikeLike
Hi @Doug Ayers,
I am implementing the same scenario in my current project but there is one thing i am still stuck up with, how to update the meeting invite of on record the user changes something.
Thanks,
Shishir
LikeLiked by 1 person
Hi Shishir,
My (limited) understanding of iCalendar is that per RFC2445 if a calendar program processes multiple events with the same UID property then the subsequent events should be treated as updates, not new events.
Therefore, I would think if the first email with the .ics attachment is received by a user and they add the event to their calendar then if they receive a second email with an updated .ics attachment but which specifies the same UID then when that second email’s event is added to their calendar then the calendar program would update the event in the calendar.
Hope that helps!
Doug
LikeLike
Hi Doug,
I achieved the scenario 🙂 thanks for replying back
Kind Regards,
Shishir
LikeLiked by 1 person
Its not working in my case, showing me error in outlook: “The operation failed”
LikeLike
Hi,
Is there a way where we can send outlook meeting invite directly without an attachment and the person should be able to accept or decline?
Or else even if we send it as an attachment the user should be able to accept it.
LikeLiked by 1 person
Hi Manoj,
Good question, I’m not sure. For the purposes of this exercise I just needed to get an .ics attachment and then our users would open it in Outlook and accept that way.
LikeLike
Doug,
Any chance we can make this a group meeting invite, as opposed to a single event on one person’s calendar?
I’d like to send this to a few folks at a time, via Email Alerts in the process builder. But I want everyone to know who has accepted the invitation for the event.
Any thoughts on how to do this?
LikeLiked by 1 person
Reading the calendar spec it seems possible but not sure when I’ll have time to try it out. Nice idea!
LikeLike
Doug, Thanks for the great article. It just finished using your experience for my own! One issue I’m having though is getting the start and end time of the meeting event set properly. The time between the two events is showing up properly in the ical attachment, but the start time is WAY off. The meeting should start at 1:18 pm but the ical is displaying the start time as 8:18 am. In your code, you mention a trick of adding a white space before the date expression to automatically set the event to the user’s locale. Where exactly would you put that white space?
My object has two fields, one DATE type for the Start Date, one TIME type for the Start Time. I combined those values into a formula field called StartDateTime and use that formula field in my VF email template. The formula field generates something like this:
2018-05-25T16:44:00.000Z
My VF email template uses lines like:
DTSTART;TZID=GMT:
DTEND;TZID=GMT:
The date displays properly in the event attachment, but the time starts 7 hours early. Any ideas what I’m doing wrong?
LikeLiked by 1 person
Hi Ryan,
The single whitespace trick is not pertinent to the email .ical format, it was just for outputting the date in the Visualforce page to the user to auto-format to their timezone/locale. That is done one line 16 of the code snippet in the post. There is a whitespace between
value="
and{!relatedTo
.My guess why your .ical values are off-timezone is because the date/time value is a combination of a Date field and a Time field. Time fields do not store a time zone with them, they “just are” whatever hour specified them to be. So context must provide the timezone. In .ical code snippet, when you use DTSTART;TZID=GMT: then you are saying that whatever date/time text that follows is in the GMT time zone. The day and hour that the email recipient will see in their calendar will be that GMT time offset by the recipient’s time zone.
For example, if your .ical code sends me:
DTSTART;TZID=GMT:2018-05-25T16:44:00.000Z
then because I’m in Central time zone then I will see that value adjusted -6 hours, so 10am rather than 4pm.
If you are using separate Date and Time fields, then in your formula that combines them then you need to either (a) adjust the value based on the time zone the Time field is assumed to represent, or (b) adjust the TZID value in the .ical code snippet to be the time zone that the Time field represents.
LikeLike
Hey Doug,
Were you able to send the meeting invite directly to outlook not as attachment. Could you please share if there is any update.
Thanks.
LikeLiked by 1 person
I only used the .ical Visualforce attachment trick. I have not tried anything else.
LikeLike
Hi Doug,
Thanks for the great post!! I have a very strange issue though. With the same code, I am getting “Add to Calendar” link in all other Mail systems like Gmail, icloud except Outlook:-(. Just getting the text email, reminder.ics is missing from the attachment. I am checking outlook configuration if somehow the attachments are getting filtered. Please suggest, if there is anything I could check.
Thanks,
Vaishali
LikeLiked by 1 person
Hi Vaishali, I’m glad you like the post, thank you for your kind feedback!
Unfortunately, I do not know why Outlook is not showing your reminder.ics attachment. Perhaps there is a mail setting that is stripping out attachments? I know some companies prevent .exe attachments.
LikeLike
Thanks, this is helpful!
LikeLiked by 1 person
Glad you like it, Bobby!
LikeLike
Great solution Doug….as always!
LikeLiked by 1 person
Thanks, Bryan!
LikeLike
Hi Doug,
On opening the reminder.ics fiel after downloadig, I am getting an error, that says -“The file is invalid.” Can you suggest any ways i can fix this?
LikeLike