The outlook calendar, iCalendar and RFC 2445

You can exchange Outlook appointments with other applications. One way is to export or import files in the iCalendar format. In the formats supported by Outlook you will also find the vCalendar format, iCalendar is basically a newer version of this one. The iCalendar specs are based on RFC2445, it is supported by several manufacturers and can be used to interchange appointment data with non Outlook users as well.

In my case I have an applet which generates a list of appointments which are to be imported by an Outlook user. Getting this to work was a little more complicated than it looked due to the somewhat cryptical language of an RFC, contradicting sources on the web and different behavior of Outlook versions. Let me share what I found.

The applet will produce a text file with an ics extension containing. The appointments are fed from a dataset, where each row describes an appointment. The contents of the file are constructed using a stringbuilder.

public class IcalMaker

{

private StringBuilder sb;

private string uid;

public string MakeCalender(IcalActiviteiten acts, bool reminders)

{

sb = new StringBuilder();

uid = Guid.NewGuid().ToString();

sb.AppendLine("BEGIN:VCALENDAR");

sb.AppendLine("PRODID:-//Microsoft Corporation//Outlook 11.0 MIMEDIR//EN");

sb.AppendLine("VERSION:2.0");

sb.AppendLine("METHOD:PUBLISH");

for (int i=0; i < acts.IcalActiviteit.Count; i++)

addEvent(acts.IcalActiviteit[i], i, reminders);

sb.AppendLine("END:VCALENDAR");

return sb.ToString();

}

The code sets up the stringbuilder, an unique id, the opening lines and starts looping through the appointments.

Building these has a little quirk, although the code itself is very straightforward. Each event is enclosed in a BEGIN and an END line.

private void addEvent(IcalActiviteiten.IcalActiviteitRow act, int id, bool reminder)

{

sb.AppendLine("BEGIN:VEVENT");

sb.AppendLine(string.Format("DTSTART:{0:yyyyMMdd}T{1:hhmmss}", act.Datum, act.Aanvang));

sb.AppendLine(string.Format("DTEND:{0:yyyyMMdd}T{1:hhmmss}", act.Datum, act.Einde));

sb.AppendLine(string.Format("LOCATION:{0}", act.Zaal));

sb.AppendLine(string.Format("TRANSP:OPAQUE"));

sb.AppendLine(string.Format("SEQUENCE:0"));

sb.AppendLine(string.Format("UID:{0}-{1}", uid, id));

sb.AppendLine(string.Format("DTSTAMP:{0:yyyyMMdd}T{0:hhmmss}", act.Datum));

sb.AppendLine(string.Format("CATEGORIES:{0}", act.ActiviteitsNaam));

sb.AppendLine(string.Format("DESCRIPTION:{0}", "Your description here");

sb.AppendLine(string.Format("SUMMARY:{0}", act.ActiviteitsNaam));

sb.AppendLine("PRIORITY:5");

sb.AppendLine("X-MICROSOFT-CDO-IMPORTANCE:1");

sb.AppendLine("CLASS:PUBLIC");

if (reminder)

{

sb.AppendLine("BEGIN:VALARM");

sb.AppendLine("TRIGGER:-PT15M");

sb.AppendLine("ACTION:DISPLAY");

sb.AppendLine("DESCRIPTION:Reminder");

sb.AppendLine("END:VALARM");

}

sb.AppendLine("END:VEVENT");

}

The format and value of the event start (DTSTART) and end (DTEND) time needs special attention. Anyone who ever took their outlook data to a different time zone will have noticed all appointments moving in time when changing the time zone in Windows. Personally I find this frustrating, for instance when preparing for the PDC (in the Netherlands) I entered all sessions I didn't want to miss in my Outlook schedule. Having arrived in LA after adapting to the local culture Outlook wanted me to turn up in the middle of the night to hear Anders Hejlsberg speak. You can wake me up any time for such a presentation but I just known he won't be there. Outlook stores the times in UTC time and presents them using the actual time zone. Moving to another time zone, moves the appointments.

When feeding Outlook from an external application this same problem pops up. My application, Syllabus plus scheduling software, has no notion of time zones at all; it just thinks local time. At first sight you could recalculate all times to UTC times. But then you have to be aware of the dates the offset from UTC changes, that is the date the environment changes to day-lights saving time. You will end up with quite complicated configuration settings in your app. According to RFC 2445 a time zone can be added to a timestamp. But in that case you have to set up a time zone administration in you app, not very compelling either.

The good thing is that you can enter timestamps as so-called floating time, which indicates that the moment in time is determined by the local time zone. The bad thing is that Outlook 2000 does not support this, Outlook 2003 does and Outlook 2007 will bombard you with error messages telling it doesn't. To make things even more confusing I found my Outlook 2007 complaining about nothing, it does import all floating time events and does translate them quite right. For the moment I just have to tell my users to ignore the error message when using Outlook 2007.

The difference between a floating time and an UTC time is one letter. This is an UTC time

"DTSTART:{0:yyyyMMdd}T{1:hhmmss}Z"

And this a floating time

"DTSTART:{0:yyyyMMdd}T{1:hhmmss}"

The UTC time has an extra Z.

Another property which needs some explanation is UID, the unique ID. This is supposed to be unique for every event. In my case I generate a guid for the series and append the event's sequence. Outlook will not complain when the ID is not unique, but it is part of the spec.

In case you want to add a reminder to the appointment add a VALARM. In the example this is hard coded at 15 minutes : TRIGGER:-PT15M

Using this code I have all information Outlook needs in one string. A web app can write this directly to the response, following the minimal code to get that done.

IcalMaker icm = new IcalMaker();

IcalActiviteiten acts = getAppointmentData();

Response.Clear();

Response.ContentType = "application/binary";

Response.AddHeader("Content-Disposition", "attachment;filename=YourAppointments.ics");

Response.Write(icm.MakeCalender(acts, CheckBoxReminders.Checked));

Response.Flush();

Response.End();

Adding the appointments to outlook is now a click away.

That's it. I don't claim to understand all settings and fiddlings. But it works well; and that's enough for the moment.

This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://www.onlinescorekeeper.com/ slolife

    Check out http://www.codeproject.com/vb/net/vcalendar.asp for a .net class that has similar code.

    Good stuff on the timezone stuff, something I didn’t spend a lot of time with in my code.

    I’ll also have to add support for the X-MICROSOFT-CDO-IMPORTANCE field.

  • http://codebetter.com/blogs/peter.van.ooijen/ pvanooijen

    Nice article !
    I got the list of all fields by reverse engineering. Saved an appointment in Outlook as iCalender and used notepad to see what it looked like. Don’t know what every detail stands for though..

  • http://www.flickr.com/photos/12766851@N00/ Mike

    Nice post.

    Years ago I wrote ASP code to generate vCards, so I can appreciate what you went through with the RFC (I did the same at that time). It’s been on the back of my mind to write some code for generating vCalendars… thanks for sharing!

    Mike

  • Milo

    “Z versus T”
    That’s not the case. According to rfc2445 section 4.3.5 it’s always [date]T[time], where [time] may end with a Z (indicating UTC time) or without one (indicating a floating time).

    So this is an UTC time:
    “DTSTART:{0:yyyyMMdd}T{1:hhmmss}Z”

    And this a floating time
    “DTSTART:{0:yyyyMMdd}T{1:hhmmss}”

  • http://codebetter.com/blogs/peter.van.ooijen/ pvanooijen

    Thanks Milo. You’re right, the content is updated.

  • Misha

    I have been trying to write a icalendar file to show time as ‘Out of Office’ instead of the default ‘Busy’.

    would you know how to set this?

  • http://codebetter.com/blogs/peter.van.ooijen/ pvanooijen

    Isn’t that an outlook property ? Not part of icalender ?

  • kallien

    What is the way to set the time as ‘Out Of Office’?

  • http://BusinessCalendar.Org Alex

    Hi,
    I’ve been trying to do a simple iCalendar implementation in php. You’ll find the threads below with discussions of various aspects below. Mac has proven to be very easy. Outlook seems to fight every step.

    Your implementation above does not include the “folding” required by RFC 2445, nor the replacement of characters ” , ; : etc” as I have found in other examples and advice given to me. Am I missing something?

    If you have an opportunity, check these out and comment, as well.
    http://forums.devshed.com/php-development-5/preg-replace-explaination-needed-497498.html
    http://forums.devshed.com/php-development-5/if-you-have-outlook-or-icalendar-i-need-your-iballs-496241.html
    http://forums.devshed.com/php-development-5/dating-a-google-calendar-494912.html
    http://forums.devshed.com/php-development-5/icalendar-and-outlook-495158.html

    Alex

  • vishal

    Great Article.
    congrats
    But Sir I want to know that what will be the size of iCal file in memory and how can we calculate that size using bit information of that file using hex viewer.

    Regards
    Vishal
    email: sbvishal@gmail.com

  • http://codebetter.com/blogs/peter.van.ooijen/ pvanooijen

    @Alex. My implementation is not a full implementaion of RFC 2445. My point is that a lot of email clients don’t follow RFC 2445 either, especially Outlook is bad. Being a good citizen you should implement as much of the RFC as possible but at the same time you have to be carefull the consuming apps don’t trip over the content. I stated this in more word here

    http://codebetter.com/blogs/peter.van.ooijen/archive/2007/11/09/implement-a-standard-document-be-strict-when-you-write-but-forgiving-when-you-read.aspx

    @vishal: You can read the size of the result file when save it. But that’s not the amount of memory it takes to build it. In case that troubles you you need a profiler.

  • Sean

    I need to go the other way…. I want to take advantage of the easy to use Calendar interface for a content publisher to make a calendar in outlook export an iCalendar that I can place on the site to read in the event/appointment information via ASP.NET. This to me would be much easier than having to create an event manager and storing the data etc myself. any thoughts? anybody?

  • http://codebetter.com/blogs/peter.van.ooijen/ pvanooijen

    Should be no problem. You can save the outlook schedule directly as an ical file. It’s in the export wizard of Outlook’s file menu.

  • gui

    This class is not defined “IcalActiviteiten”
    What is it suppost to be? Can you add it?

  • http://codebetter.com/blogs/peter.van.ooijen/ pvanooijen

    Icalactiviteiten is an interface. The members of this interface describe the activity to be published. So that’s the point your own functionality enters the code.

  • Eric

    Can anyoned explain how to include the Attendees, so instead of manually click the Invite Attendees button and add the emails in the TO field, well the form field will take the emails written by the client and it will implemented into the ics file ready for the author to click SEND ??? please can this be done.

    email me your answer to: djzomby@hotmail.com

  • http://codebetter.com/blogs/peter.van.ooijen/ pvanooijen

    What about reverse engineering. Create such an appointment and save it as ical (In the Outlook menu). Which will show you the ical’s content.

    Email the answer ?
    http://codebetter.com/blogs/peter.van.ooijen/archive/2007/02/27/A-blog-is-not-a-helpdesk.aspx

  • Eric

    Ive already done that, the ics is attach. The only thing is, the attendee does nothing, I can add and change the email for the FROM (Organizer) but thats it, and its not good enough. Ive been searching for over 2 month just to include 1 extra email in the Required: field. My form is built so when the client submits, the author accepts it and it has to be save in the client calendar and the boardroom calendar (author). Any idea?

    http://www.experts-exchange.com/Web_Development/Web_Languages-Standards/ASP/Q_23178137.html

  • http://codebetter.com/blogs/peter.van.ooijen/ pvanooijen

    Eric,

    May I suggest some TDD to get the thing working ? Mock (stub) the desired result. See if it behaves well. Separate that from the form to construct the thing.

  • Amy K

    Out of office is

    X-MICROSOFT-CDO-BUSYSTATUS:OOF

  • Steve P

    Floating time is still not floating in Outlook 2007.

    I’m writing an app to enter flight information into a user’s calendar, so most of the time the return leg originates in a different time zone to the outward leg.
    I have ways of working out the timezone and dst parameters for each airport which would allow me populate with UTC time or specify a VTIMEZONE but floating times are a much better solution cos:
    a) It means I don’t have to do the work to figure out airport timezone
    b) I don’t have to create additional database tables to store the timezone data
    c) I don’t have to worry about maintaining the timezone database in years to come
    but most importantly
    d) Users won’t keep phoning up to say that the calendar entries are going in at the wrong time
    - to get an email saying your return flight from LAX to LHR is taking off at 15:30 which contains a calendar entry where the flight takes off at 09:30 is very confusing
    - IMO most users would like to see their calendars displayed in local time irrespective of what timezone they are in

    I’ve been quite a way through the RFC before discovering this atricle (which is very good BTW and a far preferable option than reading the RFC) … and had already tried out the floating time format and imported into Outlook 2002 – it didn’t work – no suprises there

    Most of our customers will be using Outlook 2003-2007 so if floating times work my problem goes away – so I got a collegue to load the ics into 2007 – sadly it’s just the same as 2002
    - don’t know if I’m doing somwething wrong – but it’s not exactly rocket science removing the Z at the end of the date string

    Tried to create a floating appointment in 2007 to reverse engineer, but found I can set the time zone to anywhere in the world for the appointment, but not set it to ‘floating timezone’

    I would have given up long ago and gone down the airport timezone route had it not been for the glimmer of hope offered by this article

    I have seen some posts which suggest that floating time only works for all day appointments – http://forums.teamsnap.com/forums/5/topics/206

    - any ideas?

    Steve

  • Pratik

    A detail of the interface IcalActiviteiten would help to no end. Since, the variable names are not intuitive (at least to me), can’t make out what value to pass to them.

  • http://codebetter.com/blogs/peter.van.ooijen/ pvanooijen

    It’s meant to be enigmatic. It’s nothing else but fodder to feed your ical appointments.. The iCal names, the fits CAPITALIZED part of the textlines are important.

  • Gregguz

    UTC vs. floating time

    You can use ToUniversalTime method of DateTime c# class and the date and time will be generated correctly for Outlook, it won’t also generate any errors. Good Luck.

    string.Format(“DTSTART:{1:yyyyMMddTHH0000}Z”,
    StartDate.ToUniversalTime())

  • Sam

    The clients server is hosted at CST and when adding appoinments using the vcs file as above times are changed to one hr ahead. The client could be in anyyime zone. Is there a way for me to tell the vcs file to ignore the GMT format and just take the datetime I pass in.

  • http://strivinglife.com/words/ James Skemp

    Late comment: Has anyone gotten the reminder functionality to work?

    I’ve tried this and various tweaks, but neither Outlook 2003 nor 2007 accept this, when the appointment is sent as an attachment, via email.

  • tatyaso

    Hi,
    I have created I cal file .
    While Importing ical file in Outlook 2007 it chaanging time . but in Outlook 2010 its showing correct.

    Below is format of Ical file

    BEGIN:VCALENDAR
    PRODID:-//Microsoft Corporation//Outlook 14.0 MIMEDIR//EN
    VERSION:2.0
    METHOD:PUBLISH
    BEGIN:VTIMEZONE
    TZID:Alaskan Standard Time
    BEGIN:STANDARD
    DTSTART:16011104T020000
    TZOFFSETFROM:-0800
    TZOFFSETTO:-0900
    END:STANDARD
    END:VTIMEZONE
    BEGIN:VEVENT
    CLASS:PUBLIC
    CREATED:20101027T072242Z
    DESCRIPTION:\n
    DTEND;TZID=”Alaskan Standard Time”:20101026T003000
    DTSTAMP:20101027T072242Z
    DTSTART;TZID=”Alaskan Standard Time”:20101026T000000
    LOCATION:sdfsdf
    PRIORITY:5
    SEQUENCE:0
    SUMMARY;LANGUAGE=en-us:testing is goin on
    END:VEVENT
    END:VCALENDAR

    Please Help Me

  • http://codebetter.com/members/pvanooijen/default.aspx pvanooijen

    It has to do with the timezone. Are both of your Outlook versions and their calendars living in the same zone ?
    When so, I wouldn’t be surprised to see the two Outlook versions implementing the handling of a time zone different. This post is from the pre 2010 era, it was not tested against Outlook 2010.

  • Accounts Man

    hello Peter!  Great article and very informing.  What if you were going the “other way around”?  That is, you are creating an outlook event and sending it to an email that would then be read into a web-based website?  Can this be done?  I’m using PHP and MySQL right now, but am unfamiliar with how to read “frequency” or “reoccurence” of an outlook event from it’s iCalendar format.  Any ideas? :)