Управление встречами: создание и изменение, конвертация ICS в MSG

Contents
[ ]

В этой статье рассматриваются стандартные iCalendar (ICS) встречи, обрабатываемые через Appointment класс. Чтобы работать с Outlook MapiCalendar элементы вместо этого, см. Управление элементами календаря Outlook; чтобы хранить и считывать элементы календаря внутри PST, см. Управление элементами календаря в файлах PST.

Создать встречу и сохранить её на диск в формате MSG или ICS

Этот Appointment класс в Aspose.Email для .NET может использоваться для создания новой встречи. В этой статье мы сначала создаём встречу и сохраняем её на диск в формате ICS. Для создания встречи и сохранения её на диск требуются следующие шаги.

  1. Создать экземпляр Appointment класс и инициализировать его с помощью этого конструктора.
  2. Передайте следующие аргументы в указанный выше конструктор
    1. Место
    2. Сводка
    3. Описание
    4. Дата начала
    5. Дата завершения
    6. Организатор
    7. Участники
  3. Вызвать Save() метод и указать имя файла и формат в аргументах.

Встречу можно открыть в Microsoft Outlook или любой программе, способной загрузить файл ICS. Если файл открыт в Microsoft Outlook, он автоматически добавит встречу в календарь Outlook.

Следующий фрагмент кода показывает, как создать и сохранить встречу на диск в формате ICS или MSG.


// Create and initialize an instance of the Appointment class
Appointment appointment = new Appointment(
    "Meeting Room 3 at Office Headquarters",// Location
    "Monthly Meeting",                      // Summary
    "Please confirm your availability.",    // Description
    new DateTime(2015, 2, 8, 13, 0, 0),     // Start date
    new DateTime(2015, 2, 8, 14, 0, 0),     // End date
    "from@domain.com",                      // Organizer
    "attendees@domain.com");                // Attendees

// Save the appointment to disk in ICS format            
appointment.Save(fileName + ".ics", new AppointmentIcsSaveOptions());
Console.WriteLine("Appointment created and saved to disk successfully.");

// Save the appointment to disk in MSG format
appointment.Save(fileName + ".msg", new AppointmentMsgSaveOptions());
Console.WriteLine("Appointment created and saved to disk successfully.");

Создание встречи с HTML‑содержимым

Вы можете указать альтернативные представления описания события в разных типах контента, используя заголовок X-ALT-DESC. Это позволяет получателям файла iCalendar выбирать представление, которое лучше соответствует их потребностям. Например, можно включить описание в простом тексте с типом контента "text/plain" и описание в HTML с типом контента "text/html". Для каждого альтернативного представления добавляется заголовок X-ALT-DESC. Чтобы создать встречу с HTML‑содержимым, установите HtmlDescription свойство.

Попробуйте следующий пример кода для создания встречи с альтернативным HTML‑описанием:

  1. Создайте новый экземпляр класса Appointment.
  2. Передайте необходимые параметры в конструктор Appointment:
    • Укажите место проведения встречи.
    • Установите дату и время начала.
    • Установите дату и время окончания.
    • Укажите организатора.
    • Укажите участника.
  3. Установите HtmlDescription свойство объекта встречи, указывающее, что описание в формате HTML.
  4. Установите свойство Description объекта встречи в строку формата HTML, заключённую в многострочную строку:
    • Разметка HTML включает блок <style>, определяющий CSS‑класс с именем "text" со стилями шрифта.
    • Тело HTML содержит тег абзаца <p> с CSS‑классом "text" и фактическое сообщение‑приглашение.
  5. Объект встречи теперь готов, и вы можете выполнять дальнейшие операции или сохранить его как файл iCalendar.
var appointment = new Appointment("Bygget 83",
    DateTime.UtcNow, // start date
    DateTime.UtcNow.AddHours(1), // end date
    new MailAddress("TintinStrom@from.com", "Tintin Strom"), // organizer
    new MailAddress("AinaMartensson@to.com", "Aina Martensson")) // attendee
{
    HtmlDescription = @"
    <html>
     <style type=""text/css"">
      .text {
             font-family:'Comic Sans MS';
             font-size:16px;
            }
     </style>
    <body>
     <p class=""text"">Hi, I'm happy to invite you to our party.</p>
    </body>
    </html>"
};

