Отправка запросов на собрание Outlook без Outlook?

Мне просто интересно, можно ли отправлять запросы на собрания людям без установки Outlook на сервере и использования COM-взаимодействия (чего я хочу избежать на сервере любой ценой).

У нас есть Exchange 2003 в домене Windows 2003, и все пользователи являются пользователями домена. Думаю, я могу отправить iCal / vCal или что-то в этом роде, но мне интересно, есть ли правильный стандартный способ отправки запросов на собрание через Exchange без Outlook?

Если это важно, это C # / .net.


person Michael Stum    schedule 20.01.2009    source источник
comment
Количество времени, которое вы выбрали для ожидания, заставляет меня думать, что мое предложение не совсем то, что вы имели в виду. Вы хотя бы заставили его работать?   -  person Tomalak    schedule 23.01.2009
comment
Просто не успел раньше потестить. Быстрая проверка, похоже, сработала, и я отправил приглашение на собрание Outlook учетной записи, в которой включен протокол POP3, чтобы получить необработанный дамп. Этих двух битов достаточно, чтобы я мог разобраться в остальном, так как мне нужно только отправлять встречи, но не заботиться об ответе.   -  person Michael Stum    schedule 23.01.2009
comment
В любом случае, ваш ответ был чрезвычайно полезен, большое спасибо!   -  person Michael Stum    schedule 23.01.2009
comment
Ваше здоровье! :) Рад слышать.   -  person Tomalak    schedule 23.01.2009


Ответы (5)


Способ отправки приглашения на собрание в Outlook (и его распознавания) выглядит следующим образом:

  • prepare an iCalendar file, be sure to set these additional properties, as Outlook needs them:
  • prepare a multipart/alternative mail:
    • Part 1: text/html (or whatever you like) - this is displayed to "ordinary" mail readers or as a fall-back and contains a summary of the event in human readable form
    • Часть 2: text/calendar; method=REQUEST, содержит содержимое файла ics (параметр заголовка method должен соответствовать методу в ics). Следите за правильной кодировкой текста, объявление параметра заголовка charset не повредит.
    • Часть 3: При желании прикрепите сам файл .ics, чтобы обычные почтовые программы могли предложить пользователю что-нибудь, на что нужно щелкнуть. Outlook на самом деле не требует вложения, потому что он просто читает text/calendar часть.
  • Отправьте письмо пользователю Outlook. Если у вас все сделано правильно, письмо отображается как приглашение на встречу с кнопками присутствия и автоматической записью в календаре пользователя после принятия.
  • Настройте что-то, что обрабатывает ответы (они отправляются организатору собрания). Мне еще не удалось настроить автоматическое отслеживание посетителей для работы с почтовым ящиком Exchange, потому что событие не существует в календаре организаторов. Outlook нужны UID и SEQUENCES, чтобы соответствовать ожиданиям, но с UID, который вы создали, это вряд ли сработает.

Чтобы получить помощь по деталям и особенностям формата файлов ics, обязательно посетите Выдержки из спецификации iCalendar от Масахиде Канзаки. Они - свет в темноте, гораздо лучше, чем пробираться сквозь RFC 2445. Но опять же, возможно, для .NET существует удобная библиотека.

person Tomalak    schedule 20.01.2009
comment
Просто не успел раньше потестить. Быстрая проверка, похоже, сработала, и я отправил приглашение на собрание Outlook учетной записи, в которой включен протокол POP3, чтобы получить необработанный дамп. Этих двух битов достаточно, чтобы я мог разобраться в остальном, так как мне нужно только отправлять встречи, но не заботиться об ответе. - person Michael Stum; 23.01.2009
comment
Удаление следующего заголовка из Части 2 помогло мне: Content-Disposition: attachment; filename = meeting.ics Пока этот заголовок находится в письме, Outlook будет отображать ICS как вложение. - person Bob; 02.12.2009
comment
Вот что происходит, когда присутствует заголовок Content-Disposition: attachment. ;-) - person Tomalak; 03.12.2009
comment
Спасибо, это было действительно полезно - я долго размышлял, почему это не работает, но понял, что отправляю почту как multipart / mixed, а не как mulitpart / альтернативу. Ага! - person Mat Mannion; 14.03.2011

См. Библиотеку 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

person Stefan Steiger    schedule 17.10.2012

iCalendar - отличное решение общего назначения, а библиотека DDay.iCal - отличный способ сделать это из .NET, но я считаю, что Веб-службы Exchange (EWS) - лучшее решение в контексте исходного вопроса (Exchange, C # /. NET).

А если вы используете язык .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("[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);
person Oran Dennison    schedule 18.08.2014
comment
Согласен, это решение намного проще других. Следует также отметить, что EWS не требует взаимодействия Outlook COM. - person JordanTDN; 11.07.2017

Приведенный ниже код отправит запрос на собрание таким образом, чтобы Outlook отображал кнопки «Принять / Отклонить».

Обратите внимание, что UID должен быть уникальным для каждой встречи, я использовал GUID.

Также обратите внимание, что вам необходимо заменить CREATED, DTSTART, DTEND, DTSTAMP, LAST-MODIFIED. Это дата / время по всемирному координированному времени.

    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="[email protected]">
        <network defaultCredentials="true" host="smtp.example.local" />
      </smtp>
    </mailSettings>
  </system.net>
person saille    schedule 24.04.2014

Вы можете отправлять запросы о встрече по почте в Outlook, используя стандарт iCal (RFC 5545)

Таким образом нельзя отправлять задачи. Вы можете отправлять «Встречи», но они отображаются в Outlook как вложения .ics, которые необходимо принимать «вслепую».

Запросы на собрания отображаются в Outlook с красивым предварительным просмотром и могут быть приняты или отклонены. Отправляющая программа может изменить или отменить встречу после ее отправки.

Создать действительный элемент iCal очень просто с помощью библиотеки DDay.iCal .Net

Код ниже представляет собой полный рабочий пример. Он создает строку с действительным запросом на собрание iCal и отправляет ее по почте.

Код создает письмо с:

  • текстовое тело для простых почтовых клиентов
  • HTML тело для рассылки в современных почтовых клиентах
  • Запрос на собрание iCal как AlternateView (будет отображаться в Outlook)
  • Запрос на собрание iCal как вложение (можно использовать в почтовых клиентах, отличных от Outlook)

В коде показано, как добавить:

  • текст описания в формате HTML, выглядит лучше в Outlook
  • Приоритет, видимость (общедоступный / частный / конфиденциальный)
  • дополнительный органайзер (будет отображаться в Outlook вместо отправителя почты)
  • необязательные участники
  • дополнительная сигнализация
  • необязательные вложения к собранию. будет отображаться в календаре Outlook

Некоторые важные детали:

  • отправитель почты (или необязательный органайзер) и получатель почты должны отличаться, чтобы эта функция работала в Outlook
  • МЕТОД в .ics и МЕТОД в Mime.ContentType должны совпадать
  • Встреча должна быть в будущем, чтобы эта работа стала перспективной.
  • часть .ics должна быть последней частью alternateView в сообщении MIME.

Точные сведения о том, как Outlook интерпретирует файлы .ics, подробно описаны в [MS-OXCICAL]: алгоритм преобразования iCalendar в объект встречи

Мы будем использовать эти сборки:

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 = "[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);

Вот функция 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>
  ...
person DrKoch    schedule 04.10.2014
comment
Спасибо за столь обстоятельный ответ! Экономит много проб и ошибок - person Tom Carver; 23.04.2016