0 votes
by (150 points)
edited

How do I handle sending and receiving Appointments? I know for sending, the eml data should be stored in an AlternateView with the content type set to text/calendar, but for some reason it's not working for me.

Can someone shine some light toward helping me with this??? Thanks!

Applies to: Rebex Secure Mail

4 Answers

+1 vote
by (148k points)
edited
 
Best answer

To construct a calendar appointment, the following C# code can be used:

// plaintext and HTML descriptions (HTML version is required by Outlook)
string bodyText = "Please come to project XYZ review meeting.";
string bodyHtml = "<p>Please come to project XYZ review meeting.</p>";

// appointment data - see http://tools.ietf.org/html/rfc2445 for details
string appointmentData =
    "BEGIN:VCALENDAR\n" +
    "PRODID:Rebex Mail\n" +
    "VERSION:2.0\n" +
    "BEGIN:VTIMEZONE\n" +
    "TZID:US-Eastern\n" +
    "BEGIN:STANDARD\n" +
    "DTSTART:19981025T020000\n" +
    "RDATE:19981025T020000\n" +
    "TZOFFSETFROM:-0400\n" +
    "TZOFFSETTO:-0500\n" +
    "TZNAME:EST\n" +
    "END:STANDARD\n" +
    "BEGIN:DAYLIGHT\n" +
    "DTSTART:19990404T020000\n" +
    "RDATE:19990404T020000\n" +
    "TZOFFSETFROM:-0500\n" +
    "TZOFFSETTO:-0400\n" +
    "TZNAME:EDT\n" +
    "END:DAYLIGHT\n" +
    "END:VTIMEZONE\n" +
    "BEGIN:VEVENT\n" +
    "DTSTAMP:19980309T231000Z\n" +
    "UID:guid-1.host1.com\n" +
    "ORGANIZER;ROLE=CHAIR:MAILTO:mrbig@host.com\n" +
    "ATTENDEE;RSVP=TRUE;ROLE=REQ-PARTICIPANT;CUTYPE=GROUP:MAILTO:employee-A@host.com\n" +
    "DESCRIPTION:Project XYZ Review Meeting\n" +
    "CATEGORIES:MEETING\n" +
    "CLASS:PUBLIC\n" +
    "CREATED:19980309T130000Z\n" +
    "SUMMARY:XYZ Project Review\n" +
    "DTSTART;TZID=US-Eastern:19980312T083000\n" +
    "DTEND;TZID=US-Eastern:19980312T093000\n" +
    "LOCATION:1CP Conference Room 4350\n" +
    "END:VEVENT\n" +
    "END:VCALENDAR\n";  

// construct the calendar view
AlternateView appointment = new AlternateView();
appointment.SetContent(appointmentData, "text/calendar");
appointment.ContentType.Parameters.Add("method", "REQUEST");

// construct the message
MailMessage message = new MailMessage();
message.BodyText = bodyText;
message.BodyHtml = bodyHtml;
message.AlternateViews.Add(appointment);

// save the message
message.Save(...);

To load and a calendar appointment and display its data, this should work:

// load the appointment
MailMessage appointment = new MailMessage();
appointment.Load(...);

// display text parts
Console.WriteLine("Plain text: {0}", appointment.BodyText);
Console.WriteLine("HTML text: {0}", appointment.BodyHtml);

// find and display the text/calendar part
foreach (AlternateView view in message.AlternateViews)
{
    if (view.ContentType.MediaType == "text/calendar")
    {
        Console.WriteLine("Appointment data: {0}", view.ContentString);
        break;
    }
}

If it still doesn't work for you, please let us know.

by (150 points)
Thanks, but instead of saving the message can I email it to someone? For example if I email the message to someone and they receive in outlook it will add the appointment to their calendar.
by (148k points)
Yes, you can do that easily. Instead of calling the Save method, just send the message using Smtp object, as described in the following tutorials: http://www.rebex.net/secure-mail.net/tutorial-smtp.aspx#sending-mail
by (150 points)
Hey I finally got chance to try your code and it works for the most part. I can send the appointments to outlook, but the content type of the email is being sent as "multipart/alternative"... How do I change this to get it to show up as text/calendar??? Please help!
by (148k points)
Only the content type of the root MIME entity of the email is "multipart/alternative" - the last of its sub-entities is actually "text/calendar". This structure corresponds to calendar appointments generated by third-party software. However, in case you only need the text/calendar entity, I have added a separate answer for that.
0 votes
by (148k points)
edited

