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:

  1. Workflow Rule with Timed-Dependent Email Alert some hours before start date
  2. Trigger or Flow to create a Salesforce Event related to the object and use its reminder feature (i.e. leverage Salesforce’s calendar system)
  3. 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:

  1. 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.
  2. 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.
  3. 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)

<messaging:emailTemplate subject="Close Opportunity"
<messaging:htmlEmailBody >
Opportunity: <a href="https://test.salesforce.com/{!relatedTo.id}"><apex:outputText value="{!relatedTo.name}"/></a>
Visualforce dateformat trick, put a whitespace character before the date expression and it will format in org's locale, not GMT
Close Date: <apex:outputText value=" {!relatedTo.CloseDate}"/>
<messaging:attachment filename="reminder.ics">
PRODID::-//hacksw/handcal//NONSGML v1.0//EN
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"/>

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/.