Как организовать массовую рассылку отчетов по email контрагентам в 1С 8.3?

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

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

Разберем основные архитектурные подходы и технические нюансы реализации массовой рассылки отчетов в 1С:Предприятие 8.3.

Вариант 1. Внедрение подсистемы «Рассылка отчетов» из Библиотеки стандартных подсистем (БСП)

Если в конфигурацию уже интегрирована или планируется к внедрению Библиотека стандартных подсистем (версии 2.1 и выше), наиболее надежным и функциональным решением будет использование готовой подсистемы «Рассылка отчетов».

Проанализируем преимущества этого подхода:

  1. Отчеты на базе системы компоновки данных (СКД) автоматически адаптируются под рассылку с сохранением вариантов настроек.
  2. Подсистема поддерживает персонализацию: для каждого контрагента можно настроить индивидуальный отбор данных, чтобы получатель видел только свою информацию.
  3. Поддерживается отправка в различных форматах (PDF, XLSX, ZIP-архивы) по гибкому расписанию через регламентные задания.
  4. Реализован контроль доставки, логирование ошибок и управление списками получателей.

Если отчет уже разработан с использованием вариантов отчетов БСП, настройка рассылки сводится к созданию элемента в справочнике рассылок без написания дополнительного программного кода.

Вариант 2. Разработка собственной очереди отправки сообщений

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

Шаг 1. Создание структуры для хранения очереди

Создадим регистр сведений или специализированный справочник ОчередьИсходящейПочты со следующими реквизитами:

  1. Контрагент (Ссылка на контрагента).
  2. АдресПолучателя (Строка с email-адресом).
  3. Тема и ТелоПисьма (Строки).
  4. ФайлВложения (Хранилище значения для двоичных данных сформированного отчета).
  5. Статус (Перечисление: «В очереди», «Отправлено», «Ошибка»).
  6. КоличествоПопыток (Число) и ТекстОшибки (Строка).
  7. ДатаСоздания и ДатаОтправки (Дата и время).

Шаг 2. Формирование отчетов и наполнение очереди

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

Посмотрим на пример кода формирования отчета и помещения вложения в очередь:


// Формируем табличный документ отчета программно
ТабДок = Новый ТабличныйДокумент;
// ... заполнение ТабДок через ПроцессорКомпоновкиДанных с отбором по Контрагенту ...

ИмяВременногоФайла = ПолучитьИмяВременногоФайла("pdf");
ТабДок.Записать(ИмяВременногоФайла, ТипФайлаТабличногоДокумента.PDF);

ДвоичныеДанныеВложения = Новый ДвоичныеДанные(ИмяВременногоФайла);
УдалитьФайлы(ИмяВременногоФайла);

// Запись в регистр очереди
МенеджерЗаписи = РегистрыСведений.ОчередьИсходящейПочты.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Идентификатор = Новый УникальныйИдентификатор();
МенеджерЗаписи.Период = ТекущаяДатаСеанса();
МенеджерЗаписи.Контрагент = ТекущийКонтрагент;
МенеджерЗаписи.АдресПолучателя = АдресПочты;
МенеджерЗаписи.Тема = "Отчет за период";
МенеджерЗаписи.ФайлВложения = Новый ХранилищеЗначения(ДвоичныеДанныеВложения, Новый СжатиеДанных(9));
МенеджерЗаписи.Статус = Перечисления.СтатусыОтправкиПочты.ВТранспорте;
МенеджерЗаписи.Записать();

Шаг 3. Регламентная отправка пачками (пакетирование)

Чтобы не перегружать почтовый сервер и не попадать под блокировки спам-фильтров, создадим отдельное регламентное задание, которое периодически выбирает ограниченный пакет записей (например, по 50 писем) с помощью конструкции ВЫБРАТЬ ПЕРВЫЕ 50 и выполняет отправку.