In case you prefer a message with a single text/calendar entity, you can use the following code to construct it:

string appointmentData =
    "BEGIN:VCALENDAR\n" +
    ... same as before ...
    "END:VCALENDAR\n";

// construct the calendar entity
MimeMessage appointment = new MimeMessage();
appointment.SetContent(appointmentData, "text/calendar");

// save the entity
appointment.Save(...);

The MimeMessage class is available in Rebex.Mime namespace. However, it looks like the other variant (text/calendar embedded in multipart/alternative) is slightly more compatible with third-party software (such as MS Outlook).

Again, instead of saving the MimeMessage, you can send it using the Smtp object.

by (150 points)
Okay, thanks that worked. But my issue now is that when I send the appointment to outlook, outlook doesn't display it the same (displaying an accept, decline and etc). Nor does outlook add the appointment to the calendar. Do you have any insight on this? And I do appreciate all your help, thanks!
by (150 points)
Is there a way to convert the string appointmentData above to an Appointment?
0 votes
by (73.6k points)
edited

The problem was the METHOD was not specified within the appointemt data and entity's Content-Type. This code works with my Outlook 2010. Please give it a try.

static string ConstructVCalendar(string from, string to, DateTime start, DateTime end, string summary, string description, string location)
{
    StringBuilder sb = new StringBuilder();
    sb.Append("BEGIN:VCALENDAR\n");
    sb.Append("METHOD:REQUEST\n");
    sb.Append("VERSION:2.0\n");
    sb.Append("PRODID:Rebex Mail\n");
    sb.Append("BEGIN:VEVENT\n");
    sb.AppendFormat("DTSTAMP:{0}\n", DateTime.Now.ToUniversalTime().ToString(@"yyyyMMdd\THHmmss\Z"));
    sb.AppendFormat("UID:{0}\n", Guid.NewGuid());
    sb.AppendFormat("ORGANIZER:MAILTO:{0}\n", from);
    sb.AppendFormat("ATTENDEE;RSVP=TRUE:MAILTO:{0}\n", to);
    sb.AppendFormat("DTSTART:{0}\n", start.ToUniversalTime().ToString(@"yyyyMMdd\THHmmss\Z"));
    sb.AppendFormat("DTEND:{0}\n", end.ToUniversalTime().ToString(@"yyyyMMdd\THHmmss\Z"));
    sb.Append("CATEGORIES:MEETING,PROJECT\n");
    sb.Append("CLASS:PUBLIC\n");
    sb.AppendFormat("SUMMARY:{0}\n", summary);
    sb.AppendFormat("DESCRIPTION:{0}\n", description);
    sb.AppendFormat("LOCATION:{0}\n", location);
    sb.Append("END:VEVENT\n");
    sb.Append("END:VCALENDAR\n");
    return sb.ToString();
}

// ...
string from = "organizer@host.com";
string to = "attendee@host.cz";
DateTime start = new DateTime(2011, 2, 28, 10, 30, 0, DateTimeKind.Local);
DateTime end = start.AddHours(2); // duration is 2 hours

// appointment data - see http://tools.ietf.org/html/rfc2445 for details
string appointmentData = ConstructVCalendar(from, to, start, end, "My summary", "My description", "My location");

// construct the calendar entity
MimeMessage appointment = new MimeMessage();
appointment.SetContent(appointmentData, "text/calendar");
appointment.ContentType.Parameters.Add("method", "REQUEST");
appointment.From = from;
appointment.To = to;

Smtp.Send(appointment, "SMTP.server.name");

Please note the line sb.AppendFormat("UID:{0}\n", Guid.NewGuid()); This UID can be used lately to change this appointemnt.

0 votes
by (140 points)
edited

I need the code too but I realize it's just not as easy as the VCalendar. Look into the AppointmentItemClass in the interop library, what a pain, need to deal with COM+

...