Создание запроса черновика встречи

В наших предыдущих статьях было показано, как создать и сохранить встречу в формате ICS. Часто требуется создать запрос встречи в режиме черновика, чтобы базовая информация была внесена, а затем такой черновик встречи мог быть переслан другим пользователям для внесения необходимых изменений в соответствии с их потребностями. Чтобы сохранить встречу в режиме черновика, MethodType свойство класса Appointment должно быть установлено в AppointmentMethodType.Publish. Следующий фрагмент кода показывает, как создать черновик запроса встречи.

string sender = "test@gmail.com";
string recipient = "test@email.com";

MailMessage message = new MailMessage(sender, recipient, string.Empty, string.Empty);

Appointment app = new Appointment(string.Empty, DateTime.Now, DateTime.Now, sender, recipient)
{
    MethodType = AppointmentMethodType.Publish
};

message.AddAlternateView(app.RequestApointment());

MapiMessage msg = MapiMessage.FromMailMessage(message);

// Save the appointment as draft.
msg.Save(dstDraft);

Console.WriteLine(Environment.NewLine + "Draft saved at " + dstDraft);

Создание черновика встречи из текста

Следующий фрагмент кода показывает, как создать черновик встречи из текста. 

string ical = @"BEGIN:VCALENDAR
METHOD:PUBLISH
PRODID:-//Aspose Ltd//iCalender Builder (v3.0)//EN
VERSION:2.0
BEGIN:VEVENT
ATTENDEE;CN=test@gmail.com:mailto:test@gmail.com
DTSTART:20130220T171439
DTEND:20130220T174439
DTSTAMP:20130220T161439Z
END:VEVENT
END:VCALENDAR";

string sender = "test@gmail.com";
string recipient = "test@email.com";
MailMessage message = new MailMessage(sender, recipient, string.Empty, string.Empty);
AlternateView av = AlternateView.CreateAlternateViewFromString(ical, new ContentType("text/calendar"));
message.AlternateViews.Add(av);
MapiMessage msg = MapiMessage.FromMailMessage(message);
msg.Save(dataDir + "draft_out.msg");

Настройка встреч

Установка статуса участников встречи

API Aspose.Email для .NET позволяет задавать статус участников встречи при формировании сообщения-ответа. Это добавляет свойство PARTSTAT в файлICS.

DateTime startDate = new DateTime(2011, 12, 10, 10, 12, 11),
         endDate = new DateTime(2012, 11, 13, 13, 11, 12);
MailAddress organizer = new MailAddress("aaa@amail.com", "Organizer");
MailAddressCollection attendees = new MailAddressCollection();
MailAddress attendee1 = new MailAddress("bbb@bmail.com", "First attendee");
MailAddress attendee2 = new MailAddress("ccc@cmail.com", "Second attendee");

attendee1.ParticipationStatus = ParticipationStatus.Accepted;
attendee2.ParticipationStatus = ParticipationStatus.Declined;
attendees.Add(attendee1);
attendees.Add(attendee2);

Appointment target = new Appointment(location, startDate, endDate, organizer, attendees);

Настройка идентификатора продукта для iCalendar

API Aspose.Email для .NET позволяет получать или задавать идентификатор продукта, создавшего объект iCalendar.

string description = "Test Description";
Appointment app = new Appointment("location", "test appointment", description, DateTime.Today,
DateTime.Today.AddDays(1), "first@test.com", "second@test.com");

AppointmentIcsSaveOptions saveOptions = AppointmentIcsSaveOptions.Default;
saveOptions.ProductId = "Test Corporation";
app.Save(dataDir + "ChangeProdIdOfICS.ics", saveOptions);

Загрузка встреч

Также Appointment класс может использоваться для загрузки встречи из файла ICS.

Загрузка встречи в формате ICS

