Интеграция корпоративной почты на базе Microsoft Exchange Server 2013 (и более новых версий) с платформой 1С:Предприятие 8.3 — классическая задача, с которой сталкивается практически каждый разработчик в крупной компании. Специфика Exchange заключается в его тесной связи со службой каталогов Active Directory (AD), жестких требованиях к безопасности (использование TLS-шифрования) и поддержке современных веб-служб EWS (Exchange Web Services).
В процессе настройки такого взаимодействия разработчики часто сталкиваются со специфическими трудностями: отсутствием почтового клиента на терминальных серверах, ошибками авторизации, невозможностью корректно отправить почту по защищенным каналам или сбоями при прикреплении тяжелых файлов к письмам. В этой статье мы подробно разберем, как решить все эти проблемы штатными и альтернативными инструментами 1С. В частности, если учет ведется в 1С:Бухгалтерии 3.0, можно автоматизировать создание счетов и договоров в 1С по письмам с заказами от клиентов.
Мы проанализируем различные подходы к интеграции: от настройки классического SMTP-релея до написания прямых HTTP-запросов к EWS и использования внешних утилит.
Среди разработчиков долгое время существовал миф, что 1С не умеет работать с современными протоколами шифрования (в частности, TLS), которые требует Exchange 2013. На самом деле, современные версии платформы 1С:Предприятие 8.3 (начиная с релиза 8.3.9) полностью поддерживают TLS 1.2 и TLS 1.3 на уровне платформы.
Для отправки почты через защищенный канал SMTP нам понадобится объект ИнтернетПочтовыйПрофиль и инициализация защищенного соединения. Рассмотрим пример настройки почтового профиля для отправки писем:
Профиль = Новый ИнтернетПочтовыйПрофиль;
Профиль.АдресСервераSMTP = "exchange.company.local";
Профиль.ПортSMTP = 587; // Стандартный порт для SMTP с TLS (STARTTLS)
// Включаем использование защищенного соединения SSL/TLS
Профиль.ИспользоватьSSLSMTP = Истина;
Профиль.ТолькоЗащищеннаяАутентификация = Ложь;
// Указываем доменные учетные данные пользователя
Профиль.ПользовательSMTP = "domain\user_mail";
Профиль.ПарольSMTP = "v@ry_Str0ng_P@ss";
Профиль.АутентификацияSMTP = СпособSMTPАутентификации.Login;
Почта = Новый ИнтернетПочта;
Письмо = Новый ИнтернетПочтовоеСообщение;
Письмо.Тема = "Тестовое сообщение из 1С через TLS";
Письмо.Отправитель = "user_mail@company.ru";
Письмо.Получатели.Добавить("recipient@external.com");
Текст = Письмо.Тексты.Добавить("Приветствуем! Данное письмо отправлено напрямую через почтовый сервер Exchange.");
Текст.ТипТекста = ТипТекстаПочтовогоСообщения.ПростойТекст;
Попытка
Почта.Подключиться(Профиль);
Почта.Послать(Письмо);
Почта.Отключиться();
Сообщить("Письмо успешно отправлено!");
Исключение
Сообщить("Ошибка при отправке почты: " + ОписаниеОшибки());
КонецПопытки;
Важное примечание для старых версий платформы 1С: Если по каким-то причинам ваша конфигурация работает на устаревшей платформе, которая не поддерживает TLS напрямую, можно прибегнуть к двум системным решениям:
Если вам требуется не просто отправлять почту, а полноценно взаимодействовать с ящиком (создавать черновики, искать письма, работать с календарями Exchange), классического протокола SMTP/POP3 будет недостаточно. В этом случае на помощь приходит веб-служба Exchange Web Services (EWS), которая принимает SOAP-запросы (XML-пакеты) по протоколу HTTP/HTTPS.
Для интеграции с EWS мы можем использовать объект HTTPСоединение. Одним из главных преимуществ такого подхода является поддержка сквозной доменной авторизации (Windows-авторизации/NTLM) без необходимости хранить и передавать пароли пользователей в явном виде.
Давайте разберем, как инициализировать соединение с EWS с использованием доменной авторизации:
// Для доменной авторизации (SSO) используем параметр ИспользоватьАутентификациюОС = Истина
// При этом параметры "Пользователь" и "Пароль" оставляем пустыми.
// Платформа автоматически подставит учетные данные пользователя Windows, под которым запущен сеанс 1С
// (или под которыми запущен процесс сервера 1С:Предприятия, если код выполняется на сервере).
СерверExchange = "exchange.company.local";
ЗащищенноеСоединение = Новый ЗащищенноеСоединениеOpenSSL();
HTTPСоединение = Новый HTTPСоединение(
СерверExchange, // Адрес сервера
443, // HTTPS-порт
, // Пользователь (пусто для SSO)
, // Пароль (пусто для SSO)
, // Прокси
30, // Таймаут в секундах
ЗащищенноеСоединение,
Истина // Использовать аутентификацию ОС (NTLM/Negotiate)
);
Теперь мы можем сформировать SOAP-запрос для создания и отправки сообщения. Обмен с EWS происходит посредством отправки XML-структур в теле POST-запроса на адрес /ews/exchange.asmx.
При реализации обмена с EWS через HTTPСоединение разработчики часто сталкиваются с крайне загадочной проблемой: мелкие запросы и отправка писем без вложений работают идеально, но как только к письму прикрепляется файл размером более 100 КБ, сервер Exchange возвращает ошибку 401 Unauthorized (или 401 Не авторизован).
Выясним причину этого поведения. Она кроется в особенностях реализации протокола HTTP/1.1 в платформе 1С и механизме веб-сервера IIS, на котором работает Exchange.
По умолчанию, при передаче больших объемов данных (бинарных файлов) платформа 1С автоматически добавляет в HTTP-запрос служебный заголовок Expect: 100-continue. Этот заголовок сообщает серверу: «Я собираюсь отправить большой объем данных, подтверди свою готовность».
Однако веб-сервер IIS при использовании NTLM-авторизации (Kerberos/Negotiate) некорректно обрабатывает этот заголовок во время многоэтапного процесса хэндшейка (авторизации). IIS разрывает соединение до завершения авторизации, возвращая ошибку 401.
Решение проблемы чрезвычайно простое: необходимо принудительно отключить (очистить) заголовок Expect перед отправкой HTTP-запроса в 1С. Рассмотрим пример отправки запроса с вложением:
ЗапросHTTP = Новый HTTPЗапрос("/ews/exchange.asmx");
ЗапросHTTP.Заголовки.Вставить("Content-Type", "text/xml; charset=utf-8");
// КРИТИЧЕСКИ ВАЖНАЯ СТРОКА: убираем заголовок Expect для обхода ошибки 401 NTLM
ЗапросHTTP.Заголовки.Вставить("Expect", "");
// Формируем XML-тело SOAP-запроса для создания вложения (CreateAttachment)
// (ПутьКФайлуЗапроса содержит заранее сформированный XML с base64-кодом вашего вложения)
ЗапросHTTP.УстановитьИмяФайлаТела(ПутьКФайлуЗапроса);
Попытка
ОтветHTTP = HTTPСоединение.ОтправитьДляОбработки(ЗапросHTTP);
Если ОтветHTTP.КодСостояния = 200 Тогда
Сообщить("Вложение успешно передано в Exchange!");
Иначе
Сообщить("Ошибка сервера Exchange. Код ответа: " + ОтветHTTP.КодСостояния);
Сообщить("Текст ответа: " + ОтветHTTP.ПолучитьТелоКакСтроку());
КонецЕсли;
Исключение
Сообщить("Не удалось связаться с сервером EWS: " + ОписаниеОшибки());
КонецПопытки;
Очистка заголовка Expect заставляет платформу отправлять все данные сразу в одном пакете вместе с авторизационными токенами, что решает проблему с ошибкой 401 раз и навсегда.
Если ручное формирование SOAP XML-пакетов для EWS кажется вам слишком трудоемким и избыточным процессом, можно прибегнуть к надежным системным альтернативам.
Операционная система Windows имеет встроенный мощный инструмент автоматизации — PowerShell. В доменной среде PowerShell может бесшовно отправлять письма через Exchange, используя авторизацию текущего пользователя Windows. Нам достаточно вызвать скрипт из 1С.
Рассмотрим, как реализовать этот метод по шагам:
// Определяем параметры письма
Кому = "recipient@company.ru";
Тема = "Отчет по продажам";
Тело = "Добрый день! Во вложении свежий отчет.";
ПутьКВложению = "C:\temp\report.xlsx";
// Формируем команду PowerShell
// Используем командлет Send-MailMessage с параметром -UseSsl
ШаблонСкрипта =
"Send-MailMessage -SmtpServer 'exchange.company.local' " +
"-Port 587 -UseSsl " +
"-To '%1' -From '1c-sender@company.ru' " +
"-Subject '%2' -Body '%3' " +
"-Attachments '%4' -Encoding UTF8";
КомандаPS = СтрШаблон(ШаблонСкрипта, Кому, Тема, Тело, ПутьКВложению);
// Записываем скрипт во временный файл .ps1 для избежания проблем с кодировкой командной строки
ИмяФайлаСкрипта = КаталогВременныхФайлов() + "send_mail.ps1";
ТекстовыйДокумент = Новый ТекстовыйДокумент;
ТекстовыйДокумент.УстановитьТекст(КомандаPS);
ТекстовыйДокумент.Записать(ИмяФайлаСкрипта, КодировкаТекста.ANSI);
// Запускаем процесс выполнения скрипта в фоновом режиме
ПараметрыЗапуска = "-ExecutionPolicy Bypass -File """ + ИмяФайлаСкрипта + """";
ЗапуститьПриложение("powershell.exe " + ПараметрыЗапуска, , Истина); // Третий параметр Истина заставит 1С ожидать завершения отправки
Этот метод не требует сложных настроек в 1С, автоматически наследует доменные права безопасности и отлично справляется с вложениями любого объема.
Microsoft предоставляет готовую библиотеку для работы с Exchange — EWS Managed API (файл Microsoft.Exchange.WebServices.dll). С ее помощью можно обращаться к объектам Exchange через понятные методы, избегая написания сложных XML-запросов. Вы можете зарегистрировать эту библиотеку в операционной системе и вызывать ее методы через .NET/COM-объекты из кода 1С.
Пример логики подключения к EWS Managed API в 1С выглядит следующим образом:
// Загружаем сборку EWS API через COM-объект или внешнюю компоненту Elisy .Net Bridge
// (в примере показана концептуальная схема работы с объектами .NET)
Попытка
Service = Новый COMОбъект("Microsoft.Exchange.WebServices.Data.ExchangeService");
Service.Url = Новый COMОбъект("System.Uri")("https://exchange.company.local/ews/exchange.asmx");
Service.UseDefaultCredentials = Истина; // Используем доменную авторизацию текущего сеанса
Email = Новый COMОбъект("Microsoft.Exchange.WebServices.Data.EmailMessage")(Service);
Email.Subject = "Письмо через EWS Managed API";
Email.Body = "Приветствуем! Это письмо сформировано через официальную библиотеку Microsoft.";
Email.ToRecipients.Add("recipient@company.ru");
Email.Attachments.AddFileAttachment("C:\temp\report.xlsx");
// Отправляем письмо и сохраняем копию в отправленных
Email.SendAndSaveCopy();
Сообщить("Успешно отправлено через EWS API!");
Исключение
Сообщить("Ошибка при работе с EWS Managed API: " + ОписаниеОшибки());
КонецПопытки;
Мы подробно проанализировали особенности взаимодействия 1С 8.3 с почтовым сервером Microsoft Exchange 2013. В зависимости от архитектурных ограничений и задач вашей организации вы можете выбрать один из рассмотренных путей: