Почему дублируется отправка отчетов по электронной почте в 1С и как это исправить

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

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

Выясним причину дублирования на примере кода

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

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


// Ошибочный вариант реализации
Почта = Новый ИнтернетПочта;
Попытка
    Почта.Подключиться(Профиль);
Исключение
    Сообщить("Ошибка подключения к почтовому серверу");
    Возврат;
КонецПопытки;

Попытка
    Почта.Послать(Сообщение, ОбработкаТекстаИнтернетПочтовогоСообщения.НеОбрабатывать, ПротоколИнтернетПочты.SMTP);
    СообщенияОтправки = Почта.Послать(Сообщение, ОбработкаТекстаИнтернетПочтовогоСообщения.НеОбрабатывать, ПротоколИнтернетПочты.SMTP);
Исключение
    Сообщить(Получатель.ЭлПочта);
    Сообщить(ОписаниеОшибки());
КонецПопытки;
Почта.Отключиться();

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

Разберем по шагам правильное исправление кода

Для устранения дублирования необходимо оставить ровно один вызов метода Послать у объекта ИнтернетПочта. Исправим процедуру отправки писем следующим образом:


// Корректный вариант реализации
Почта = Новый ИнтернетПочта;
Попытка
    Почта.Подключиться(Профиль);
Исключение
    Сообщить("Ошибка подключения к почтовому серверу");
    Сообщить(ОписаниеОшибки());
    Возврат;
КонецПопытки;

Попытка
    // Выполняем отправку сообщения строго один раз
    СообщенияОтправки = Почта.Послать(Сообщение, ОбработкаТекстаИнтернетПочтовогоСообщения.НеОбрабатывать, ПротоколИнтернетПочты.SMTP);
Исключение
    Сообщить("Не удалось отправить письмо адресату: " + Получатель.ЭлПочта);
    Сообщить(ОписаниеОшибки());
КонецПопытки;

Почта.Отключиться();

Другие возможные причины задвоения почтовых сообщений

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

  1. Зависание по таймауту SMTP-соединения: При передаче объемных вложений через медленный канал почтовый сервер успевает принять письмо и отправить его далее, но не успевает передать в 1С код подтверждения 250 OK. Если таймаут в объекте ИнтернетПочтовыйПрофиль слишком мал (например, 60 секунд), платформа 1С расценивает связь как разорванную и может совершить повторную попытку. Увеличьте параметр Таймаут до 120–180 секунд.
  2. Запуск процедуры в нескольких событиях формы: Убедимся, что вызов процедур рассылки не продублирован в обработчиках ПриОткрытии и ПриСозданииНаСервере или нажатии кнопок.
  3. Ошибки в запросе выборки получателей: Если запрос соединяет таблицы без четкой группировки, один и тот же контрагент с одинаковой электронной почтой может попасть в результат выборки несколько раз.
  4. Параллельные экземпляры в Планировщике задач: В свойствах задачи Windows Scheduler необходимо проверить вкладку «Параметры» и убедиться, что задействовано правило «Не запускать новый экземпляр» (Do not start a new instance), если предыдущий процесс еще выполняется.

Как гарантировать однократную отправку писем

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

Рассмотрим вариант с проверкой перед отправкой:


// Проверка перед отправкой отчета
ДатаОтправки = НачалоДня(ТекущаяДата());
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ИсторияРассылки.Контрагент
    |ИЗ
    |	РегистрСведений.ИсторияРассылки КАК ИсторияРассылки
    |ГДЕ
    |	ИсторияРассылки.Контрагент = &Контрагент
    |	И ИсторияРассылки.Период = &ДатаОтправки";

Запрос.УстановитьПараметр("Контрагент", ВыбДилер);
Запрос.УстановитьПараметр("ДатаОтправки", ДатаОтправки);

Если Запрос.Выполнить().Пустой() Тогда
    // Выполняем отправку и фиксируем факт отправки в базе
    глОтправитьОтчетПоПочте(Таб, ВыбДилер, ТемаОтправки, 0, "file:G:\Bases2\Balance.htm", 2);
    ЗафиксироватьФактОтправки(ВыбДилер, ДатаОтправки);
КонецЕсли;

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

← На главную