Чтобы загрузить встречу в формате ICS, требуется выполнить следующие шаги:

  1. Создать экземпляр Appointment класс.
  2. Вызвать Load() метод, указывая путь к файлу ICS.
  3. Прочитайте любое свойство, чтобы получить любую информацию о встрече (файл ICS).

Следующий фрагмент кода показывает, как загрузить встречу в формате ICS.

// Load an Appointment just created and saved to disk and display its details.
Appointment loadedAppointment = Appointment.Load(dstEmail);
Console.WriteLine(Environment.NewLine + "Loaded Appointment details are as follows:");
// Display the appointment information on screen
Console.WriteLine("Summary: " + loadedAppointment.Summary);
Console.WriteLine("Location: " + loadedAppointment.Location);
Console.WriteLine("Description: " + loadedAppointment.Description);
Console.WriteLine("Start date: " + loadedAppointment.StartDate);
Console.WriteLine("End date: " + loadedAppointment.EndDate);
Console.WriteLine("Organizer: " + loadedAppointment.Organizer);
Console.WriteLine("Attendees: " + loadedAppointment.Attendees);
Console.WriteLine(Environment.NewLine + "Appointment loaded successfully from " + dstEmail);

Конвертировать ICS в MSG

API позволяет легко преобразовать встречу в объект сообщения. Следующий пример кода показывает, как конвертировать запрос встречи в MailMessage или MapiMessage:

var appointment = Appointment.Load("appRequest.ics");

var eml = appointment.ToMailMessage();
var msg = appointment.ToMapiMessage();

Чтение нескольких событий из файла ICS

List<Appointment> appointments = new List<Appointment>();
CalendarReader reader = new CalendarReader(dataDir + "US-Holidays.ics");

while (reader.NextEvent())
{
    appointments.Add(reader.Current);
}
//working with appointments...

Записать несколько событий в файл ICS

AppointmentIcsSaveOptions saveOptions = new AppointmentIcsSaveOptions();
saveOptions.Action = AppointmentAction.Create;
using (CalendarWriter writer = new CalendarWriter(dataDir + "WriteMultipleEventsToICS_out.ics", saveOptions))
{
    for (int i = 0; i < 10; i++)
    {
        Appointment app = new Appointment(string.Empty, DateTime.Now, DateTime.Now, "sender@domain.com", "receiver@domain.com");
        app.Description = "Test body " + i;
        app.Summary = "Test summary:" + i;
        writer.Write(app);
    }
}

Определить версию встречи

Чтобы определить версию встречи, вы можете использовать Appointment.Version свойство Appointment класс. Это свойство помогает определить, на какой версии основаны их файлы, обеспечивая интеграцию с другими системами и приложениями.

Следующий образец кода показывает, как реализовать это свойство в вашем проекте:

var app = Appointment.Load("meeting.ics");

// Version is a string that holds the ICS/VCS version, e.g. "2.0" for iCalendar
if (app.Version == "2.0")
{
    // do something
}

Отправка и отмена запросов на встречи

Этот Appointment класс, вместе с SmtpClient, может использоваться для отправки запросов на встречи, повторяющихся встреч, обновлений и отмен по электронной почте. Встреча добавляется в MailMessage в виде альтернативного представления.

Отправить запрос на встречу

Чтобы отправить запрос на встречу, создайте Appointment, добавьте её к сообщению с помощью RequestApointment метод, и отправьте сообщение. Сохраните UniqueId значение, чтобы позже можно было сослаться на ту же встречу при отправке обновления или отмены.

// Create an instance of SmtpClient
SmtpClient client = new SmtpClient("smtp.gmail.com", 587, "user@gmail.com", "password");
client.SecurityOptions = SecurityOptions.Auto;

// Gather the attendees
MailAddressCollection attendees = new MailAddressCollection();
attendees.Add(new MailAddress("first.attendee@domain.com", "First Attendee"));
attendees.Add(new MailAddress("second.attendee@domain.com", "Second Attendee"));

// Create the message and the appointment
MailMessage msg = new MailMessage();
msg.From = "organizer@domain.com";
msg.To = attendees;

