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

# Our daily link (2008-01-16)@ Wednesday, January 16, 2008 4:29 PM

Software Rhino ETL 2.0 Announcing Sandcastle Version 2.4.10115 Agile Patterns of Agile Adoption by Mike

# 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

# Link Listing - January 16, 2008@ Thursday, January 17, 2008 8:01 AM

Link Listing - January 16, 2008

# Link Listing - January 16, 2008@ Thursday, January 17, 2008 8:02 AM

Announcements .NET Framework Library Source Code now available [Via: ScottGu ] Announcing ALT.NET Open...

# 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#@ Monday, April 21, 2008 8:31 AM

Good Article.

by Vijaya Bhaskar K

# re: Creating vCalendars programmatically in C#@ Friday, May 02, 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 05, 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#@ Friday, April 10, 2009 2:16 PM

Great job man, this worked almost instantly.  Kudos!  I also wanted to be able to set my own reminder time, so I found this page:  www.codeproject.com/.../vcalendar.aspx which creates an alarm object from a timespan, so I added that class to this class and pass in an alarm object.

It works (with some debugging), but I can only seem to get one alarm to function, and not multiple alarms (reminders) like the page suggests.

by Aaron McCoy

# 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#@ Tuesday, May 05, 2009 8:00 AM

Great work Brad,

Could you please suggest me how to cancel the meeting request sent thru your module. I changed the method attribute to CANCEL and incremented the sequence, keeping the same UID. But nothing works. Any alternatives/suggestions that I may be missing?

Thanks,

RO

by red october

# re: Creating vCalendars programmatically in C#@ Wednesday, September 02, 2009 12:29 AM

Hi Bradvin,

    This is working fine for yahoo and gmail accounts but if i try to open the Hotmail account with calendar appointment, not able to open the mail. Any suggestions?

Thanks,

chandra

by chandra

# re: Creating vCalendars programmatically in C#@ Monday, September 07, 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!

Leave a Comment

(required) 
(required) 
(optional)
(required)