Как реализовать отправку документов по электронной почте из 1С при проведении?

Программист 1С v8.3 (Обычные формы) 1С:Зарплата и Управление Персоналом IT и автоматизация бизнеса
← На главную

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

Почему нельзя отправлять письма напрямую из процедуры проведения?

Рассмотрим риски и проблемы, к которым приводит отправка почты непосредственно в обработке проведения:

  1. Зависание и блокировки базы данных. Проведение документа происходит внутри транзакции. Если почтовый сервер долго отвечает, отсутствует интернет или возникла задержка по сети, транзакция остается открытой. Это блокирует таблицы базы данных для остальных пользователей.
  2. Откат проведения при ошибке сети. Любое исключение при отправке письма (например, таймаут соединения) приведет к тому, что документ не проведется вообще.
  3. Снятие типовой конфигурации с поддержки. Внесение изменений в модули типовых документов затрудняет последующее обновление программы.

Для решения этой задачи проанализируем два правильных архитектурных подхода, которые позволяют сохранить конфигурацию обновляемой и обезопасить проведение документов.

Способ 1. Использование подписки на событие, регистра сведений и регламентного задания

Разберем наиболее надежный вариант. Вся логика разделяется на два этапа: быстрое сохранение события в очередь при проведении и асинхронная отправка сообщений фоновым или регламентным заданием.

Рассмотрим пошаговую реализацию:

  1. Создание регистра сведений. Создадим регистр сведений ОчередьОтправкиПочты с измерением Документ (ссылка на документ) и ресурсом ДатаЗаписи.
  2. Создание подписки на событие. Добавим подписку на событие ПриЗаписи или ОбработкаПроведения для нужных документов. В обработчике подписки записываем ссылку на проведенный документ в регистр сведений. Это выполняется мгновенно и не задерживает транзакцию.
  3. Отправка сообщений по расписанию. Создаем регламентное задание или внешнюю обработку, которая по расписанию читает записи из регистра, формирует письма с вложениями, отправляет их и удаляет обработанные записи из регистра.

Посмотрим на пример функции отправки почты через объект ИнтернетПочта:


Функция ОтправитьНаЭлектроннуюПочту(Получатели, Тема, Текст, ПутьКФайлуВложения = Неопределено) Экспорт

    Профиль = Новый ИнтернетПочтовыйПрофиль;
    Профиль.АутентификацияSMTP = СпособSMTPАутентификации.ПоУмолчанию;
    Профиль.АдресСервераSMTP = "smtp.yourserver.com";
    Профиль.ПортSMTP = 25;
    Профиль.Пользователь = "user@domain.com";
    Профиль.ПользовательSMTP = "user@domain.com";
    Профиль.ПарольSMTP = "Password";
    Профиль.ВремяОжидания = 60;

    ПочтовоеСообщение = Новый ИнтернетПочтовоеСообщение;
    ПочтовоеСообщение.Тема = Тема;
    ПочтовоеСообщение.Отправитель.Адрес = "user@domain.com";
    ПочтовоеСообщение.Отправитель.ОтображаемоеИмя = "1С:Предприятие";

    Если ТипЗнч(Получатели) = Тип("Массив") Тогда
        Для Каждого Адрес Из Получатели Цикл
            ПочтовоеСообщение.Получатели.Добавить(СокрЛП(Адрес));
        КонецЦикла;
    ИначеЕсли ТипЗнч(Получатели) = Тип("Строка") Тогда
        ПочтовоеСообщение.Получатели.Добавить(СокрЛП(Получатели));
    КонецЕсли;

    Если ЗначениеЗаполнено(ПутьКФайлуВложения) Тогда
        ПочтовоеСообщение.Вложения.Добавить(ПутьКФайлуВложения);
    КонецЕсли;

    ПочтовоеСообщение.Тексты.Добавить(Текст, ТипТекстаПочтовогоСообщения.ПростойТекст);

    Почта = Новый ИнтернетПочта;
    Попытка
        Почта.Подключиться(Профиль);
        Почта.Послать(ПочтовоеСообщение);
        Почта.Отключиться();
        Возврат Истина;
    Исключение
        Комментарий = "Ошибка при отправке сообщения: " + ОписаниеОшибки();
        ЗаписьЖурналаРегистрации("ОтправкаПочты.Ошибка", УровеньЖурналаРегистрации.Ошибка, , , Комментарий);
        Возврат Ложь;
    КонецПопытки;

КонецФункции

Способ 2. Использование COM-объекта CDO.Message (для ОС Windows)

В некоторых случаях стандартный объект ИнтернетПочта может иметь проблемы со специфическими почтовыми серверами (например, 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();
    Исключение
        ЗаписьЖурналаРегистрации("ПочтоваяПодсистема.ОшибкаОтправки", 
            УровеньЖурналаРегистрации.Ошибка, , , ОписаниеОшибки());
    КонецПопытки;

КонецПроцедуры

Рекомендации по настройке почтового сервера и отладке

Если код выполняется без ошибок, но письма не доходят до адресатов, обратите внимание на следующие моменты:

← На главную