Appointment app = new Appointment("Meeting Room 1", DateTime.Now, DateTime.Now.AddHours(1), msg.From, attendees);
app.Summary = "Monthly Meeting";
app.Description = "Please confirm your availability.";

// Add the appointment to the message and send it
msg.AddAlternateView(app.RequestApointment());
client.Send(msg);

Отправить запрос на повторяющуюся встречу

Чтобы создать запрос на встречу с повторением, укажите рекуррентный паттерн (например, WeeklyRecurrencePattern) к Appointment.Recurrence свойство. Сохранение уникального идентификатора встречи позволяет позже отправлять обновления.

// Create a mail message
MailMessage msg1 = new MailMessage();
msg1.To.Add("to@domain.com");
msg1.From = new MailAddress("from@gmail.com");

// Fill the appointment object
DateTime startDate = new DateTime(2013, 12, 1, 17, 0, 0);
DateTime endDate = new DateTime(2013, 12, 31, 17, 30, 0);
Appointment agendaAppointment = new Appointment("same place", startDate, endDate, msg1.From, msg1.To);

// Create a unique id so the appointment can be accessed later
string szUniqueId = Guid.NewGuid().ToString();
agendaAppointment.UniqueId = szUniqueId;
agendaAppointment.Description = "----------------";

// Create a weekly recurrence pattern: Mon, Tue and Thu
WeeklyRecurrencePattern pattern1 = new WeeklyRecurrencePattern(14);
pattern1.StartDays = new CalendarDay[3];
pattern1.StartDays[0] = CalendarDay.Monday;
pattern1.StartDays[1] = CalendarDay.Tuesday;
pattern1.StartDays[2] = CalendarDay.Thursday;
pattern1.Interval = 1;

// Set the recurrence pattern for the appointment
agendaAppointment.Recurrence = pattern1;

// Attach the appointment to the mail
msg1.AlternateViews.Add(agendaAppointment.RequestApointment());

// Send the mail with the appointment request
SmtpClient client = new SmtpClient("smtp.gmail.com", 587, "your.email@gmail.com", "your.password");
client.SecurityOptions = SecurityOptions.Auto;
client.Send(msg1);

Отправить запрос обновления встречи

Для отправки обновления ранее отправленной встречи требуется уникальный идентификатор встречи. Используйте UpdateAppointment метод для создания альтернативного представления обновления.

static public void SendUpdate(string szUniqueId)
{
    DateTime startDate = new DateTime(2013, 12, 12, 17, 0, 0);
    DateTime endDate = new DateTime(2013, 12, 12, 17, 30, 0);
    Appointment appUpdate = new Appointment("Different Place", startDate, endDate,
        "organizer@gmail.com", "attendee@domain.com");
    appUpdate.UniqueId = szUniqueId;
    appUpdate.Summary = "update meeting request summary";
    appUpdate.Description = "update";

    MailMessage msgUpdate = new MailMessage("organizer@gmail.com", "attendee@domain.com",
        "test email - update meeting request", "test email");
    msgUpdate.AddAlternateView(appUpdate.UpdateAppointment());

    SmtpClient smtp = new SmtpClient("server.domain.com", 587, "username", "password");
    smtp.Send(msgUpdate);
}

Отменить запрос на встречу

Чтобы отменить встречу, сформируйте такой же Appointment (используя информацию, сохраненную при отправке запроса), добавьте её к сообщению с помощью CancelAppointment метод, и отправьте сообщение участникам.

// Re-create the attendee collection and the appointment from your stored data
MailAddressCollection attendees = new MailAddressCollection();
attendees.Add(new MailAddress("first.attendee@domain.com", "First Attendee"));
attendees.Add(new MailAddress("second.attendee@domain.com", "Second Attendee"));

Appointment app = new Appointment("Meeting Room 1", "Monthly Meeting", "Please confirm your availability.",
    DateTime.Now, DateTime.Now.AddHours(1),
    new MailAddress("organizer@domain.com", "Organizer"), attendees);