При пакетной отправке критически важно держать SMTP-соединение открытым на протяжении всей пачки, а не вызывать методы подключения и отключения для каждого отдельного письма.

Рассмотрим пример процедуры фоновой отправки пачки писем:


Процедура ОтправитьОчередьПочты() Экспорт

    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ ПЕРВЫЕ 50
        |	Очередь.Идентификатор КАК Идентификатор,
        |	Очередь.АдресПолучателя КАК АдресПолучателя,
        |	Очередь.Тема КАК Тема,
        |	Очередь.ФайлВложения КАК ФайлВложения
        |ИЗ
        |	РегистрСведений.ОчередьИсходящейПочты КАК Очередь
        |ГДЕ
        |	Очередь.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыОтправкиПочты.ВТранспорте)
        |	И Очередь.КоличествоПопыток < 3
        |УПОРЯДОЧИТЬ ПО
        |	Очередь.Период ВОЗР";
        
    Результат = Запрос.Выполнить();
    Если Результат.Пустой() Тогда
        Возврат;
    КонецЕсли;
    
    Выборка = Результат.Выбрать();
    
    Профиль = ПолучитьПочтовыйПрофиль(); // Функция получения ИнтернетПочтовыйПрофиль
    Почта = Новый ИнтернетПочта;
    
    Попытка
        Почта.Подключиться(Профиль);
    Исключение
        ЗаписьЖурналаРегистрации("ОтправкаПочты", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
        Возврат;
    КонецПопытки;
    
    Пока Выборка.Следующий() Цикл
        
        Письмо = Новый ИнтернетПочтовоеСообщение;
        Письмо.Получатели.Добавить(Выборка.АдресПолучателя);
        Письмо.Тема = Выборка.Тема;
        Письмо.Тексты.Добавить("Добрый день! Во вложении отчет за месяц.", ТипТекстаПочтовогоСообщения.ПростойТекст);
        
        ДвоичныеДанныеФайла = Выборка.ФайлВложения.Получить();
        Если ДвоичныеДанныеФайла <> Неопределено Тогда
            ИмяВременного = ПолучитьИмяВременногоФайла("pdf");
            ДвоичныеДанныеФайла.Записать(ИмяВременного);
            Письмо.Вложения.Добавить(ИмяВременного, "Отчет.pdf");
        КонецЕсли;
        
        Попытка
            Почта.Послать(Письмо);
            ФиксироватьУспехОтправки(Выборка.Идентификатор);
        Исключение
            ФиксироватьОшибкуОтправки(Выборка.Идентификатор, ОписаниеОшибки());
        КонецПопытки;
        
        Если ЗначениеЗаполнено(ИмяВременного) Тогда
            УдалитьФайлы(ИмяВременного);
        КонецЕсли;
        
    КонецЦикла;
    
    Почта.Отключиться();

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

Вариант 3. Оптимизация производительности и почтовые лимиты

При работе с базами на тысячи контрагентов необходимо учитывать внешние технические ограничения:

  1. Многопоточная генерация: Если формирование отчетов для всех клиентов занимает длительное время, задействуем механизм ФоновыеЗадания.Выполнить(), разделив массив контрагентов на несколько параллельных потоков.
  2. Паузы между отправками: Если почтовый сервис жестко ограничивает частоту транзакций (Rate Limit), между итерациями цикла можно использовать процедуру Приостановить(КоличествоСекунд).
  3. Использование локального SMTP-релея: Чтобы 1С мгновенно отдавала письма и не зависела от скорости внешнего интернета, внутри сети предприятия разворачивают локальный почтовый сервер (Postfix, Exim). 1С передает сообщения на локальный узел за доли секунды, а релей сам управляет очередью, повторами и лимитами на внешние адреса.
  4. Защита от спам-фильтров: Для гарантированной доставки писем на стороне DNS почтового домена отправителя должны быть корректно настроены записи SPF, DKIM и DMARC.
← На главную