¿Enviando solicitudes de reunión de Outlook sin Outlook?

Me pregunto si es posible enviar solicitudes de reunión a personas sin tener instalado Outlook en el servidor y usando COM Interop (que quiero evitar en un servidor a toda costa).

Tenemos Exchange 2003 en un dominio de Windows 2003 y todos los usuarios son usuarios de dominio. Supongo que puedo enviar ’round iCal / vCal o algo así, pero me pregunto si existe una forma estándar adecuada de enviar solicitudes de reunión a través de Exchange sin Outlook.

Esto es C # /. Net si es importante.

La forma de enviar una convocatoria de reunión a Outlook (y hacer que se reconozca) es la siguiente:

  • prepare un archivo iCalendar, asegúrese de establecer estas propiedades adicionales, ya que Outlook las necesita:
    • UID
    • SEQUENCE
    • CREATED
    • LAST-MODIFIED
    • DTSTAMP
  • prepare un correo multipart/alternative :
    • Parte 1: text/html (o lo que quieras) – esto se muestra a los lectores de correo “ordinarios” o como un respaldo y contiene un resumen del evento en forma legible por humanos
    • Parte 2: text/calendar; method=REQUEST text/calendar; method=REQUEST , contiene el contenido del archivo ics (el parámetro del method header debe coincidir con el método en el ics). Tenga cuidado con la encoding de texto correcta, declarando que un parámetro de encabezado de charset no dolerá.
    • Parte 3: opcionalmente, adjunte el archivo .ics mismo, para que los lectores de correo ordinarios puedan ofrecer al usuario algo para hacer clic. Outlook realmente no requiere el archivo adjunto porque solo lee la parte de text/calendar .
  • Envíe el correo a un usuario de Outlook. Si lo hizo todo bien, el correo aparece como una convocatoria de reunión, complete con los botones de asistencia y la entrada automática en el calendario de los usuarios al aceptar.
  • Configure algo que procese las respuestas (van al organizador de la reunión). Aún no he podido obtener el seguimiento automático de asistentes para trabajar con un buzón de Exchange porque el evento no existirá en el calendario de los organizadores. Outlook necesita los UID y SECUENCIAS para que coincidan con sus expectativas, pero con un UID que haya inventado esto difícilmente funcionará.

Para obtener ayuda sobre los detalles y peculiaridades del formato de archivo ics, asegúrese de visitar los Extractos de la especificación iCalendar de Masahide Kanzaki . Son una luz en la oscuridad, mucho mejor que roer su camino a través de RFC 2445 . Pero, de nuevo, tal vez exista una biblioteca práctica para .NET.

Consulte la biblioteca DDay.iCal C # en sourceforge:
http://sourceforge.net/projects/dday-ical/

Luego lea este artículo del proyecto de código:
http://www.codeproject.com/Articles/17980/Adding-iCalendar-Support-to-Your-Program-Part-1

Y lee esto:
Exportar evento con formato C # a iCalendar y vCalendar