// Create the cancellation message
MailMessage msg = new MailMessage();
msg.From = new MailAddress("organizer@domain.com", "");
msg.To = attendees;
msg.Subject = "Cancel meeting";
msg.AddAlternateView(app.CancelAppointment());

SmtpClient smtp = new SmtpClient("smtp.gmail.com", 587, "user@gmail.com", "password");
smtp.Send(msg);

Работа с рекуррентными паттернами iCalendar

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

Рекуррентные паттерны могут включать исключения (не путать с исключениями, представляющими ошибки во время выполнения программы). Исключения добавляют или удаляют даты повторений относительно исходного паттерна. Их можно задавать как явные повторения или как собственный паттерн. Примеры рекуррентных паттернов с исключениями:

  • Каждая вторая пятница, кроме периода с июня по август.
  • 1‑е число каждого месяца, кроме января, когда должно быть 2‑е.

RFC iCalendar определяет компоненты, такие как VEVENT или VTODO, которые представляют события или задачи. У компонентов могут быть свойства, такие как дата/время начала, описание, местоположение, участники и повторения. Паттерн повторения обычно является свойством повторяющейся задачи или события. Свойства паттерна повторения, определенные iCalendar:

  • DTSTART — дата и время начала паттерна (также представляет первое событие, если оно явно не исключено).
  • RRULE — задает правило повторения для набора повторений.
  • RDATE — определяет список дат и времени, включаемых в набор повторений.
  • EXRULE — задает правило повторения для исключений из набора повторений.
  • EXDATE — определяет список дат и времени исключений из набора повторений.

Требуется только DTSTART, и он может быть указан только один раз. Все остальные свойства являются необязательными и могут задаваться более одного раза.

Модель объектов рекуррентности Aspose.Email

Этот Aspose.Email.Calendar.Recurrences пространство имен содержит классы для работы с рекуррентными объектами iCalendar. CalendarRecurrence и RecurrenceRule являются центральными классами и предоставляют конкретные реализации соответствующих элементов RFC 2445.

  • Этот CalendarRecurrence класс представляет весь рекуррентный паттерн. Вы можете создать новый паттерн с нуля, используя конструктор по умолчанию, или загрузить существующий паттерн в формате iCalendar, используя статический FromiCalendar метод.
  • Этот RecurrenceRule класс представляет часть RRULE или EXRULE шаблона повторения. RecurrenceRule открывает ряд свойств, напрямую сопоставляемых с их аналогами в стандарте iCalendar. Например, ByMonth соответствует BYMONTH в iCalendar и т.д. Анализируя или задавая значения RecurrenceRule свойства, вы можете анализировать или изменять правило повторения.

Следующий фрагмент кода загружает рекуррентный паттерн (в котором часть RRULE содержит правило повторения) и генерирует повторения:

// Ten team meetings, every Monday at 10am.
CalendarRecurrence pattern = new CalendarRecurrence("DTSTART:20040301T100000\n" + "RRULE:FREQ=WEEKLY;COUNT=10;BYDAY=MO");
DateCollection dates = pattern.GenerateOccurrences();

Генерация повторений из рекуррентного паттерна

С Aspose.Email можно генерировать повторения из рекуррентного паттерна. Чтобы получить «следующее» повторение, используйте GenerateOccurrences метод с параметром nNextOccurrences = 1. Следующий фрагмент кода генерирует 20 повторений, используя GenerateOccurrences(20).

CalendarRecurrence recurrencePattern = new CalendarRecurrence();
recurrencePattern.StartDate = new DateTime(1997, 9, 10, 9, 0, 0);
RecurrenceRule rule = recurrencePattern.RRules.Add();
rule.Frequency = Frequency.Monthly;
rule.Count = 20;
rule.Interval = 18;
rule.ByMonthDay.Add(new int[] { 10, 11, 12, 13, 14, 15 });
DateCollection expectedDates = recurrencePattern.GenerateOccurrences(20);
Console.WriteLine("expectedDates.Count = " + expectedDates.Count);
foreach (DateTime date in expectedDates)
{
    Console.WriteLine("DateTime = " + date);
}

Получить удобный для пользователя текст рекуррентного правила

