Thursday, July 10, 2008

Outlook 2003 Meeting Requests, Part 1: Message Format

Problem: How to create a proper Outlook-compliant meeting request. That is, a request that Outlook shows as an accept/decline dialog:



Before describing a solution, I should emphasize that I'm using a Windows XP Pro (English) with Finnish regional settings and there are probably some localization issues here. For example, GMail does not accept any meeting requests I send from Outlook and Outlook sees only invite.ics attachment from GMail, no accept/decline dialog:




A .NET Solution?


Surprisingly, it turns out that Microsoft does not provide a convenient .Net solution for creating Outlook compatible meeting requests. No handy classes in System.Net.Mail, for example. Only available solution is to reverse engineer Outlook-generated meeting requests from scratch. For this, you need to have access to the raw message with SMTP headers included.

I recommend sending a request from Outlook to Gmail and opening it with the "show original" function:













To generate an identical message in .NET 1.1 you need to program directly with CDO, not with System.Web.Mail. It doesn't provide enough functionality to get the job done properly. With System.Web.Mail you can send a request as an iCalendar attachment but you won't get the accept/deny dialog to work.

Chuck Sphor has shown how to compose a meeting request with System.Net.Mail. (.NET 2.0) I couldn't try this the last time around because we were still using .Net 1.1. But I will return to this later...

Perhaps the most time-consuming problem is to find the correct MIME format. The format I got to work with Outlook (but not with GMail) is given below. It consists of three parts:
  • A plain text message body
  • an HTML message body
  • an Outlook-compatible iCalendar attachment.
Finding a correct iCalendar by trial and error is pain. I still don't have a clear understanding what are the minimum requirements to get the accept/deny -dialog work.

MIME Header:

Content-class: urn:content-classes:calendarmessage
MIME-Version: 1.0
Content-Type: multipart/alternative;
boundary="----_=_NextPart_001_01C86837.267B72A8"


Plain text part

------_=_NextPart_001_01C86837.267B72A8
Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

When: 5. helmikuuta 2008 6:30-7:00 (GMT+02:00) Helsinki, Kyiv, Riga, =
Sofia, Tallinn, Vilnius.
Where: fsd

*~*~*~*~*~*~*~*~*~*

HTML part

------_=_NextPart_001_01C86837.267B72A8
Content-Type: text/html;
charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

HTML headers...


When: 5. helmikuuta 2008 6:30-7:00 =
(GMT+02:00) Helsinki, Kyiv, Riga, Sofia, Tallinn, Vilnius.

Where: fsd


*~*~*~*~*~*~*~*~*~*



iCalendar attachment


------_=_NextPart_001_01C86837.267B72A8
Content-class: urn:content-classes:calendarmessage
Content-Type: text/calendar;
method=REQUEST;
name="meeting.ics"
Content-Transfer-Encoding: 8bit

BEGIN:VCALENDAR
METHOD:REQUEST
PRODID:Microsoft CDO for Microsoft Exchange
VERSION:2.0
BEGIN:VTIMEZONE
TZID:(GMT+02.00) Athens/Istanbul/Minsk
X-MICROSOFT-CDO-TZID:7
BEGIN:STANDARD
DTSTART:16010101T040000
TZOFFSETFROM:+0300
TZOFFSETTO:+0200
RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=10;BYDAY=-1SU
END:STANDARD
BEGIN:DAYLIGHT
DTSTART:16010101T030000
TZOFFSETFROM:+0200
TZOFFSETTO:+0300
RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=3;BYDAY=-1SU
END:DAYLIGHT
END:VTIMEZONE
BEGIN:VEVENT
DTSTAMP:20080205T203907Z
DTSTART;TZID="(GMT+02.00) Athens/Istanbul/Minsk":20080205T063000
SUMMARY:From Outlook to Gmail
UID:040000008200E00074C5B7101A82E008000000001098E3EA4768C801000000000000000
0100000004FDA693286B8C9499A0455CD25355E23
ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN="receiver@
gmail.com":MAILTO:
ORGANIZER;CN="Meeting Organizer":MAILTO:
LOCATION:fsd
DTEND;TZID="(GMT+02.00) Athens/Istanbul/Minsk":20080205T070000
DESCRIPTION:\N
SEQUENCE:0
PRIORITY:5
CLASS:
CREATED:20080205T203905Z
LAST-MODIFIED:20080205T203905Z
STATUS:CONFIRMED
TRANSP:OPAQUE
X-MICROSOFT-CDO-BUSYSTATUS:BUSY
X-MICROSOFT-CDO-INSTTYPE:0
X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY
X-MICROSOFT-CDO-ALLDAYEVENT:FALSE
X-MICROSOFT-CDO-IMPORTANCE:1
X-MICROSOFT-CDO-OWNERAPPTID:-370858024
X-MICROSOFT-CDO-APPT-SEQUENCE:0
X-MICROSOFT-CDO-ATTENDEE-CRITICAL-CHANGE:20080205T203907Z
X-MICROSOFT-CDO-OWNER-CRITICAL-CHANGE:20080205T203907Z
BEGIN:VALARM
ACTION:DISPLAY
DESCRIPTION:REMINDER
TRIGGER;RELATED=START:-PT00H15M00S
END:VALARM
END:VEVENT
END:VCALENDAR

------_=_NextPart_001_01C86837.267B72A8--


In Part 2 I will explain how to use CDO to create the message with all necessary parts.

5 comments:

Eurotrippers said...
This comment has been removed by the author.
Anonymous said...

I look forward to your Part 2.

Now my problme is that I have set three part of CDO Message body (text/plain,text/html and text/calendar),in the text/calendar part I used ADODB.Stream.writetext method to handle my ics-formatted string. But I still got an email not a meeting request in my outlook after the cdo message's sent out.

Anonymous said...

By the way, I use the outlook 2003 as well. I downloaded the CDOEX.dll from internet with the version 6.5.72260.

Alessandro said...

Hi, I have a problem that a external application send a appointment. I my Exchange 2007 works, but in exchange 2003 does not. the dialogs keeping grayed.

I´m not using CDO to send the appointimts, have you a idea to solve that problem.

tnks.

-mika- said...

Hi Alessandro!

I'm sorry but I don't have a direct answer to your question. Have you already posted this question to www.stackoverflow.com? Any debugging needs the iCalendar message in question, but of course you can obfuscate any sensitive data from it.

I've had trouble with Outlook 2003 vs. 2007 once and it was that Outlook 2007 required a VERSION:2.0 iCalendar in order to NOT to interpret the timezone as UTC/GMT. For example, DTSTART:20090527T090000 should show 9:00 in every timezone but DTSTART:20090527T090000T would show 9:00 only at the UTC time zone.

-mika-