Skip to Content
Technical Articles
Author's profile photo Chris Stiles

Dressing up your VCAL in LMS

Introduction

Many years ago (more than I care to count), I was in a role where I managed blended learning programs.  This would include sending out calendar invites to all the participants I was expecting to attend.   In my somewhat bias opinion, they were well written and communicated the necessary information.  Nothing fancy, but easy to read and to the point.  On average, there were 75 people on the “required” list, and maybe 40 or so would show up.  I would then be left to reach out to the absentees, find out why they didn’t attend, and develop a plan to catch up.

One day, I decided to dress the invites up a little by adding a banner image across the top.  The image was of a conference room table and some chairs, one of which was pulled out from the table, turned towards the viewer.  It had a caption … “We’ve saved a seat for you!”.

An interesting thing happened.  Upon sending out this newly dressed up invite, I immediately started getting responses.

“Thank you for saving me a seat, but I have a conflict today, when can I make this up?”

“Thank you for thinking of me, I’ll be OOO that day.”

“Unfortunately, I’ll be on Jury Duty next week”.

Seldom would people proactively tell me that they were unable to attend a class.  Having advance notice meant I could better set the instructors expectation on the number of attendees and certainly saved me a lot of time in follow up work, and was greatly appreciated.  Clearly, the decision to dress up my calendar invites prompted a different (and positive) behavior in our learners.

In this blog, I’ll describe at a high level, how to modify the VCAL entry to support HTML in SuccessFactors LMS. This will allow you to dress up your calendar invites, and hopefully have the same positive experience I did.

Getting down to the details

How do I know what notification to use, if it has options for a VCAL, and what Tokens I can use?

The first stop is SAPs Help Portal.  Specifically the “Template ID to Trigger to Receiver Map” found here.  I’ve always found this a helpful tool to determine what templates there are, when they are triggered, and who gets them.

Once you’ve identified the template you think you’d like to use, you can check if it has a VCAL option by looking the template up under System Administration » Manage Email » Email Notification Templates.  When you’ve opened the template, check the Messages tab.  If there is a Message ID labelled “VCAL”, you’ve got yourself a winner !

NOTE:  We will not be using the WYSIWYG editor in these instructions.  The code we are looking at, and will be setting, is in the VCAL Message field, as seen below.

 

VCAL%20Message%20ID

VCAL Message ID

What syntax Tags are supported?

For a complete list of Syntax Tags that are supported in notifications, first check

System Administration » Manage Email » Email Notification Templates

Search for (and view) the notification that has the VCAL you are modifying.  On the Summary tab, there is a Token Set ID.

For example, the SystemEnrollmentNotification templates, uses the ENROLLMENT token set.

Now that you have the Token set ID, lets take a look at what tokens are available.

System Administration » Manage Email » Email Notification Token Sets

There is a limited amount of Tokens sets, so there is no Search Selector for them.  You may need to expand your list to show all, or page through until you find ENROLLMENT.   View the token set to get a complete list of available tokens.

The Defaults

Lets take a look at the default configuration.

BEGIN:VCALENDAR
METHOD:REQUEST
<LOOP>
BEGIN:VEVENT
UID:<ESCAPEFORVCAL value="<&VCAL_UID>"/>
SEQUENCE:<ESCAPEFORVCAL value="<&VCAL_SEQUENCE>"/>
ORGANIZER:<ESCAPEFORVCAL value="<&VCAL_ORG>"/>
SUMMARY:<ESCAPEFORVCAL value="<&VCAL_SUM>"/>
LOCATION:<&VCAL_LOCN>
DESCRIPTION:<ESCAPEFORVCAL value="<&VCAL_DESC>"/>
DTSTART:<&VCAL_DTSTART>
DTEND:<&VCAL_DTEND>
BEGIN:VALARM
TRIGGER:PT15M
ACTION:DISPLAY
END:VALARM
END:VEVENT
</LOOP>
END:VCALENDAR

 

