Отправлять приглашения на собрания Outlook без Outlook?
Мне просто интересно, можно ли отправлять приглашения на собрания людям без установки Outlook на сервере и использования COM Interop (чего я хочу избежать на сервере любой ценой).
У нас есть Exchange 2003 в домене Windows 2003, и все пользователи являются пользователями домена. Я полагаю, что могу отправить "круглый iCal / vCal" или что-то в этом роде, но мне интересно, есть ли подходящий стандартный способ отправки приглашений на собрания через Exchange без Outlook?
Это C#/.NET, если это имеет значение.
5 ответов
Способ отправить приглашение на собрание в Outlook (и распознать его) выглядит следующим образом:
- подготовьте файл iCalendar, обязательно установите эти дополнительные свойства, так как они нужны Outlook:
UID
SEQUENCE
CREATED
LAST-MODIFIED
DTSTAMP
- подготовить
multipart/alternative
почта:- Часть 1:
text/html
(или как вам угодно) - это отображается для "обычных" читателей почты или в качестве запасного варианта и содержит сводку события в удобочитаемой форме - Часть 2:
text/calendar; method=REQUEST
, содержит содержимое файла ics (заголовокmethod
Параметр должен соответствовать методу в ИКС). Следите за правильной кодировкой текста, объявляяcharset
Параметр заголовка не повредит. - Часть 3: При желании прикрепите сам файл.ics, чтобы обычные читатели почты могли предложить пользователю что-нибудь, на что можно нажать. Outlook не требует вложений, потому что он просто читает
text/calendar
часть.
- Часть 1:
- Отправьте письмо пользователю Outlook. Если вы все сделали правильно, письмо отобразится в виде приглашения на собрание, с кнопками посещаемости и автоматической записью в календаре пользователей после принятия.
- Настройте что-то, что обрабатывает ответы (они отправляются организатору собрания). Я еще не смог настроить автоматическое отслеживание посетителей для работы с почтовым ящиком Exchange, поскольку событие не существует в календаре организаторов. Outlook требует UID и SEQUENCES, чтобы соответствовать его ожиданиям, но с UID, который вы создали, это вряд ли сработает.
Для получения дополнительной информации о деталях и особенностях формата файла ics обязательно посетите отрывки спецификаций iCalendar от Masahide Kanzaki. Они свет в темноте, намного лучше, чем грызть ваш путь через RFC 2445. Но опять же, может быть, есть удобная библиотека для.NET.
Смотрите библиотеку DDay.iCal C# на sourceforge:
http://sourceforge.net/projects/dday-ical/
Тогда прочитайте эту статью:
http://www.codeproject.com/Articles/17980/Adding-iCalendar-Support-to-Your-Program-Part-1
И прочитайте это:
Экспорт события с C# в формат iCalendar и vCalendar
iCalendar - отличное решение общего назначения, а библиотека DDay.iCal - отличный способ сделать это из.NET, но я считаю, что веб-службы Exchange (EWS) являются лучшим решением в контексте исходного вопроса (Exchange, C#). /.СЕТЬ).
А если вы используете язык.NET, такой как C#, вам следует использовать оболочку EWS Managed API, которая значительно упрощает работу с EWS.
Из документации показано, как использовать управляемый API EWS для создания собрания и отправки запроса приглашенным:
// 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);
Вы можете отправлять приглашения на собрания по почте в Outlook, используя стандарт iCal (RFC 5545)
Вы не можете отправлять вещи таким образом. Вы можете отправлять "Встречи", но они выглядят в Outlook как приложения.ics, которые должны приниматься "вслепую".
Приглашения на собрание отображаются в Outlook с хорошим предварительным просмотром и могут быть приняты или отклонены. Программа отправки может изменить или отменить собрание после его отправки.
Легко создать действительный элемент iCal с помощью библиотеки DDay.iCal .Net
Код ниже является полным рабочим примером. Он создает строку с действительным приглашением на собрание iCal и отправляет ее по почте.
Код создает письмо с:
- текстовое тело для простых почтовых клиентов
- Тело HTML для diplay в современных почтовых клиентах
- приглашение на собрание iCal в качестве AlternateView (будет отображаться в Outlook)
- приглашение на собрание iCal в виде вложения (может использоваться в почтовых клиентах, отличных от outlook)
Код показывает, как добавить:
- текст описания в виде HTML, выглядит лучше в перспективе
- Приоритет, видимость (публичный / частный / конфиденциальный)
- опциональный органайзер (будет отображаться в outlook вместо отправителя почты)
- дополнительные участники
- дополнительная сигнализация
- дополнительные приложения к встрече. будет отображаться в календаре Outlook
Некоторые важные детали:
- отправитель почты (или дополнительный организатор) и получатель почты должны отличаться, чтобы сделать эту работу в outlook
- МЕТОД в.ics и МЕТОД в Mime.ContentType должны совпадать
- Встреча должна состояться в будущем, чтобы сделать эту работу в перспективе
- часть.ics должна быть последней альтернативной частью в письме MIME
Точные подробности о том, как outlook интерпретирует файлы.ics, подробно описаны в [MS-OXCICAL]: алгоритм преобразования объектов iCalendar в Appointment
Мы будем использовать эти сборки:
using System;
using System.IO;
using System.Net.Mail;
using DDay.iCal;
using DDay.iCal.Serialization.iCalendar;
Для DDay.iCal достаточно скачать двоичные файлы DDay.iCal. Если вы хотите добавить некоторые функции, лучше всего взглянуть на исходники DDay.iCal, поскольку документация устарела, и источники содержат довольно полные тесты, которые описывают все его функции.
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 <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("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<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("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);
Вот функция 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;
}
Проще всего настроить SmtpClient в файле конфигурации следующим образом:
<configuration>
...
<system.net>
<mailSettings>
<smtp>
<network host="mysmtp.server.com" port="25" userName="mySmtpUserName" password="myPassword" />
</smtp>
</mailSettings>
</system.net>
...
Приведенный ниже код будет отправлять приглашение на собрание таким образом, чтобы Outlook отображал кнопки "Принять / Отклонить".
Обратите внимание, что UID должен быть уникальным для каждой встречи, я использовал GUID.
Также обратите внимание, что вам нужно заменить CREATED, DTSTART, DTEND, DTSTAMP, LAST-MODIFIED. Это дата / время 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);
}
Предполагается, что в вашем конфигурационном файле настроен локальный SMTP-сервер:
<system.net>
<mailSettings>
<smtp deliveryMethod="Network" from="no-reply@example.com">
<network defaultCredentials="true" host="smtp.example.local" />
</smtp>
</mailSettings>
</system.net>