2009-01-20 16 views
36

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

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.

+1

La cantidad de tiempo que eligió esperar me hace piense que mi sugerencia no es exactamente lo que tenía en mente. ¿Al menos lo hiciste funcionar? – Tomalak

+1

Simplemente no tuve tiempo de probarlo antes. Una prueba rápida de esto pareció funcionar, y envié una invitación a la reunión de Outlook a una cuenta que tiene habilitado POP3 para obtener un "volcado crudo".Estos dos bits son lo suficientemente buenos para que pueda pensar en el resto, ya que solo necesito enviar reuniones pero no me importa la respuesta –

+1

. En cualquier caso, su respuesta fue tremendamente útil, ¡muchas gracias! –

Respuesta

47

La manera de enviar una solicitud de reunión a Outlook (y lo han reconocido) dice así:

  • preparar un archivo iCalendar, asegúrese de establecer estas propiedades adicionales, como Outlook los necesita:
  • preparar un multipart/alternative mail:
    • Parte 1: text/html (o lo que quieras) - esto se muestra a los lectores "ordinario" electrónico o como un retroceso y contiene una resumen del evento en forma legible para humanos
    • Parte 2: text/calendar; method=REQUEST, contiene el contenido del archivo ics (el parámetro method del encabezado debe coincidir con el método en ics). Tenga cuidado con la codificación de texto correcta, declarar que un parámetro de encabezado charset no hará daño.
    • 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 simplemente lee la parte text/calendar.
  • Enviar 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.
  • Configura 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 el iCalendar Specification Excerpts by Masahide Kanzaki. Son una luz en la oscuridad, mucho mejor que roer tu camino a través del RFC 2445. Pero, de nuevo, tal vez exista una biblioteca práctica para .NET.

+0

Simplemente no tuve tiempo de probarlo antes. Una prueba rápida de esto pareció funcionar, y envié una invitación a la reunión de Outlook a una cuenta que tiene habilitado POP3 para obtener un "volcado crudo". Estos dos bits son lo suficientemente buenos para que pueda entender el resto, ya que solo necesito enviar reuniones pero no me importa la respuesta –

+1

Quitar el siguiente encabezado de la Parte 2 me convenció: Content-Disposition: attachment; filename = meeting.ics Mientras este encabezado estuviera en el correo, Outlook mostraría el ICS como un archivo adjunto. – Bob

+0

Esto es lo que sucede cuando un encabezado 'Content-Disposition: attachment' está presente. ;-) – Tomalak

3

El código de abajo para enviar una solicitud de reunión de tal manera que Outlook reproducirá los botones Aceptar/Rechazar.

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

También tenga en cuenta que debe reemplazar CREATED, DTSTART, DTEND, DTSTAMP, LAST-MODIFIED. 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 el fichero de configuración:

<system.net> 
    <mailSettings> 
     <smtp deliveryMethod="Network" from="[email protected]"> 
     <network defaultCredentials="true" host="smtp.example.local" /> 
     </smtp> 
    </mailSettings> 
    </system.net> 
5

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

Y si usa un lenguaje .NET como C#, debe usar el contenedor EWS Managed API, que simplifica enormemente el trabajo con EWS.

De the docs, aquí es cómo utilizar la API de EWS logrado 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("[email protected]"); 
appointment.RequiredAttendees.Add("[email protected]"); 
appointment.OptionalAttendees.Add("[email protected]"); 

// Send the meeting request to all attendees and save a copy in the Sent Items folder. 
appointment.Save(SendInvitationsMode.SendToAllAndSaveCopy); 
+1

Estoy de acuerdo, esta solución es mucho más simple que las otras. También se debe tener en cuenta que EWS no requiere la interoperabilidad COM de Outlook. – JordanTDN

3

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

Usted no puede enviar elementos de tareas 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 aceptarse o rechazarse. El programa de envío puede modificar o cancelar la reunión después de que se haya enviado.

Se easieset a crear un elemento de iCal válido con el DDay.iCal .Net Library

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

El código crea un mail con:

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

El código muestra cómo agregar:

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

Algunos detalles importantes:

  • mail del remitente (u organizador opcional) y el receptor de correo debe ser diferente para hacer este trabajo en la perspectiva
  • METHOD en .ics y método en Mime.ContentType debe coincidir con
  • la reunión debe estar en el futuro para hacer este trabajo en la perspectiva
  • la parte .ics debe ser la última parte AlternateView en el correo MIME

Los detalles exactos sobre el panorama de manera interpreta archivos .ics se detallan en [MS-OXCICAL]: iCalendar to Appointment Object Conversion Algorithm

Usaremos estos conjuntos:

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

Por su DDay.iCal suficiente para descargar el DDay.iCal binary Files. Si desea agregar algunas características, es mejor consultar las fuentes de DDay.iCal porque la documentación está desactualizada y las fuentes 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 = "[email protected]"; 
string bodyPlainText = "This is the simple iCal plain text msg"; 
string bodyHtml = "This is the simple <b>iCal HTML message</b>"; 
string location = "Meeting room 101"; 
// 1: High 
// 5: Normal 
// 9: low 
int priority = 1; 
//===================================== 
MailMessage message = new MailMessage(); 

message.From = new MailAddress("[email protected]"); 
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<Event>(); 
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("[email protected]"); 
//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:[email protected]"); 
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í el() 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; 
} 

Su más fácil de configurar el SmtpClient en el fichero de configuración de la siguiente manera:

<configuration> 
    ... 
    <system.net> 
    <mailSettings> 
     <smtp> 
     <network host="mysmtp.server.com" port="25" userName="mySmtpUserName" password="myPassword" /> 
     </smtp> 
    </mailSettings> 
    </system.net> 
    ... 
+0

¡Gracias por una respuesta tan completa! Ahorra mucho ensayo y error –

Cuestiones relacionadas