9

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("song@company.com", "Song");
    msg.To.Add(new MailAddress("John@company.com", "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:song@company.com
    ATTENDEE;CN=""Lay, Sean"";ROLE=REQ-PARTICIPANT;RSVP=TRUE:MAILTO:lins@company.com
    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:song@company.com")
        } 
    };

    e.Attendees.Add(new Attendee()
    {
        CommonName = "John, Song",
        ParticipationStatus = "REQ-PARTICIPANT",
        Rsvp = true,
        Value = new Uri("mailto:song.John@company.com")
    });

    e.Attendees.Add(new Attendee()
    {
        CommonName = "John, Sean",
        ParticipationStatus = "REQ-PARTICIPANT",
        Rsvp = true,
        Value = new Uri("mailto:Johns@company.com")
    });

    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("song.John@company.com", "Credit Inquiry");
    msg.To.Add(new MailAddress("song.John@company.com", "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!

CarenRose
  • 1,266
  • 1
  • 12
  • 24
Brian
  • 301
  • 3
  • 8
  • Go back to your original working code, and implement a StringBuilder or string concatenation to handle the construction of your string test. Looks like you will have to pass a list of recipients and roles as well. But you have that to do in either case. – JamieMeyer Oct 28 '17 at 15:09
  • I was hoping iCal.net could help with formatting of long string in each line. The iCalendar spec has limit of 75 character on each line. And also I was hoping to be able to attach files to the event , not sure how I can do that if I go with string builder route. – Brian Oct 28 '17 at 16:06
  • The limit is actually 75 octets, though it's implemented in ical.net as 75 characters. In cases of characters that require more than 1 byte to display, the fold violates the spec, which I should fix at some point. Anyway, you can look at the fold implementation here, if you're curious: https://github.com/rianjs/ical.net/blob/master/net-core/Ical.Net/Ical.Net/Utility/TextUtil.cs#L13 – rianjs Oct 28 '17 at 21:35

2 Answers2

3

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 "song.lay@company.com", it will work if I change it to "slay@company.com"

            e.Attendees.Add(new Attendee()
        {
            CommonName = "Lay, Song",
            ParticipationStatus = "REQ-PARTICIPANT",
            Rsvp = true,
            Value = new Uri("mailto:song.lay@company.com")
        });

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

Brian
  • 301
  • 3
  • 8
  • `METHOD` is an optional property according to the spec, but apparently Outlook requires it, which kinda makes sense, because Outlook has specific business goals. It's good Microsoft is using the spec as it was intended. In this case, Microsoft actually publishes Outlook's behaviors when things are/are not specified in the ics text: http://download.microsoft.com/download/4/D/A/4DA14F27-B4EF-4170-A6E6-5B1EF85B1BAA/[MS-STANOICAL].pdf – rianjs Oct 29 '17 at 12:05
0

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.

Community
  • 1
  • 1
rianjs
  • 7,767
  • 5
  • 24
  • 40
  • Apparently the low case of TRANSP:Transparent (not TRANS :)) doesn't bother Outlook. It was actuallly because I forgot to specifythe 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 – Brian Oct 29 '17 at 05:04