Brian
Brian

Reputation: 321

Use iCal.Net to Send Meeting Invite for Microsoft Outlook

I am trying to send a meeting invite with C# and am able to get what I want with a manually formatted static string - and here is the screenshot of what I was able to get with the static string

public static void SendEmailString()
{
    MailMessage msg = new MailMessage();
    msg.From = new MailAddress("[email protected]", "Song");
    msg.To.Add(new MailAddress("[email protected]", "John"));
    msg.Subject = "CS Inquiry";
    msg.Body = "TESTING";

    string test = @"BEGIN:VCALENDAR
    PRODID: -//Company & Com//Credit Inquiry//EN
    VERSION:2.0
    METHOD:REQUEST
    BEGIN:VEVENT
    ATTENDEE;CN=""John, Song"";ROLE=REQ-PARTICIPANT;RSVP=TRUE:MAILTO:[email protected]
    ATTENDEE;CN=""Lay, Sean"";ROLE=REQ-PARTICIPANT;RSVP=TRUE:MAILTO:[email protected]
    ORGANIZER: John, Song
    DTSTART:20171205T040000Z
    DTEND:20171206T040000Z
    LOCATION:New York
    TRANSP:TRANSPARENT
    SEQUENCE:0
    UID:a16fbc2b-72fd-487f-adee-370dc349a2273asfdasd
    DTSTAMP:20171027T215051Z
    DESCRIPTION:Request for information regarding Test
    SUMMARY:Summary 
    PRIORITY: 5
    CLASS: PUBLIC
    BEGIN:VALARM
    TRIGGER:-PT1440M
    ACTION: DISPLAY
    DESCRIPTION:REMINDER
    END:VALARM
    END:VEVENT
    END:VCALENDAR
    ";

    SmtpClient sc = new SmtpClient("smtp.company.com");

    System.Net.Mime.ContentType ct = new System.Net.Mime.ContentType("text/calendar");
    ct.Parameters.Add("method", "REQUEST");
    AlternateView avCal = AlternateView.CreateAlternateViewFromString(test, ct);
    msg.AlternateViews.Add(avCal);

    sc.Send(msg);
}

I am now trying to replicate that with iCal.Net (because the date and attendees are dynamic) and couldn't get what I want. Please see this screenshot of what I get with the code below:

public static void SendICal()
{            
    DateTime dtStart = new DateTime(2017, 12, 4);
    DateTime dtEnd = dtStart.AddDays(1);

    CalendarEvent e = new CalendarEvent()
    {
        DtStart = new CalDateTime(dtStart),
        DtEnd = new CalDateTime(dtEnd),
        DtStamp = new CalDateTime(DateTime.Now),
        IsAllDay = true,
        Sequence = 0,
        Transparency = TransparencyType.Transparent,
        Description = "Test with iCal.Net",
        Priority = 5,
        Class = "PUBLIC",
        Location = "New York",
        Summary = "Tested with iCal.Net Summary",
        Uid = Guid.NewGuid().ToString(),
        Organizer = new Organizer() {
            CommonName = "John, Song",
            Value = new Uri("mailto:[email protected]")
        } 
    };

    e.Attendees.Add(new Attendee()
    {
        CommonName = "John, Song",
        ParticipationStatus = "REQ-PARTICIPANT",
        Rsvp = true,
        Value = new Uri("mailto:[email protected]")
    });

    e.Attendees.Add(new Attendee()
    {
        CommonName = "John, Sean",
        ParticipationStatus = "REQ-PARTICIPANT",
        Rsvp = true,
        Value = new Uri("mailto:[email protected]")
    });

    Alarm alarm = new Alarm()
    {
        Action = AlarmAction.Display,
        Trigger = new Trigger(TimeSpan.FromDays(-1)),
        Summary = "Inquiry due in 1 day"                 
    };

    e.Alarms.Add(alarm);            

    Calendar c = new Calendar();
    c.Events.Add(e);

    CalendarSerializer serializer = new CalendarSerializer(new SerializationContext());            
    Console.WriteJohne(serializer.SerializeToString(c));

    MailMessage msg = new MailMessage();
    msg.From = new MailAddress("[email protected]", "Credit Inquiry");
    msg.To.Add(new MailAddress("[email protected]", "Song John"));
    msg.Subject = "CS Inquiry";

    System.Net.Mime.ContentType ct = new System.Net.Mime.ContentType("text/calendar");
    ct.Parameters.Add("method", "REQUEST");
    AlternateView avCal = AlternateView.CreateAlternateViewFromString(serializer.SerializeToString(c), ct);
    msg.AlternateViews.Add(avCal);
    //Response.Write(str);
    // sc.ServicePoint.MaxIdleTime = 2;

    SmtpClient sc = new SmtpClient("smtp.company.com");            
    sc.Send(msg);
}

I am not exactly sure what I am missing here. The iCalendar information generated from iCal.net is almost identical to the static string I used.

Thanks!

Upvotes: 9

Views: 8917

Answers (2)

Brian
Brian

Reputation: 321

Apparently the low case of TRANSP:Transparent (not TRANS :)) doesn't bother Outlook. It was actually because I forgot to specify the Method property on Calendar.

Based on the spec https://www.kanzaki.com/docs/ical/method.html - "When used in a MIME message entity, the value of this property MUST be the same as the Content-Type "method" parameter value. This property can only appear once within the iCalendar object. If either the "METHOD" property or the Content-Type "method" parameter is specified, then the other MUST also be specified."

I added the line c.Method = "REQUEST"; and it worked as expected.

With one exception though - Apparently Outlook doesn't like the period in Organizer's email address. The meeting invite will not be sent with email address like "[email protected]", it will work if I change it to "[email protected]"

            e.Attendees.Add(new Attendee()
        {
            CommonName = "Lay, Song",
            ParticipationStatus = "REQ-PARTICIPANT",
            Rsvp = true,
            Value = new Uri("mailto:[email protected]")
        });

I will open another thread for that, but would love to hear it if someone knows why :)

Upvotes: 4

rianjs
rianjs

Reputation: 7944

There's a bug in ical.net where statuses are not uppercase as RFC-5545 requires. This is because they're enums, and the string name of the enum is what's used during serialization. In this particular case, I think if you do a string replacement for TRANS:Transparent, and uppercase (TRANS:TRANSPARENT), this should fix your problem.

As a general practice, avoid unnecessary properties as it just increases the serialization burden, and size of the resulting output, so don't specify transparency unless you actually need it.

Despite the simplicity of the fix, I haven't made the change yet, because there's no way to do it in a backwards-compatible way, which requires bumping ical.net's major version number. (Client code wouldn't have to change, but the underlying type would go from enum to string, which requires clients to recompile their code.)

In the future, you might find the icalendar.org validator useful for tracking down errors like this.

Upvotes: 0

Related Questions