This code generates a calendar invite that looks something like this:

 

Default%20Calendar%20Invite

Default Calendar Invite

 

Fairly plain and straight forward. What if I told you, this was possible?

 

Calendar%20Invite%20Generated%20by%20LMS

Calendar Invite Generated by LMS

 

I won’t go through all the line by line code necessary to generate this (that’s not the point of the blog), but I’ll tell you what settings you need to add/change to support adding your own custom HTML.

The Magic you’ve been waiting for

Supporting HTML in the body of the calendar invite requires only two additional lines of code to the VCAL Message.

  1. VERSION: 2.0
    Add this line immediately under the first, as seen below.  That’s all there is to the first part. Nothing additional to add to this line.
  2. X-ALT-DESC;FMTTYPE=text/html:
    This line can be added anywhere after the first LOOP and before the closing </LOOP> tags.  However, I find adding it before/after to the plain text “Description” field to be a good practice.  Anything after the colon will be processed as HTML.  So start with your opening <html> tag, and start writing your HTML here.  Then, as good practice dictates, close your html with </html>.  You have full access to all the HTML in between, except things like Javascript and linking to External CSS.  Generally, these are unacceptable to most email servers, security, etc.  Certainly, this does not prevent you from creating great emails and calendar invites.  You’ll see in the Tips section, I recommend using in-line CSS for exactly this reason.

HTML code (tables, color, inline css, etc) will not work in the text DESCRIPTION field. The X-ALT-DESC parameter provides a method to add HTML to an event description. Although considered experimental, this field has become the method of choice when including HTML in a description. When using HTML, both fields must be included so that iCalendar readers that do not support the X-ALT-DESC field can still read the text version.

BEGIN:VCALENDAR
VERSION:2.0
METHOD:REQUEST
<LOOP>
BEGIN:VEVENT
UID:<ESCAPEFORVCAL value="<&VCAL_UID>"/>
SEQUENCE:<ESCAPEFORVCAL value="<&VCAL_SEQUENCE>"/>
ORGANIZER:<ESCAPEFORVCAL value="<&VCAL_ORG>"/>
SUMMARY:<ESCAPEFORVCAL value="<&VCAL_SUM>"/>
LOCATION:<&VCAL_LOCN>
X-ALT-DESC;FMTTYPE=text/html:<html><body> ... <h1>This is a header</h1><br/>This is a label in italics:<i>   <label key="notification.Enrollment.MessageText5"/></i><br/>And the SChedule Component tag in bold:<b> <&SCHD-CPNT></b></body></html>
DESCRIPTION:Hello <&STUD-FIRST> <&STUD-LAST>, \n\n You have successfully '<&STUD-ENRL-STATUS>' in this class. You can still put some better verbiage here .. and use \n to indicate a new line.
DTSTART:<&VCAL_DTSTART>
DTEND:<&VCAL_DTEND>
BEGIN:VALARM
TRIGGER:PT15M
ACTION:DISPLAY
END:VALARM
END:VEVENT
</LOOP>
END:VCALENDAR

 

If you’d like to clean up the plain text version of your calendar invite, then you can certainly do that as well.  You can add syntax tags above and beyond what is there by default, using \n for a new line.  I’ve included a simple example of this in the code box above.

Tips

