VS.NET 2010 (and above) Users Click Here   

HOMECONTACT PRODUCTS DOWNLOADS PURCHASE TESTIMONIALS FORUMS COMPANY CONTACT
Home
Products
Downloads
Purchase
Licensing
Licensing FAQ
Software Updates
Support Forums
Testimonials
Feature Requests
Guarantee
About Us
Contact Us
Hosting Companies
Privacy Policy
   
Shopping Cart


Search

iCalendar as an Email Body

by Dave 14. October 2010 01:58

 Recently I had a request about sending an iCalendar (Meeting Request) object, as the email body itself, rather than as an attachment.(Thanks Paras!)

Background
iCalendars are special attachments that can be used to represent Meeting Requests or Appointments. By default, most mail systems like to have the iCalendar  object as an alternative body. In fact, that is how I wrote aspNetEmail to work. When you can create and add an iCalendar to the EmailMessage object, under the covers, aspNetEmail actually adds it to the internal body parts collection.

Below are 3 code examples. One example demonstrates creating a standard iCalendar enabled  email.  The 2nd example demonstrates creating email that has the iCalendar as the body. The 3rd example offers a combination of the 2.

All 3 of these examples use the following helper method called CreateiCal(…)

Create iCal creates a very simple iCalendar object, that has a meeting set tomorrow at 10am.

public iCalendar CreateiCal()
{
	iCalendar iCal = new iCalendar(); 
	iCal.ContentTransferEncoding = MailEncoding.Bit7;

	//create an start and end date, tomorrow at 10am, for 1 hr.
	DateTime tomorrow = DateTime.Now.AddDays(1);
	DateTime start = new DateTime( tomorrow.Year, tomorrow.Month, tomorrow.Day, 10,0,0);
	DateTime end = start.AddHours( 1 );

	//set some basic properties
	iCal.Event.Summary.Text = "this is a test ical"; 
	iCal.Event.Location.Text = "100 main conf room"; 
	iCal.Event.DateStart.Date = start; 
	iCal.Event.DateEnd.Date = end; 

	iCal.TimeZone.Format = TimeZoneFormat.ConvertToUTC;

	return iCal;
}

Example 1
This example demonstrates how to create a standard iCalendar enabled email. This code example will create the iCalender object, and add it to the EmailMessage object. Internally, aspNetEmail actually adds the iCalender to the internal body parts collection. The resulting email will actually have 3 body parts:

a)A Plain Text body part
b)A Html Body Part
c)An iCalendar Body Part

Here is a code example that demonstrates this behavior, along with a screenshot of the resulting email.

public void NormaliCalendar()
{
	//create a normal EmailMessage object
	//set some basic properties
	EmailMessage msg = new EmailMessage( "127.0.0.1" );
	msg.From = "me@example.com";
	msg.To = "you@example.com";
	msg.Subject = "ical test";

	//create the iCalendar object
	iCalendar iCal = CreateiCal(); 

	//add the iCalendar to the EmailMessage object
	msg.AddCalendar( iCal );

	//send it
	//msg.Send();
}

Notice that in that screenshot, we can have a nicely formatted, easily readable body. By default, aspNetEmail will create this from the properties of the iCalendar. However, the developer can over ride this behavior, and create their own friendly body.

Example 2
Some mail systems don't like to have a 3rd body part. This is typically a smaller subset, has a specialized situation. Instead, these mail systems like to have the entire body of the email actually be the iCalendar. The limitation of this is that some mail systems don't know how to interpret the email message.  This may or may not affect your situation. If you need to have the iCalendar object be the email body, the following code example demonstrates this behavior. Also, found below, is a screenshot of an email that doesn't know how to render this type of format.

public void iCalAsBody()
{
	//create a normal EmailMessage object
	//set some basic properties
	EmailMessage msg = new EmailMessage( "127.0.0.1" );
	msg.From = "me@example.com";
	msg.To = "you@example.com";
	msg.Subject = "ical test";

	//create the iCalendar object
	iCalendar iCal = CreateiCal(); 

	//set the body of the EmailMessage object itself.
	msg.ContentType = "text/Calendar;\r\n\tMethod=\"REQUEST\";";
	msg.Body = 	iCal.ToString( iCalendarType.iCal );

	//send it
	//msg.Send();

}

