Как реализовать надежную отправку почты в 1С с повторными попытками при сбоях

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

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

Вариант 1. Реализация цикла с ограниченным количеством попыток

Самый простой и очевидный способ — обернуть код отправки в цикл. Однако здесь важно соблюсти два правила: ограничить количество итераций, чтобы не войти в бесконечный цикл, и добавить временную паузу между попытками. Рассмотрим пример кода, который реализует такой подход:


МаксимальноеКоличествоПопыток = 5;
ТекущаяПопытка = 1;
УспешноОтправлено = Ложь;

Пока ТекущаяПопытка <= МаксимальноеКоличествоПопыток Цикл
    Попытка
        Почта.Послать(Сообщение);
        УспешноОтправлено = Истина;
        Прервать; // Выходим из цикла, если письмо ушло
    Исключение
        ТекстОшибки = ОписаниеОшибки();
        ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Попытка " + ТекущаяПопытка + " не удалась: " + ТекстОшибки);
        
        // Делаем паузу перед следующей попыткой
        // На сервере 1С нет функции Sleep, используем системные методы или ожидание
        Если ТекущаяПопытка < МаксимальноеКоличествоПопыток Тогда
            // Например, вызов системной паузы через Ping (простой вариант для сервера)
            КомандаПаузы = "ping -n 10 127.0.0.1 > nul"; 
            ЗапуститьПриложение(КомандаПаузы, , Истина); 
        КонецЕсли;
        
        ТекущаяПопытка = ТекущаяПопытка + 1;
    КонецПопытки;
КонецЦикла;

Если Не УспешноОтправлено Тогда
    // Обработка ситуации, когда все попытки исчерпаны
    ЗаписатьОшибкуВЛог(Сообщение, ТекстОшибки);
КонецЕсли;

Проанализируем этот код. Мы используем переменную ТекущаяПопытка для контроля. Если метод Послать() отрабатывает без исключений, срабатывает оператор Прервать, и выполнение продолжается. Если же возникает ошибка, мы выводим сообщение (или записываем в журнал регистрации) и увеличиваем счетчик. Важно: мгновенные повторы редко помогают при сетевых проблемах, поэтому пауза в 10–30 секунд крайне желательна.

Вариант 2. Анализ возвращаемого значения метода Послать()

Начиная с версии платформы 8.3.10, поведение метода ИнтернетПочта.Послать() изменилось. Теперь он не всегда вызывает исключение, если письмо не удалось отправить. В некоторых случаях метод возвращает Соответствие, где ключом является адрес получателя, а значением — текст ошибки. Разберем, как правильно обрабатывать такие ситуации:


РезультатОтправки = Почта.Послать(Сообщение);

Если ТипЗнч(РезультатОтправки) = Тип("Соответствие") И РезультатОтправки.Количество() > 0 Тогда
    Для Каждого ОшибкаАдреса Из РезультатОтправки Цикл
        // Ключ - это e-mail, Значение - текст ошибки
        Сообщить("Письмо на адрес " + ОшибкаАдреса.Ключ + " не отправлено. Причина: " + ОшибкаАдреса.Значение);
    КонецЦикла;
    // Здесь также можно реализовать логику повтора для конкретных адресов
КонецЕсли;

Этот механизм особенно полезен, если в одном письме указано несколько получателей. Если один адрес заблокирован, а другой доступен, 1С отправит письмо доступному адресату и вернет ошибку только по проблемному. В старых версиях (до 8.3.10) метод возвращал Неопределено или вызывал исключение.

Вариант 3. Использование фоновых заданий для автоматического перезапуска

Если задача выполняется в фоновом режиме (например, регламентным заданием), мы можем делегировать управление повторами самой платформе 1С. У объекта ФоновыеЗадания при программном запуске есть параметры, отвечающие за поведение при сбоях. Выясним, как это реализовать:


ПараметрыЗадания = Новый Структура;
ПараметрыЗадания.Вставить("КоличествоПовторов", 3);
ПараметрыЗадания.Вставить("ИнтервалПовтора", 60); // пауза в секундах

ФоновыеЗадания.Выполнить("МойОбщийМодуль.ОтправитьПисьмо", ПараметрыПроцедуры, КлючЗадания, , ПараметрыЗадания);

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

Вариант 4. Профессиональный подход с использованием БСП

Если ваша конфигурация построена на базе Библиотеки стандартных подсистем (БСП), мы настоятельно рекомендуем использовать подсистему «Работа с почтовыми сообщениями». Вместо прямой отправки через ИнтернетПочта, следует использовать методы этой подсистемы. Рассмотрим преимущества:

  1. Очередь сообщений: Письма записываются в специальный регистр сведений ОчередьПочтовыхСообщений.
  2. Автоматическая обработка: Существует стандартное регламентное задание, которое с заданной периодичностью пытается отправить письма из очереди.
  3. История и логирование: В системе сохраняется информация о количестве неудачных попыток и текстах ошибок для каждого письма.
  4. Гибкость: Вы можете программно поместить письмо в очередь, и система сама разберется с транспортными протоколами и повторами.

Пример программного добавления в очередь (схематично для БСП):


ПараметрыПисьма = Новый Структура;
ПараметрыПисьма.Вставить("Кому", "owner@example.com");
ПараметрыПисьма.Вставить("Тема", "Отчет по копии ИБ");
ПараметрыПисьма.Вставить("Тело", "Текст сообщения...");

// Вызов стандартного метода БСП
РаботаСПочтой.ОтправитьПочтовоеСообщение(УчетнаяЗапись, ПараметрыПисьма);

Важные рекомендации и предостережения

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

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

← На главную