Текст, удобный для пользователя, для правила можно получить с помощью FriendlyText свойство. Вывод следующего кода: "Повторять каждый месяц 1‑е и 1‑е с конца дня(дней) месяца максимум 2 раза."

RecurrenceRule rule = new RecurrenceRule();
rule.Frequency = Frequency.Monthly;
rule.Count = 2;
rule.ByMonthDay.Add(1);
rule.ByMonthDay.Add(-1);
Console.WriteLine(rule.FriendlyText);

Примеры рекуррентных паттернов

Следующие образцы строк RRULE показывают, как выражать типичные расписания.

  • Последний день месяца, каждый месяц. Если вам нужно событие за день до последнего дня месяца, используйте BYMONTHDAY=-2. Если вы указываете BYMONTHDAY=31, тогда согласно стандарту iCalendar, событие не генерируется в месяцах, в которых меньше 31 дня.

    RRULE:FREQ=MONTHLY;BYMONTHDAY=-1
    
  • Последний рабочий день каждого месяца. Это правило выбирает все рабочие дни месяца и выбирает последний из них. В результате получается последний рабочий день месяца.

    RRULE:FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1
    
  • Последний понедельник года.

    RRULE:FREQ=YEARLY;BYDAY=-1MO
    
  • Пятница первой недели ISO 8601 года. В спецификации ISO 8601 первая неделя года — первая, содержащая минимум четыре дня.

    FREQ=YEARLY;BYWEEKNO=1;BYDAY=FR
    
  • Первый пятничный день года. В 1999 году, например, первый пятничный день года — 1999/01/01, тогда как пятница первой недели ISO 8601 — 1999/01/08.

    FREQ=YEARLY;BYDAY=1FR
    

Важные детали iCalendar (RFC 2445)

Даты или даты со временем могут использоваться в элементах DTSTART, UNTIL, EXDATE и RDATE при указании рекуррентного паттерна. iCalendar определяет тип значения DATE для календарных дат и тип DATE‑TIME для точных дат и времени. DATE‑TIME может быть задан в трех формах: локальное время, время UTC и локальное время с часовым поясом.

  • DATE. Согласно стандарту iCalendar, значения DATE должны соответствовать yyyyMMdd формат. Например, 19970714 представляет 14 июля 1997 года.
  • DATE‑TIME с локальным временем. Дата в форме локального времени — это просто значение даты‑времени без индикатора UTC и без ссылки на часовой пояс. Например, DTSTART:19980118T230000 представляет 18 января 1998 года, 23:00. Дата‑временные значения этого типа называют «плавающими»; они не привязаны к какому‑либо часовому поясу и представляют одинаковые часы, минуты и секунды независимо от текущего часового пояса.
  • DATE‑TIME с временем UTC. Дата с UTC‑временем (абсолютным временем) обозначается заглавной буквой Z добавляемый к значению времени. Например, DTSTART:19980119T070000Z представляет 19 января 1998 года, 07:00 UTC. Обратите внимание, что Aspose.Email игнорирует суффикс UTC, Z суффикс и считает время локальным. Стандарт RFC 2445 гласит, что время в правиле UNTIL рекуррентного паттерна должно быть в формате UTC; Aspose.Email принимает время в любом формате в правиле UNTIL.
  • DATE‑TIME с локальным временем и часовым поясом. Для указания часового пояса свойство DATE‑TIME изменяется с помощью свойства TZID. Например, DTSTART;TZID=US-Eastern:19980119T020000 представляет 2 утра в Нью‑Йорке 19 января 1998 года. Обратите внимание, что Aspose.Email в текущей версии игнорирует параметр TZID и считает время локальным.
  • BYWEEKNO и соответствие ISO 8601. Используйте BYWEEKNO только когда требуется соответствие ISO 8601 требуется. Номера недель, определяемые ISO 8601, отличаются от обычных: первая неделя календарного года — это первая неделя, содержащая минимум четыре дня. Правило BYWEEKNO задает список номеров недель года через запятую (допустимые значения от 1 до 53 и от -1 до -53) и доступно только для YEARLY‑правил.

См. также