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