BradVin's .Net Blog

Code, snippets, controls, utils, etc. Basically all things .net

Creating vCalendars programmatically in C#

Have you ever wanted to send out meeting requests from your code? Well I wanted to do just that today. And I didnt want to reference the Outlook dll's. I simply wanted to send an email to an attendee's email address.

After much searching and alot of useless code I found a gem at http://chuckdotnet.blogspot.com. I took the code there and modified it slightly so that you can send the meeting request to multiple recipients (attendees) at once.

below is the method that creates the system.net.mailmessage object with all the necessary alternateviews, so that when opened in outlook it behaves exactly like a meeting request that was sent from within outlook. remember to add using System.Net.Mail;using System.Net.Mime; to the top of your code.


public static MailMessage CreateMeetingRequest(DateTime start, DateTime end, string subject, string summary,
string location, string organizerName, string organizerEmail, string attendeeName, string attendeeEmail)
{
MailAddressCollection col = new MailAddressCollection();
col.Add(new MailAddress(attendeeEmail, attendeeName));
return CreateMeetingRequest(start, end, subject, summary, location, organizerName, organizerEmail, col);
}

public static MailMessage CreateMeetingRequest(DateTime start, DateTime end, string subject, string summary,
string location, string organizerName, string organizerEmail, MailAddressCollection attendeeList)
{
MailMessage msg = new MailMessage();

// Set up the different mime types contained in the message
System.Net.Mime.ContentType textType = new System.Net.Mime.ContentType("text/plain");
System.Net.Mime.ContentType HTMLType = new System.Net.Mime.ContentType("text/html");
System.Net.Mime.ContentType calendarType = new System.Net.Mime.ContentType("text/calendar");

// Add parameters to the calendar header
calendarType.Parameters.Add("method", "REQUEST");
calendarType.Parameters.Add("name", "meeting.ics");

// Create message body parts
// create the Body in text format
string bodyText = "Type:Single Meeting\r\nOrganizer: {0}\r\nStart Time:{1}\r\nEnd Time:{2}\r\nTime Zone:{3}\r\nLocation: {4}\r\n\r\n*~*~*~*~*~*~*~*~*~*\r\n\r\n{5}";
bodyText = string.Format(bodyText,
organizerName,
start.ToLongDateString() + " " + start.ToLongTimeString(),
end.ToLongDateString() + " " + end.ToLongTimeString(),
System.TimeZone.CurrentTimeZone.StandardName,
location,
summary);

AlternateView textView = AlternateView.CreateAlternateViewFromString(bodyText, textType);
msg.AlternateViews.Add(textView);

//create the Body in HTML format
string bodyHTML = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2//EN\">\r\n<HTML>\r\n<HEAD>\r\n<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=utf-8\">\r\n<META NAME=\"Generator\" CONTENT=\"MS Exchange Server version 6.5.7652.24\">\r\n<TITLE>{0}</TITLE>\r\n</HEAD>\r\n<BODY>\r\n<!-- Converted from text/plain format -->\r\n<P><FONT SIZE=2>Type:Single Meeting<BR>\r\nOrganizer:{1}<BR>\r\nStart Time:{2}<BR>\r\nEnd Time:{3}<BR>\r\nTime Zone:{4}<BR>\r\nLocation:{5}<BR>\r\n<BR>\r\n*~*~*~*~*~*~*~*~*~*<BR>\r\n<BR>\r\n{6}<BR>\r\n</FONT>\r\n</P>\r\n\r\n</BODY>\r\n</HTML>";
bodyHTML = string.Format(bodyHTML,
summary,
organizerName,
start.ToLongDateString() + " " + start.ToLongTimeString(),
end.ToLongDateString() + " " + end.ToLongTimeString(),
System.TimeZone.CurrentTimeZone.StandardName,
location,
summary);

AlternateView HTMLView = AlternateView.CreateAlternateViewFromString(bodyHTML, HTMLType);
msg.AlternateViews.Add(HTMLView);

//create the Body in VCALENDAR format
string calDateFormat = "yyyyMMddTHHmmssZ";
string bodyCalendar = "BEGIN:VCALENDAR\r\nMETHOD:REQUEST\r\nPRODID:Microsoft CDO for Microsoft Exchange\r\nVERSION:2.0\r\nBEGIN:VTIMEZONE\r\nTZID:(GMT-06.00) Central Time (US & Canada)\r\nX-MICROSOFT-CDO-TZID:11\r\nBEGIN:STANDARD\r\nDTSTART:16010101T020000\r\nTZOFFSETFROM:-0500\r\nTZOFFSETTO:-0600\r\nRRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=11;BYDAY=1SU\r\nEND:STANDARD\r\nBEGIN:DAYLIGHT\r\nDTSTART:16010101T020000\r\nTZOFFSETFROM:-0600\r\nTZOFFSETTO:-0500\r\nRRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=3;BYDAY=2SU\r\nEND:DAYLIGHT\r\nEND:VTIMEZONE\r\nBEGIN:VEVENT\r\nDTSTAMP:{8}\r\nDTSTART:{0}\r\nSUMMARY:{7}\r\nUID:{5}\r\nATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN=\"{9}\":MAILTO:{9}\r\nACTION;RSVP=TRUE;CN=\"{4}\":MAILTO:{4}\r\nORGANIZER;CN=\"{3}\":mailto:{4}\r\nLOCATION:{2}\r\nDTEND:{1}\r\nDESCRIPTION:{7}\\N\r\nSEQUENCE:1\r\nPRIORITY:5\r\nCLASS:\r\nCREATED:{8}\r\nLAST-MODIFIED:{8}\r\nSTATUS:CONFIRMED\r\nTRANSP:OPAQUE\r\nX-MICROSOFT-CDO-BUSYSTATUS:BUSY\r\nX-MICROSOFT-CDO-INSTTYPE:0\r\nX-MICROSOFT-CDO-INTENDEDSTATUS:BUSY\r\nX-MICROSOFT-CDO-ALLDAYEVENT:FALSE\r\nX-MICROSOFT-CDO-IMPORTANCE:1\r\nX-MICROSOFT-CDO-OWNERAPPTID:-1\r\nX-MICROSOFT-CDO-ATTENDEE-CRITICAL-CHANGE:{8}\r\nX-MICROSOFT-CDO-OWNER-CRITICAL-CHANGE:{8}\r\nBEGIN:VALARM\r\nACTION:DISPLAY\r\nDESCRIPTION:REMINDER\r\nTRIGGER;RELATED=START:-PT00H15M00S\r\nEND:VALARM\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n";
bodyCalendar = string.Format(bodyCalendar,
start.ToUniversalTime().ToString(calDateFormat),
end.ToUniversalTime().ToString(calDateFormat),
location,
organizerName,
organizerEmail,
Guid.NewGuid().ToString("B"),
summary,
subject,
DateTime.Now.ToUniversalTime().ToString(calDateFormat),
attendeeList.ToString());

AlternateView calendarView = AlternateView.CreateAlternateViewFromString(bodyCalendar, calendarType);
calendarView.TransferEncoding = TransferEncoding.SevenBit;
msg.AlternateViews.Add(calendarView);

// Adress the message
msg.From = new MailAddress(organizerEmail);
foreach (MailAddress attendee in attendeeList)
{
msg.To.Add(attendee);
}
msg.Subject = subject;

return msg;
}
Published Wednesday, January 16, 2008 8:29 PM by bradvin
Filed under: ,

