Pull to refresh

Работа с почтой на MS Exchange сервере через EWS. Часть 1

Reading time5 min
Views99K


Здравствуйте, читатели Хабрахабр!

В рамках серии этих постов я хочу рассказать о такой технологии как EWS и о том, как ее использовать для работы с почтой, хранящейся на серверах MS Exchange 2007 — 2010. Я постараюсь показать, как просто и удобно использовать EWS.

Мы начнем с самого начала, с знакомства с это технологией и создания первого проекта, а закончим более сложными манипуляциями с почтой.

Данный пост является вводным и он, скорее всего, окажется неинтересен тем, кто уже знаком с EWS.

Введение


Exchange Web Services (EWS) — это специальный протокол, разработанный MS, и предназначенный для управления почтой и другими компонентами составляющими MS Exchange. В основе протокола лежит XML. Описание поддерживаемых операций и примеры можно найти здесь.

EWS сравнительно молодая технология, появившаяся в Exchange 2007, и пришедшая на смену протоколу WebDAV. MS вкладывает много усилий в разработку и усовершенствование EWS. Сейчас это мощнейший инструмент, с простым и понятным API, а также с прекрасной документацией, позволяющий решать задачи менеджмента объектов MS Exchange.

Архитектура EWS показана на следующей картинке:



Как видно, EWS размещается на серверах имеющих Client Access Server (CAS) роль. Это роль отвечает за обработку запросов от пользователя, т.е. любые клиента, такие как Outlook, MFCMapi, браузер + OWA и т.д., все они подсоединяются к CAS'у. Запрос от клиентского приложения попадает в IIS, где и находится application имплементирующий функциональность EWS. Т.е. EWS «живет» в IIS и выполняется в отдельном процессе или процессах w3wp.exe (процессы в которых исполняются IIS application pool'ы). Помимо EWS там могут «крутится» и другие приложения, например, OWA, ECP и PowerShell.

EWS выступает в виде прослойки между клиентским запросом и внутренностями Exchange. Когда поступает EWS-запрос от клиентского приложения, то он проксируется во внутренние вызовы Exchange, после чего поступает на Mailbox Server role, где уже и производятся сами операции.

Примечание: Немного о внутреннем устройстве Mailbox роли можно прочитать в моей предыдущей статье.

Физически EWS размещен внутри набора .NET сборок. И начиная с Exchange 2010 туда попадают не только EWS вызовы, но и OWA. Т.е. MS, видимо, осознала не удачность идеи нескольких ветвей одинакового по функциональности кода и решила оставить только одну ветку, что должно упростить и ускорить support и разработку.

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

Разработка


Нам понадобятся:
  1. MS Exchange Server 2007 — 2010 для тестирования
  2. Visual Studio 2008 — 2010
Первым делом создадим пустой консольный проект C#. Далее нужно добавить reference'ы с описанием классов/методов/типов и т.п., которые нам необходимы для работы с EWS. Самый простой способ это cделать, при наличии Exchange, это добавить Web Reference. В VS 2010 для этого нужно выделить проект и выбрать Add Service Rederence, далее Advanced, Add Web Reference и в поле URL указать адрес вашего тестового сервера в формате https://[server name]/EWS/Services.wsdl, т.е. должно получиться вот так:



После нажатия далее начнется загрузка reference'ов, и если все пройдет хорошо, вам предложат указать имя этого reference'а, и по окончанию он будет добавлен в проект.

Всё, теперь мы можем попытаться подсоединиться к серверу. И первое, что нужно сделать это получить объект ExchangeServiceBinding, это, пожалуй, самый важный объект в EWS, именно через него будут вызываться все допустимые методы и именно он идентифицирует конкретное подключение на стороне клиента. Для создания данного объекта можно воспользоваться следующим методом:

public static ExchangeServiceBinding GetBinding(
    String server, 
    String domain, 
    String user, 
    String password)
{
    var esb = new ExchangeServiceBinding();
    // Указываем используемые креды
    esb.Credentials = new NetworkCredential(user, password, domain);
    // Задаем входную точку для EWS
    esb.Url = "https://" + server + "/EWS/Exchange.asmx";
    esb.RequestServerVersionValue = new RequestServerVersion();
    // Указываем тип Exchange сервера 
    // Для Exchange 2007 SP1 и 2010 подходит Exchange2007_SP1
    // Для Exchange 2007 без SP нужно указать Exchange2007
    esb.RequestServerVersionValue.Version = ExchangeVersionType.Exchange2007_SP1;
            
    return esb;
}

