При автоматизации бизнес-процессов часто возникает задача отправлять печатную форму или данные документа на электронную почту сразу после его проведения (например, при приеме сотрудника на работу). Однако попытка встроенной отправки письма прямо из модуля документа в процедуре ОбработкаПроведения является серьезной ошибкой. В этом материале разберем, почему не стоит отправлять почту внутри транзакции проведения и как правильно построить архитектуру решения с использованием подписок на события, регистров сведений и регламентных заданий.
Рассмотрим риски и проблемы, к которым приводит отправка почты непосредственно в обработке проведения:
Для решения этой задачи проанализируем два правильных архитектурных подхода, которые позволяют сохранить конфигурацию обновляемой и обезопасить проведение документов.
Разберем наиболее надежный вариант. Вся логика разделяется на два этапа: быстрое сохранение события в очередь при проведении и асинхронная отправка сообщений фоновым или регламентным заданием.
Рассмотрим пошаговую реализацию:
ОчередьОтправкиПочты с измерением Документ (ссылка на документ) и ресурсом ДатаЗаписи.ПриЗаписи или ОбработкаПроведения для нужных документов. В обработчике подписки записываем ссылку на проведенный документ в регистр сведений. Это выполняется мгновенно и не задерживает транзакцию.Посмотрим на пример функции отправки почты через объект ИнтернетПочта:
Функция ОтправитьНаЭлектроннуюПочту(Получатели, Тема, Текст, ПутьКФайлуВложения = Неопределено) Экспорт
Профиль = Новый ИнтернетПочтовыйПрофиль;
Профиль.АутентификацияSMTP = СпособSMTPАутентификации.ПоУмолчанию;
Профиль.АдресСервераSMTP = "smtp.yourserver.com";
Профиль.ПортSMTP = 25;
Профиль.Пользователь = "user@domain.com";
Профиль.ПользовательSMTP = "user@domain.com";
Профиль.ПарольSMTP = "Password";
Профиль.ВремяОжидания = 60;
ПочтовоеСообщение = Новый ИнтернетПочтовоеСообщение;
ПочтовоеСообщение.Тема = Тема;
ПочтовоеСообщение.Отправитель.Адрес = "user@domain.com";
ПочтовоеСообщение.Отправитель.ОтображаемоеИмя = "1С:Предприятие";
Если ТипЗнч(Получатели) = Тип("Массив") Тогда
Для Каждого Адрес Из Получатели Цикл
ПочтовоеСообщение.Получатели.Добавить(СокрЛП(Адрес));
КонецЦикла;
ИначеЕсли ТипЗнч(Получатели) = Тип("Строка") Тогда
ПочтовоеСообщение.Получатели.Добавить(СокрЛП(Получатели));
КонецЕсли;
Если ЗначениеЗаполнено(ПутьКФайлуВложения) Тогда
ПочтовоеСообщение.Вложения.Добавить(ПутьКФайлуВложения);
КонецЕсли;
ПочтовоеСообщение.Тексты.Добавить(Текст, ТипТекстаПочтовогоСообщения.ПростойТекст);
Почта = Новый ИнтернетПочта;
Попытка
Почта.Подключиться(Профиль);
Почта.Послать(ПочтовоеСообщение);
Почта.Отключиться();
Возврат Истина;
Исключение
Комментарий = "Ошибка при отправке сообщения: " + ОписаниеОшибки();
ЗаписьЖурналаРегистрации("ОтправкаПочты.Ошибка", УровеньЖурналаРегистрации.Ошибка, , , Комментарий);
Возврат Ложь;
КонецПопытки;
КонецФункции
В некоторых случаях стандартный объект ИнтернетПочта может иметь проблемы со специфическими почтовыми серверами (например, Microsoft Exchange) или требовать обхода особенностей аутентификации. На платформах под управлением ОС Windows можно использовать системный COM-объект CDO.Message.
Проанализируем пример кода отправки письма с использованием CDO.Message из регламентного задания:
Процедура ОтправитьПисьмочерезCDO(СтруктураПолучателя) Экспорт
Попытка
Письмо = Новый COMОбъект("CDO.Message");
Исключение
ЗаписьЖурналаРегистрации("ПочтоваяПодсистема.Ошибка",
УровеньЖурналаРегистрации.Ошибка, , , ОписаниеОшибки());
Возврат;
КонецПопытки;
Письмо.To = СтруктураПолучателя.Кому;
Письмо.From = СтруктураПолучателя.Отправитель;
Письмо.Subject = СтруктураПолучателя.Тема;
Письмо.TextBody = СтруктураПолучателя.Текст;
Письмо.BodyPart.Charset = "windows-1251";
Если СтруктураПолучателя.Свойство("ПутьКФайлу") И ЗначениеЗаполнено(СтруктураПолучателя.ПутьКФайлу) Тогда
Письмо.AddAttachment(СтруктураПолучателя.ПутьКФайлу);
КонецЕсли;
// Настройка параметров SMTP
Fields = Письмо.Configuration.Fields;
Fields.Item("http://schemas.microsoft.com/cdo/configuration/sendusing").Value = 2; // Отправка по сети
Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpserver").Value = "smtp.yourserver.com";
Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpserverport").Value = 25;
Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpconnectiontimeout").Value = 60;
Fields.Update();
Попытка
Письмо.Send();
Исключение
ЗаписьЖурналаРегистрации("ПочтоваяПодсистема.ОшибкаОтправки",
УровеньЖурналаРегистрации.Ошибка, , , ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
Если код выполняется без ошибок, но письма не доходят до адресатов, обратите внимание на следующие моменты:
Профиль.АутентификацияSMTP = СпособSMTPАутентификации.БезАутентификации и добавить IP-адрес сервера 1С в список разрешенных узлов на стороне почтового сервера.ИспользоватьSSLSMTP = Истина в объекте ИнтернетПочтовыйПрофиль.ТабличныйДокумент.Записать(), обязательно удаляйте его через УдалитьФайлы() в блоке ЗавершениеПопытки или после успешной отправки.