Comments

# re: Creating vCalendars programmatically in C#@ Wednesday, January 16, 2008 7:12 PM

Nice snippet brad, but have you thought about using the @ symbol to escape your string literals?

Then, instead of having your entire vCalendar template in one line using \r\n, you could have literal new lines   and would be able to see the format indicies e.g. "{0}" much better, as well as the various names of all the 'properties'.

Like so:

string bodyCalendar = @"BEGIN:VCALENDAR

METHOD:REQUEST

PRODID:Microsoft CDO for Microsoft Exchange

VERSION:2.0

BEGIN:VTIMEZONE

TZID:(GMT-06.00) Central Time (US & Canada)

X-MICROSOFT-CDO-TZID:11

BEGIN:STANDARD

DTSTART:16010101T020000

TZOFFSETFROM:-0500

TZOFFSETTO:-0600

RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=11;BYDAY=1SU

END:STANDARD

BEGIN:DAYLIGHT

DTSTART:16010101T020000

TZOFFSETFROM:-0600

TZOFFSETTO:-0500

RRULE:FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=3;BYDAY=2SU

END:DAYLIGHT

END:VTIMEZONE

BEGIN:VEVENT

DTSTAMP:{8}

DTSTART:{0}

SUMMARY:{7}

UID:{5}

ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE;CN=""{9}"":MAILTO:{9}

ACTION;RSVP=TRUE;CN=""{4}"":MAILTO:{4}

ORGANIZER;CN=""{3}"":mailto:{4}

LOCATION:{2}

DTEND:{1}

DESCRIPTION:{7}\\N

SEQUENCE:1

PRIORITY:5

CLASS:

CREATED:{8}

LAST-MODIFIED:{8}

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:-1

X-MICROSOFT-CDO-ATTENDEE-CRITICAL-CHANGE:{8}

X-MICROSOFT-CDO-OWNER-CRITICAL-CHANGE:{8}