Before I send you off writing your HTML, I wanted to share a few tips I learned while developing the same invite you saw above.

  1. I have found the best way to identify what data comes in what syntax tags, the first thing I did was to put ALL the tags into the body of the email and/or VCAL, then trigger the email.  Then I would know which ones I wanted to use, based on the return value.
  2. While it is technically allowable to have your HTML code span multiple lines in your VCAL, I would not recommend this.  There are specific requirements on each line to support this, and its very easy to miss one.  Yes, this will result in a VERY long single line of HTML, but still valid.  Don’t worry, your email client will be able to read this just fine.
  3. use inline CSS. This is a good practice not just for VCALs but also when modifying all emails.
  4. Store images publicly (not behind something requiring authentication, and reference them using the <img> tag.  There is an alternative method using base64 encoding, however, as I have yet to test that, I’ll save it for another blog.
  5. Syntax Tags that might contains multi-line values (meaning could have a hard return in them), like <SCHED_INSTRUCTIONS>, will need to be escaped.
    ie:  <ESCAPEFORVCAL value=”<SCHED_INSTRUCTIONS>”/>

Summary

In summary, we looked at

  • Where / How  to find templates
  • where to find the tokens that are supported for a given template
  • what the default code looks like
  • the two lines you need to add to support HTML in your VCAL.
  • Tips & Tricks to avoid headaches when you get started.

 

 

 

Assigned Tags

      23 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Mark Weinmann
      Mark Weinmann

      Chris, great suggestions for what are the plain OOTB notifications in SF Learning.  As you pointed out with your opening story, User Experience is paramount in gaining interaction.  Thanks for providing these invaluable tips!

      Author's profile photo Benedict Franklin
      Benedict Franklin

      Having tried this we don't seem to get any HTML formatting appear in outlook. Is it possible to share the full code?

      Also wondering if this can be used with labels so it can appear translated?

      Many thanks,

      Ben

      Author's profile photo Chris Stiles
      Chris Stiles
      Blog Post Author

      Hi Ben

       

      Great question!  Yes, the VCAL does support Labels. I've updated the code section in the original blog above to include an example syntax tag, a label, and some very basic HTML.  I've also tested this code in a demo environment, and is working as expected, with Outlook as the email client.  Hope this helps!

      thanks

      Chris

      Author's profile photo Mirjam van Krieken
      Mirjam van Krieken

      Dear Chris,

      Thnx very much for this explaination and examples!

      When I copy/paste your coding (from BEGIN until END) above, I only see the line X-ALT-DESC appearing. See screenshot below:

       

      Do you have any idea?

      Best regards,

      Mirjam

      Author's profile photo Chris Stiles
      Chris Stiles
      Blog Post Author

      Hi Mirjam

       

      Looks like it is working as expected.  The sample I provided is only a very basic sample showing HTML code that bolds, italicizes text, and how to use labels and syntax tags inside the X-ALT-DESC line.

      Next steps would be to continue to extend the HTML code in that line to create even nicer VCALs!

      Chris

      Author's profile photo Uwe STIEGLITZ
      Uwe STIEGLITZ

      Chris, I simply love it. Many kudos :-)....

      though still a few questions:

      • How is this label key filled label key="notification.Enrollment.MessageText5  I do see some text in my VCAL (it is calendar invite), even in German :-). Where does this come from?
      • In my calendar invite I see your complete html, but I do not see the Description, starting with "Hello..." What could be the reason?
      • I did not completely understand your explanations regarding HTML in the Description field. Would it be possible? Do I have to repeat the X-ALT-DESC again? In the SF LRN Community there are suggestions to use 

        DESCRIPTION:<ESCAPEFORVCAL value=<SCHED_INSTRUCTIONS/>/>
        X-ALT-DESC;FMTTYPE=text/html:<html><SCHED_INSTRUCTIONS/></html>

        But that does not work for us either...

      I can see 

      Brgds., Uwe

      Author's profile photo Chris Stiles
      Chris Stiles
      Blog Post Author

      Hi Uwe

      You can see all labels for the entire LMS (including those used in emails) under

      References --> Manage Labels --> Labels.

      In the screenshot below, I've searched (and started editing) the label ID notification.Enrollment.MessageText5 (since you use this one as the example in your question).

      The LMS substitutes in the text provided based on the recipients language preference.  In your LMS user Preferences, you probably have the preferred language set to German, so you received that portion of the email in German.

      Editing%20a%20Label

      Editing a Label

      There are two things I will mention here:

      1. To Edit the labels, you'll need to have sufficient LMS Admin Permissions to do so.
      2. Using this method to translate emails and VCALs applies only to using the Legacy editor.  The WYSIWYG Editor allows you to do translations inside the editor itself.

      On your second question .. the DESCRIPTION line is for plain text only. Because your email reader supports HTML, it rendered the code provided in the X-ALT-DESC line instead.  Had you been using some type of email reader that does not support rendering HTML, then the plain text in the DESCRIPTION line would be rendered instead (and thus display "Hello ... ").

      You should include similar information in both the X-ALT-DESC field and the DESCRIPTION field so that all your users receive the same information.

       

      Author's profile photo Uwe STIEGLITZ
      Uwe STIEGLITZ

      Thanks again, Christ. Now I think I got it.

      After using successfully your example code,  I tried to get the registration text tag in the HTML part. But it didn't work. The HTML part was complete empty in the notification / vcal.

      Do you maybe see any mistake?

      Brgds., Uwe

       

      BEGIN:VCALENDAR
      VERSION:2.0
      METHOD:REQUEST
      <LOOP>
      BEGIN:VEVENT
      UID:<ESCAPEFORVCAL value="<&VCAL_UID>"/>
      SEQUENCE:<ESCAPEFORVCAL value="<&VCAL_SEQUENCE>"/>
      ORGANIZER:<ESCAPEFORVCAL value="<&VCAL_ORG>"/>
      SUMMARY:<ESCAPEFORVCAL value="<&VCAL_SUM>"/>
      LOCATION:<&VCAL_LOCN>
      X-ALT-DESC;FMTTYPE=text/html:<html><body><br/><SCHED_INSTRUCTIONS/> <br/></body></html>
      DESCRIPTION:Hello <&STUD-FIRST> <&STUD-LAST>, \n\n You have successfully '<&STUD-ENRL-STATUS>' in this class. You can still put some better verbiage here .. and use \n to indicate a new line.
      DTSTART:<&VCAL_DTSTART>
      DTEND:<&VCAL_DTEND>
      BEGIN:VALARM
      TRIGGER:PT15M
      ACTION:DISPLAY
      END:VALARM
      END:VEVENT
      </LOOP>
      END:VCALENDAR

      Author's profile photo Chris Stiles
      Chris Stiles
      Blog Post Author

      Hi Uwe

       

      Your code is perfect. I would say to double check that the class you registered for during your test in fact, has some test in the Registration text filed, AND for your particular language of preference as well.

       

      Navigate to the specific class you enrolled/registered for.

      Click on the "Email Notifications" tab, then in the "Edit Registration Text" section, you'll see an "Edit" hyperlink, that will pop open a WYSIWYG editor.  Make sure all the languages configured have something in their respective placeholder. There might very well be something in the English part, but hasn't been translated to other languages.

      This is the spot that the <SCHED_INSTRUCTIONS> syntax tag pulls from, and is by default, empty.

      Registration%20Text

      Registration Text

       

      Author's profile photo Uwe STIEGLITZ
      Uwe STIEGLITZ

      Hi Chris, thanks for your time and input.

      Registration Text had been filled in all languages and - to be on the safe side - on Class as well as on item level. 🙂

      I also used again your example code and it worked.

      Then I replaced only the tag, so exchanged <&SCHD-CPNT> for <SCHED_INSTRUCTIONS>.

      But it didn't go through:

       

      The tag itself works when i use

      DESCRIPTION:<ESCAPEFORVCAL value="<SCHED_INSTRUCTIONS/>"/>

      Of course it then displays the registration text as "text only".

      Overall, that is strange, isn't it?

      Bye, Uwe

      Author's profile photo Chris Stiles
      Chris Stiles
      Blog Post Author

      Hi Uwe

      This does indeed, seem strange. Prior to replying, I set up your exact scenario.

      Here is the one line from my VCAL.  Note that I've inserted <SCHED_INSTRUCTIONS/> inside the body, before the header (h1) line.

      X-ALT-DESC;FMTTYPE=text/html:<html><body> <SCHED_INSTRUCTIONS/> <h1>This is a header</h1><br/>This is a label in italics:<i>   <label key="notification.Enrollment.MessageText5"/></i><br/>And the SChedule Component tag in bold:<b> <&SCHD-CPNT></b></body></html>

       

      This is for the same Class that was previously show in the screenshot (including my spelling mistakes!)

      SCHED_INSTRUCTIONS%20Result

      SCHED_INSTRUCTIONS Result

       

       

       

      Author's profile photo Uwe STIEGLITZ
      Uwe STIEGLITZ

      I got it, thanks a lot, really! My mistake 🙂 .....

      The tag seems to get only the first line of the registration text. And I started my registration text with a break. So probably it worked all the time and showed me "a break". So now I deleted the break and put all the registration text into one line and now I can see it all and start working on nicer formatting....

      Thank you very, very much! Brgds., Uwe

      Author's profile photo Chris Stiles
      Chris Stiles
      Blog Post Author

      Hi Uwe

      No mistake!  I should have see this first, my apologies.  Any syntax tag that is multi-line, will need to be escaped.  I tried this in my demo environment, and was able to get multiple lines of formatted/html text from that field to show.

      X-ALT-DESC;FMTTYPE=text/html:<html><body><ESCAPEFORVCAL value="<SCHED_INSTRUCTIONS/>"/></body></html>

       

      Chris

       

      Author's profile photo Uwe STIEGLITZ
      Uwe STIEGLITZ

      Hi Chris,

      as always: many thanks - you spend so much time on my questions.... kudo kudo

       

      First I tried:

      <html><body>"<SCHED_INSTRUCTIONS/>"</body></html>

      , but that did not work, it only showed the first line, preceeded by a quote.

       

      Then I saw that you suggested:

      <html><body><ESCAPEFORVCAL value="<SCHED_INSTRUCTIONS/>"/></body></html>

      and that worked nicely. So: Great!

       

      Just being curious: Is there conceptually a difference between using only

      <SCHED_INSTRUCTIONS/>

      or using

      <ESCAPEFORVCAL value=<SCHED_INSTRUCTIONS/>/>

      in the X-ALT-DESC part?

       

      And I realized that this tag brings the registration text in the Class only. It does bring the registration text of the item, right? So it is not inherited from the item... Right?

       

      Best Regards and many thanks!

      Uwe

      Author's profile photo Chris Stiles
      Chris Stiles
      Blog Post Author

      Hi Uwe

       

      Glad it is working now!

       

      It does not seem to apply to the SCHED_INSTRUCTIONS tag, at least that is what my initial testing shows .I modified the text on the Item, and created a new class.  It did not get copied down. Then I registered for the new class, and did not get anything in the SCHED_INSTRUCTIONS, so it would seem that tag does not roll up to the item.

      The documentation on the other hand, suggests there is SOME inheritance from the item.

      Ref: https://help.sap.com/viewer/5fae31b1299d4033b665edabea7b9087/2111/en-US/29e11decbe614d0e9a30bec9b85b7302.html

       

      Cheers!

      Chris

      Author's profile photo Uwe STIEGLITZ
      Uwe STIEGLITZ

      This is all quite interesting 🙂

      I also created a complete new item.

      Then I added a registration text.

      Then I scheduled the item.

      Then I registered.

      And: I got the registration text in the VCAL.

      And more interesting: First I opened the invitation on my smartphone - and the VCAL did show the registration text including the HTML code as text.

      Later I opened the vcal on my laptop. There the registration text was nicely formatted according to my HTML.

      And after that I also saw the nice HTML format on my smartphone... strange...

      Have a nice day, Uwe

      Author's profile photo Rhonda Chopin
      Rhonda Chopin

      Awesome Chris, can't wait to try this.

      Rhonda

      Author's profile photo Pieter Janssens
      Pieter Janssens

      Hi Chris Stiles

      I would like to only send the calendar invites and avoid the separate/duplicate email per segment. Is there any way to do so? I noticed if I remove all content from the BODY template block, it will no longer send the email and no longer send the calender invite either...

      It doesn't make sense to have both the message email and an invite email. With multiple segments, this quickly becomes an annoyance. If you organize a meeting yourself, you send the invite containing some description of the event.

      I'm also looking for a way to modify the VCAL so that Outlook does not show the RSVP options, but I havent' found a way to do so.

      Edit: deleting the BODY content does seem to work. I'm still receiving the invite (this trick doesn't work if you use ICS apparently).

      Best regards,

      Pieter

       

      Author's profile photo Chris Stiles
      Chris Stiles
      Blog Post Author

      Hi  Pieter Janssens

      Glad removing the BODY worked out for you!  (and correct, this would not work for ICS attachments)

      As for removing RSVP options, I'm not sure I understand the request.  When LMS sends outlook calendar invites, there is Accept, Decline, or Tentative, but no option to send RSVPs.

       

      See below as an example of the buttons available on the calendar invite sent from LMS.  I can accept, but not send response to anyone.  Are you seeing something different?

       

      No%20RSVP%20options

      No RSVP options

      Author's profile photo Pieter Janssens
      Pieter Janssens

      Hi Crhis,

      No, exactly the same, but giving these options is confusing as the participant might think he is 'allowed' to decline. In reality the tentative/decline options will never be registered anywhere else but on the recipients account.

      If you create a new meeting request using Outlook, there is an option to not request an RSVP: underneath "Response Options" uncheck "Request Responses". This will then show up in the calendar and instead of 'Accept/Tentative/Decline' it will show 'No response required'.

      I've tried using ATTENDEE;CN="XXX";RSVP=false:mailto:"xxxx", but this had no effect.

      Best regards,

      Pieter

      Author's profile photo Chris Stiles
      Chris Stiles
      Blog Post Author

      Hi Pieter

      I was looking into the ATTENDEE parameter as well, and from what I have read, setting RSVP=FALSE removes the buttons that actually send the response back (seen below in a standard calendar invite), but not the Accept/Tentative/Decline buttons.

       

      Given that the RSVP buttons are missing by default, I'm inclined to think that LMS might be inserting the ATTENDEE line automatically.

      I'll keep looking, but I don't think this will be possible.

      Chris

       

       

      Chris

       

      Author's profile photo Vinay Potdar
      Vinay Potdar

      Hi Chris,

      Thanks a lot for this blog, really helpful.

      We are currently in the process of setting up Microsoft Teams Integration with VLS.

      User Emails received:

      The email notification template is VLE_ENROLLMENT (VLE Registration Notification Email Template) – This notification is sent to user(s) when user registers for the class. This email has the MS Teams URL to join the online event.

      Also, an email notification with below details. URL is being generated to join the online event.

      Meeting Key:
      Meeting Password:
      Session Details:
      Click on the following URL to join the online event:

      Also, an Training Registration Confirmation Notification Email. This email has .ics attachment and when we click on it, we can add the calendar invitation to the outlook. The .ics attachment does not have any URL / Meeting link. This .ics attachment when added to the calendar invitation to outlook it shows up in MS Teams Calendar however this MS Teams Calendar does not have the URL/meeting link to join the meeting / class.

      The email notification with the calendar invite did not include the MS Teams link.

      Is it possible if the MS Teams link can be directly accessed via calendar invite instead of only receiving a reminder via the calendar and having to access Learning, find the course to start the course?

      Regards,

      VP.

       

      Author's profile photo Vinay Potdar
      Vinay Potdar

      It is mainly with the System Enrollment Notification. Under VCAL section there is no token for URL.

      This VCAL Section is shown as .ics attachment in the email received.

      Since there is no URL / Meeting link (STUD_URL) token, when added to the calendar invite, it does not show the meeting link / URL for users to join.