Почему 1С зависает при отправке почты регламентным заданием и как это исправить?

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

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

Разбираем причину: Файловый режим vs Клиент-сервер

Первое, на что стоит обратить внимание при анализе ситуации — это режим работы базы данных. В системе 1С:Предприятие 8 механизмы выполнения фоновых и регламентных заданий принципиально отличаются в зависимости от архитектуры:

  1. Клиент-серверный режим (SQL): Все регламентные задания выполняются на стороне сервера 1С. Они работают в отдельных рабочих процессах и никак не затрагивают сеансы пользователей. Если база серверная, а интерфейс «тормозит», причину нужно искать в избыточных блокировках таблиц в коде, а не в самом факте выполнения задания.
  2. Файловый режим: Здесь нет выделенного сервера приложений. По умолчанию регламентные задания запускаются в контексте одного из активных клиентских сеансов. Это означает, что 1С «выбирает» одного из работающих пользователей и в его потоке начинает выполнять код рассылки. Пока код не выполнится, интерфейс этого пользователя будет заблокирован.

Проанализируем ситуацию: если вы используете файловую базу, то простое создание регламентного задания не гарантирует его «невидимость». Чтобы решить проблему в файловом варианте, необходимо выделить отдельный сеанс, который будет заниматься исключительно выполнением задач. Это можно сделать, запустив программу с параметром /DoScheduledJobs или используя специальную обработку, вызывающую метод ВыполнитьОбработкуЗаданий() в бесконечном цикле.

Оптимизация кода отправки почты

Часто причиной «подлагиваний» становится неоптимальный код. Посмотрим на типовой пример, где соединение с почтовым сервером устанавливается внутри цикла перебора писем. Это в корне неверно, так как операция Подключиться() требует времени на установку TCP-соединения, SSL-рукопожатие и авторизацию (иногда до 2-5 секунд на каждое письмо).

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


Процедура ВыполнитьРассылкуИзОчереди() Экспорт
    
    // Получаем сообщения из регистра сведений (очереди)
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   Очередь.Получатель,
        |   Очередь.АдресЭлектроннойПочты,
        |   Очередь.ПутьКФайлу
        |ИЗ
        |   РегистрСведений.ОчередьРассылки КАК Очередь";
    
    Выборка = Запрос.Выполнить().Выбрать();
    
    Если Выборка.Количество() = 0 Тогда
        Возврат;
    КонецЕсли;

    // Настраиваем профиль один раз
    Профиль = Новый ИнтернетПочтовыйПрофиль;
    Профиль.АдресСервераSMTP = "smtp.yandex.ru";
    Профиль.ПортSMTP = 465;
    Профиль.ИспользоватьSSLSMTP = Истина;
    Профиль.ПользовательSMTP = "info@company.ru";
    Профиль.ПарольSMTP = "ваш_пароль_приложения"; // Важно: используйте пароли приложений!
    Профиль.АутентификацияSMTP = СпособSMTPАутентификации.Login;

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

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

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

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

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

Работа с блокировками и транзакциями

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

Рекомендуется: накопить массив отправленных идентификаторов и удалить их одной операцией после завершения цикла, либо выполнять удаление вне основной транзакции. Также важно помнить, что в фоновых заданиях нельзя использовать методы Сообщить(), так как они ориентированы на интерактивный интерфейс. Используйте ЗаписьЖурналаРегистрации() для логирования процесса.

Безопасность и современные требования почтовых сервисов

Проанализируем ситуацию с почтовыми серверами (Yandex, Mail.ru, Gmail). В последнее время они запретили авторизацию по обычному паролю от ящика для сторонних приложений. Если ваша 1С не может подключиться, проверьте следующие пункты:

Использование типовых механизмов УПП 1.3

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

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

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

← На главную