iCalendar es una gran solución de propósito general, y la biblioteca DDay.iCal es una excelente manera de hacerlo desde .NET, pero creo que los Servicios Web de Exchange (EWS) son una mejor solución en el contexto de la pregunta original (Exchange, C # /.RED).

Y si usa un lenguaje .NET como C #, debe usar el envoltorio de la API administrada EWS, que simplifica enormemente el trabajo con EWS.

Desde los documentos , a continuación se explica cómo usar la API administrada EWS para crear una reunión y enviar la solicitud a los invitados:

 // Create the appointment. Appointment appointment = new Appointment(service); // Set properties on the appointment. Add two required attendees and one optional attendee. appointment.Subject = "Status Meeting"; appointment.Body = "The purpose of this meeting is to discuss status."; appointment.Start = new DateTime(2009, 3, 1, 9, 0, 0); appointment.End = appointment.Start.AddHours(2); appointment.Location = "Conf Room"; appointment.RequiredAttendees.Add("user1@contoso.com"); appointment.RequiredAttendees.Add("user2@contoso.com"); appointment.OptionalAttendees.Add("user3@contoso.com"); // Send the meeting request to all attendees and save a copy in the Sent Items folder. appointment.Save(SendInvitationsMode.SendToAllAndSaveCopy); 

El siguiente código enviará una convocatoria de reunión de tal forma que Outlook mostrará los botones Aceptar / Rechazar.

Tenga en cuenta que el UID debe ser único por reunión; he usado un GUID.

También tenga en cuenta que debe reemplazar CREATED, DTSTART, DTEND, DTSTAMP, ÚLTIMA MODIFICACIÓN. Estas son la fecha / hora UTC.

  var m = new MailMessage(); m.Subject = "Meeting"; m.Body = ""; string iCal = @"BEGIN:VCALENDAR PRODID:-//Microsoft Corporation//Outlook 14.0 MIMEDIR//EN VERSION:2.0 METHOD:PUBLISH X-MS-OLK-FORCEINSPECTOROPEN:TRUE BEGIN:VEVENT CLASS:PUBLIC CREATED:20140423T045933Z DESCRIPTION:desc DTEND:20140430T080000Z DTSTAMP:20140423T045933Z DTSTART:20140430T060000Z LAST-MODIFIED:20140423T045933Z LOCATION:location... PRIORITY:5 SEQUENCE:0 SUMMARY;LANGUAGE=en-us:Summary... TRANSP:OPAQUE UID:D8BFD357-88A7-455C-86BC-C2CECA9AC5C6 X-MICROSOFT-CDO-BUSYSTATUS:BUSY X-MICROSOFT-CDO-IMPORTANCE:1 X-MICROSOFT-DISALLOW-COUNTER:FALSE X-MS-OLK-AUTOFILLLOCATION:FALSE X-MS-OLK-CONFTYPE:0 BEGIN:VALARM TRIGGER:-PT60M ACTION:DISPLAY DESCRIPTION:Reminder END:VALARM END:VEVENT END:VCALENDAR"; using (var iCalView = AlternateView.CreateAlternateViewFromString(iCal, new System.Net.Mime.ContentType("text/calendar"))) { m.AlternateViews.Add(iCalView); var c = new SmtpClient(); // Send message c.Send(m); } 

Esto supone que tiene un servidor SMTP local configurado en su archivo de configuración:

         

Puede enviar solicitudes de reunión por correo a Outlook utilizando el estándar iCal (RFC 5545)

No puede enviar elementos pendientes de esta manera. Puede enviar “Citas” pero estas aparecen en Outlook como archivos adjuntos .ics que deben aceptarse “a ciegas”.

Las solicitudes de reunión aparecen en Outlook con una buena vista previa y pueden ser aceptadas o rechazadas. El progtwig de envío puede modificar o cancelar la reunión después de que fue enviada.

Es fácil establecer un elemento iCal válido con la biblioteca DDay.iCal .Net

El siguiente código es un ejemplo completo de trabajo. Construye una cadena con una solicitud de reunión de iCal válida y la envía por correo.

El código crea un correo con:

  • cuerpo de texto sin formato para clientes de correo simple
  • Cuerpo HTML para diplay en clientes de correo modernos
  • Solicitud de reunión de iCal como AlternateView (se mostrará en Outlook)
  • Solicitud de reunión de iCal como Adjunto (utilizable en clientes de correo que no sean Outlook)

El código muestra cómo agregar:

  • texto descriptivo como HTML, se ve mejor en perspectiva
  • Prioridad, visibilidad (pública / privada / confidencial)
  • Organizador opcional (aparecerá en Outlook en lugar del remitente del correo)
  • asistentes opcionales
  • alarma opcional
  • adjuntos opcionales a la reunión. aparecerá en el calendario de Outlook

Algunos detalles importantes:

  • El remitente del correo (o el organizador opcional) y el destinatario del correo deben ser diferentes para que esto funcione en Outlook
  • MÉTODO en .ics y METHOD en Mime.ContentType debe coincidir
  • La reunión debe estar en el futuro para que esto funcione en perspectiva
  • la parte .ics debe ser la última parte de Vista alternativa en el correo MIME

Los detalles exactos sobre la forma en que Outlook interpreta los archivos .ics se detallan en [MS-OXCICAL]: Algoritmo de conversión de objetos de iCalendar a Cita

Usaremos estas asambleas:

 using System; using System.IO; using System.Net.Mail; using DDay.iCal; using DDay.iCal.Serialization.iCalendar; 

Para DDay.iCal es suficiente descargar los archivos binarios DDay.iCal . Si desea agregar algunas características, es mejor consultar las fonts de DDay.iCal porque la documentación está desactualizada y las fonts contienen pruebas bastante completas que incluyen todas sus características.

 const string filepath = @"C:\temp\ical.test.ics"; // use PUBLISH for appointments // use REQUEST for meeting requests const string METHOD = "REQUEST"; // Properties of the meeting request // keep guid in sending program to modify or cancel the request later Guid uid = Guid.Parse("2B127C67-73B3-43C5-A804-5666C2CA23C9"); string VisBetreff = "This is the subject of the meeting request"; string TerminVerantwortlicherEmail = "mr.asker@myorg.com"; string bodyPlainText = "This is the simple iCal plain text msg"; string bodyHtml = "This is the simple iCal HTML message"; string location = "Meeting room 101"; // 1: High // 5: Normal // 9: low int priority = 1; //===================================== MailMessage message = new MailMessage(); message.From = new MailAddress("sender@myorg.com"); message.To.Add(new MailAddress(TerminVerantwortlicherEmail)); message.Subject = "[VIS-Termin] " + VisBetreff; // Plain Text Version message.Body = bodyPlainText; // HTML Version string htmlBody = bodyHtml; AlternateView HTMLV = AlternateView.CreateAlternateViewFromString(htmlBody, new System.Net.Mime.ContentType("text/html")); // iCal IICalendar iCal = new iCalendar(); iCal.Method = METHOD; iCal.ProductID = "My Metting Product"; // Create an event and attach it to the iCalendar. Event evt = iCal.Create(); evt.UID = uid.ToString(); evt.Class = "PUBLIC"; // Needed by Outlook evt.Created = new iCalDateTime(DateTime.Now); evt.DTStamp = new iCalDateTime(DateTime.Now); evt.Transparency = TransparencyType.Transparent; // Set the event start / end times evt.Start = new iCalDateTime(2014, 10, 3, 8, 0, 0); evt.End = new iCalDateTime(2014, 10, 3, 8, 15, 0); evt.Location = location; //var organizer = new Organizer("the.organizer@myCompany.com"); //evt.Organizer = organizer; // Set the longer description of the event, plain text evt.Description = bodyPlainText; // Event description HTML text // X-ALT-DESC;FMTTYPE=text/html var prop = new CalendarProperty("X-ALT-DESC"); prop.AddParameter("FMTTYPE", "text/html"); prop.AddValue(bodyHtml); evt.AddProperty(prop); // Set the one-line summary of the event evt.Summary = VisBetreff; evt.Priority = priority; //--- attendes are optional IAttendee at = new Attendee("mailto:Peter.Black@MyOrg.com"); at.ParticipationStatus = "NEEDS-ACTION"; at.RSVP = true; at.Role = "REQ-PARTICIPANT"; evt.Attendees.Add(at); // Let's also add an alarm on this event so we can be reminded of it later. Alarm alarm = new Alarm(); // Display the alarm somewhere on the screen. alarm.Action = AlarmAction.Display; // This is the text that will be displayed for the alarm. alarm.Summary = "Upcoming meeting: " + VisBetreff; // The alarm is set to occur 30 minutes before the event alarm.Trigger = new Trigger(TimeSpan.FromMinutes(-30)); //--- Attachments string filename = "Test.docx"; // Add an attachment to this event IAttachment attachment = new DDay.iCal.Attachment(); attachment.Data = ReadBinary(@"C:\temp\Test.docx"); attachment.Parameters.Add("X-FILENAME", filename); evt.Attachments.Add(attachment); iCalendarSerializer serializer = new iCalendarSerializer(); serializer.Serialize(iCal, filepath); // the .ics File as a string string iCalStr = serializer.SerializeToString(iCal); // .ics as AlternateView (used by Outlook) // text/calendar part: method=REQUEST System.Net.Mime.ContentType calendarType = new System.Net.Mime.ContentType("text/calendar"); calendarType.Parameters.Add("method", METHOD); AlternateView ICSview = AlternateView.CreateAlternateViewFromString(iCalStr, calendarType); // Compose message.AlternateViews.Add(HTMLV); message.AlternateViews.Add(ICSview); // must be the last part // .ics as Attachment (used by mail clients other than Outlook) Byte[] bytes = System.Text.Encoding.ASCII.GetBytes(iCalStr); var ms = new System.IO.MemoryStream(bytes); var a = new System.Net.Mail.Attachment(ms, "VIS-Termin.ics", "text/calendar"); message.Attachments.Add(a); // Send Mail SmtpClient client = new SmtpClient(); client.Send(message); 

Aquí la función ReadBinary ():

 private static byte[] ReadBinary(string fileName) { byte[] binaryData = null; using (FileStream reader = new FileStream(fileName, FileMode.Open, FileAccess.Read)) { binaryData = new byte[reader.Length]; reader.Read(binaryData, 0, (int)reader.Length); } return binaryData; } 

Es más fácil configurar el SmtpClient en el archivo de configuración de esta manera:

  ...        ...