Примечание: Если сервер использует self-signed сертификат, то соединиться не получится т.к. такой сертификат не пройдет валидацию. В качестве workaround'а можно добавить дополнительный код apply'щий любые сертификаты:

ServicePointManager.ServerCertificateValidationCallback = (obj, certificate, chain, errors) => true;

Имея ExchangeServiceBinding можно попытаться сделать что-нибудь полезное, например, отправить сообщение. MSDN подсказывает, что для этого нужно воспользоваться объектом CreateItemType. Для этого напишем следующий метод:

public static void SendMessage(
    ExchangeServiceBinding esb, 
    String to, 
    String subject, 
    String body)
{
    // Создаем CreateItem request
    // Он одинаковый для создания отправки сообщений 
    // Указываем, что мы хотим его именно отправить, а не сохранить
    var createItemRequest = 
        new CreateItemType
    {
        Items = new NonEmptyArrayOfAllItemsType(),
        MessageDispositionSpecified = true,
        MessageDisposition = MessageDispositionType.SendOnly
    };

    // Создаем item типа Message
    // Указываем recipients, в нашем примере только одного
    var message = new MessageType();
    message.ToRecipients = new EmailAddressType[1];
    message.ToRecipients[0] = new EmailAddressType();
    message.ToRecipients[0].EmailAddress = to;

    // Тема письма
    message.Subject = subject;

    // Содержимое письма и формат
    message.Body = new BodyType();
    message.Body.BodyType1 = BodyTypeType.Text;
    message.Body.Value = body;

    // Связываем наш request с созданным Item'ом
    createItemRequest.Items.Items = new ItemType[1];
    createItemRequest.Items.Items[0] = message;

    // Выполняем операцию
    CreateItemResponseType createItemResponse = esb.CreateItem(createItemRequest);

    // Получаем ответ
    ArrayOfResponseMessagesType responseMessages = createItemResponse.ResponseMessages;

    // Бросаем исключение, если ошибка
    var responseMessage = responseMessages.Items;
    foreach (var rmt in responseMessage.Where(rmt => rmt.ResponseClass == ResponseClassType.Error))
    {
        throw new Exception(rmt.MessageText);
    }
}


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

Вызов этого кода можно сделать так:

static void Main()
{
    ServicePointManager.ServerCertificateValidationCallback = (obj, certificate, chain, errors) => true;

    try
    {
        const String  
                server = "myserver",
                domain = "mydomain",
                user = "myuser",
                password = "mypassword",
                mailTo = "myuser2@mydomain.local",
                subject = "read me",
                body = "ehlo, developers!";
        var esb = GetBinding(server, domain, user, password);
        SendMessage(esb, mailTo, subject, body);

        Console.WriteLine("Done!");
    }
    catch (Exception e)
    {
        if(e.Message != null)
            Console.WriteLine(e.Message);
    } 
}


Если вам показалось, что код выполнился пугающе долго (у меня порядка 5 секунд), не беспокойтесь, так происходит только при первом вызове. Почти все время занимает инициализация выполняющаяся только один раз. Так же, если это был первый EWS-вызов для сервера, то серверу необходимо произвести инициализацию со своей стороны и создать новый instance w3wp для обработки запроса, а это тоже может занять какое-то время.

Заключение


Мы коротко познакомились с технологией EWS и написали простой пример отправки письма адресату.

Как видно код получается очень кратким и понятным. Документация MS достаточно хорошая и почти всегда с примерами. Если вы программировали на C++ MAPI, то вы оцените на сколько данный способ проще.

Если у вас появится задача написания почтового клиента или любые другие задачи, связанные с удаленной работой над объектами Exchange, я надеюсь, что вы воспользуетесь EWS. т.к. ИМХО данный способ наиболее простой и понятный из всех с которыми мне приходилось работать.

Спасибо, за внимание.

Продолжение следует...

Tags:
Hubs:
+11
Comments10

Articles

Change theme settings