BEGIN:VALARM

ACTION:DISPLAY

DESCRIPTION:REMINDER

TRIGGER;RELATED=START:-PT00H15M00S

END:VALARM

END:VEVENT

END:VCALENDAR";

by Dave T

# re: Creating vCalendars programmatically in C#@ Thursday, January 17, 2008 3:39 AM

good suggestion Dave - i will update the code later today

by bradvin

# re: Creating vCalendars programmatically in C#@ Monday, April 21, 2008 2:51 AM

Excellent article. Working fine...

But how to add the same in Sender's calender?

by Shashidhar Reddy C

# re: Creating vCalendars programmatically in C#@ Friday, May 2, 2008 3:26 PM

What version of the framework does this work in? I've tried it using 2.0 but it doesn't work for me.

by Mike

# re: Creating vCalendars programmatically in C#@ Monday, May 12, 2008 12:07 PM

Mike,

I got the original code to work in C# 2.0. However, when I used Dave T's code for the bodyCalendar Outlook did not recognize the Calendar appointment.

So use the code as it is originally given.

Thanks to the author, this will help our business run smoother.

by Bob

# re: Creating vCalendars programmatically in C#@ Monday, May 19, 2008 12:54 PM

I'm having issues with Vista/Outlook 2007 users. They are not receiving the invitations at all (not even text/html format). We are on an Exchange server if that makes any difference.

XP&Outlook 2003 work perfectly though.

by Bob

# re: Creating vCalendars programmatically in C#@ Wednesday, May 21, 2008 10:15 AM

Excellent. Thanks a lot for sharing.

by Karim

# re: Creating vCalendars programmatically in C#@ Wednesday, October 22, 2008 1:57 AM

Hi excellent stuff. I have a question. How do i make this a reoccurring appointment.

by Daniel

# re: Creating vCalendars programmatically in C#@ Wednesday, November 5, 2008 1:40 PM

I'm having the opposite problem from Bob above. I'm receiving the calendar items in my Outlook 2007, but our Outlook 2003 user is not receiving them.

by BruceA

# re: Creating vCalendars programmatically in C#@ Wednesday, January 21, 2009 7:46 AM

Hi,

Nice work it works for me too....but i am having a problem that Subject and body in mail are same.

Any clue where i am wrong?

by Anoop tripathi

# re: Creating vCalendars programmatically in C#@ Friday, February 13, 2009 8:14 AM

Excelent work, I facing a problem when I schedule a meeting for the attendees its working fine, but the meeting it not getting saved in the organizer calendar,like it does when you work directly with outlook, I tried several things but its not working...anyone knows a solution for this issue...

by evega

# re: Creating vCalendars programmatically in C#@ Monday, March 16, 2009 4:14 AM

Although this code works good when you have only one attendee. However it does not work as expected when you have multiple attendees. I have ";" seperated email address of attendees in the attendeeList

Please help.

by Prinul Sasdev

# re: Creating vCalendars programmatically in C#@ Monday, March 16, 2009 4:15 AM

Although this code works good when you have only one attendee. However it does not work as expected when you have multiple attendees. I have ";" seperated email address of attendees in the attendeeList

Please help.

by Prinul

# re: Creating vCalendars programmatically in C#@ Tuesday, March 17, 2009 5:12 PM

Great code just apply the method without changes on it and works fine, thanx for posting this.

by RenoMX

# re: Creating vCalendars programmatically in C#@ Thursday, March 26, 2009 7:41 PM

Would you know the format of a reschedule email?

by mike

# re: Creating vCalendars programmatically in C#@ Monday, March 30, 2009 2:17 AM

Hi bradvin

i am working on it from the last few hours but this article is really awesome.... it works fine...

thanks bradvin.keep it up.

Happy coding

yogesh.

by yogesh

# re: Creating vCalendars programmatically in C#@ Tuesday, April 21, 2009 12:22 AM

Great job Brad...

This is what I exactly needed. However, I after sending the meeting request, I tried to cancel it. For the same code, I tried retaining the UID and incremented the sequence number and changed the method parameter from "REQUEST" to "CANCEL". But this is not working for me. Anything which I'm missing here for which the meeting is not getting cancelled??

Any help would be appreciated.

by Red October

# re: Creating vCalendars programmatically in C#@ Monday, September 7, 2009 8:11 AM

Hi bradvin,

   I am unable to open calendar appointment in Hotmail any idea?

thanks,

chandra

by chandra

# re: Creating vCalendars programmatically in C#@ Wednesday, September 30, 2009 4:53 PM

Brad,

You have helped me a lot.  Thanks. Could you please explain how to add this same meeting to a Public Folder in Outlook, instead of just

the attendee's calendar?

Thanks!