Notice that in this screenshot, the email is not easily reable. Also, this iCalendar appears to be missing. This is because the email client (Outlook Express in this example) doesn't know how to render an email, where the body is an iCalender.

Example 3
The 3rd example attempts to offer a combination of both Example 1 and Example 2. By adding a "name" parameter to the Content-Type value, we can get some mail clients to alternatively render the body of the email as an attachment. There really isn't an attachment, but the mail client thinks there is. This allows some mail clients to at least add the iCalendar to their calendaring system.

Below is a code example that demonstrates this, along with a screenshot of the resulting email.

public void iCalAsBodyAndAttachment()
{
	//create a normal EmailMessage object
	//set some basic properties
	EmailMessage msg = new EmailMessage( "127.0.0.1" );
	msg.From = "me@example.com";
	msg.To = "you@example.com";
	msg.Subject = "ical test";

	//create the iCalendar object
	iCalendar iCal = CreateiCal(); 

	//set the body of the EmailMessage object itself.
	//however, the additional Name parameter tricks the 
	//mail client into thinking there is an attachment
	msg.ContentType = "text/Calendar;\r\n\tMethod=\"REQUEST\";\r\n\tName=\"meeting.ics\"";
	msg.Body = 	iCal.ToString( iCalendarType.iCal );
	//send it
	//msg.Send();

}

 

Although this email isn't as pretty, by adding the "Name" parameter, it allows the mail client to present the user with an iCal that can be used.

As always, if anyone has any questions, feel free to contact me.

Thanks!
Dave Wanta

Cancel or Update Metting Requests

by Dave 1. October 2010 09:36

One question I often receive about meeting requests is how to update or cancel them.

Can this be done with aspNetEmail?

The short answer is YES! However, there is one small gotcha, you need to keep track of the unique id of the meeting request.

According to the iCalendar specifications, each meeting request needs to have a unique id. By default, aspNetEmail uses a Guid.  aspNetEmail also allows you to over ride this unique id. Whether you create your own, or use aspNetEmail’s, you must keep track of this unique id.

Once you have the unique id of the originally sent iCalendar, you can update or cancel the request at any time in the future. 

==============================
Updating an iCalendar
==============================
To update a meeting request you will need to do 2 things:
 
UniqueId:
1) Use the same UniqueId as the original. By default, aspNetEmail simply uses a guid for a UniqueId. If you want to, you can just create your own guid, and then record it for later use. For example:
 
   string uniqueId = Guid.NewGuid().ToString().Replace( "-", string.Empty );
   ical.Event.UniqueId.Value = uniqueId;

 
Then, just store the uniqueId for any future updates.
 
Sequence number
2)Youo must also increment the sequence number by 1.
 
The newer version of aspNetEmail's iCalendar class  has a Sequence property, so you can simply increment it like:
 
ical.Event.Sequence.Index++;
or
ical.Event.Sequence.Index = 1;
or
ical.Event.Sequence.Index = 2;

(depending upon how many updates you have issued)


=================================
CANCEL an iCalender
=================================
To cancel a meeting request, you will again need to do 2 things.
 
1) You will need to still use the original UniqueId value (just like above)
 
2)You will need to change the Method of the iCal to CANCEL. Here is what the code looks like:
 
First Request
==================
string uid = Guid.NewGuid().ToString();
iCalendar ical = new iCalendar();
ical.Event.UniqueId.Value = uid;
//set other properties, add attendees, set organizer...
ical...
EmailMessage m = new EmailMessage();
m.AddCalendar( ical );
m....
m.Send();
 

Cancelled request
=================
//reset the uid
iCalendar ical2 = new iCalendar();
ical2.Event.UniqueId.Value = uid;
 
//change the method to CANCEL
ical2.Method.Value = "CANCEL";

All Day Events in an iCalendar

by Dave 1. October 2010 09:06

By default, the RFC standard for the iCalendar specification does not support all day events.

However, both Outlook and Lotus Notes support this capability. Both do it a bit differently.

Below is a code example of how to use the iCalendar functionality of aspNetEmail to create all day events in both Lotus Notes and Outlook. 

static void AllDayEvent()
{
	//create the email message object
	EmailMessage m = new EmailMessage( "192.168.1.106" );
	m.From = "me@example.com";
	m.To = "you@blah.com";
	
	//create an all day event for next week
	DateTime eventDay = DateTime.Now.AddDays(7);

	m.Subject = "all day event for " + eventDay.ToShortDateString();

	//uncomment to create an iCal for Lotus Notes
	//iCalendar iCal= AllDayEventForLotus( eventDay );

	//create an iCal for Outlook
	iCalendar iCal = AllDayEventForOutlook( eventDay );

	//set some event properties
	//set the properties
	iCal.Event.Summary.Text = "Sales Meeting"; 
	iCal.Event.Location.Text = "100 main conf room"; 


	//when we add it to the EmailMessage object, all EmailMessage recipients will
	//be added to the iCalendar *if* the iCalendar does not have any recipients
	//if we wanted to add additional attendees we could use
	//ic.Event.Attendees.Add( ... )
	m.AddCalendar(iCal); 

	m.Logging = true;
	m.LogPath = "c:\\email.log";
	m.LogOverwrite = true;

	m.SaveToFile( "c:\\temp\\" );
	m.Send();


}
static iCalendar AllDayEventForLotus(DateTime eventDay)
{
	iCalendar iCal = new iCalendar(); 

	DateTime start = new DateTime( eventDay.Year, eventDay.Year, eventDay.Day, 4, 0, 0 );
	DateTime end = new DateTime( eventDay.Year, eventDay.Year, eventDay.Day, 20, 0, 0 );

	iCal.Event.DateStart.Date = start;
	iCal.Event.DateEnd.Date = end;
	iCal.Event.Priority.PriorityType = PriorityType.Normal; 

	return iCal;
}

static iCalendar AllDayEventForOutlook( DateTime eventDay)
{
	DateTime dayStart = eventDay;
	DateTime dayEnd = eventDay.AddDays( 1 );

	iCalendar iCal = new iCalendar(); 

	iCal.TimeZone.Format = TimeZoneFormat.SuppressTimeZoneRules;

	iCal.Event.DateStart.AddParameter( "VALUE", "DATE:" + dayStart.ToString("yyyyMMdd")  );
	iCal.Event.DateEnd.AddParameter( "VALUE", "DATE:" + dayEnd.ToString( "yyyyMMdd" ) );
	iCal.Event.TimeTransparency.TransparencyType = TransparencyType.Transparent; 

	iCal.Event.Priority.PriorityType = PriorityType.Normal; 

	//set various Outlook X-Headers, so Outlook will recognize it as an All Day Event.
	iCal.Event.Properties.Add( new CustomCalendarProperty( "X-MICROSOFT-CDO-BUSYSTATUS", "FREE" ) );
	iCal.Event.Properties.Add( new CustomCalendarProperty( "X-MICROSOFT-CDO-INSTTYPE", "0" ) );
	iCal.Event.Properties.Add( new CustomCalendarProperty( "X-MICROSOFT-CDO-INTENDEDSTATUS", "FREE" ) );
	iCal.Event.Properties.Add( new CustomCalendarProperty( "X-MICROSOFT-CDO-ALLDAYEVENT", "TRUE" ) );

	return iCal;
}

 

 

Testimonial

[in response to a support answer]Worked beautifully in all 5 languages that we use. Great support as always. "

M.L.

Read more testimonials
ListNanny aspNetDNS aspNetEmail aspNetPOP3 aspNetMX IPMuncher aspNetMIME aspNetPING aspNetTraceRoute aspNetIMAP aspNetMHT