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

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

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

Анализ причин: почему не срабатывает отправка при программной записи

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

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

Почему отправка почты при записи регистра — антипаттерн

Проанализируем риски выполнения сетевых операций при записи данных. Любая запись в базу данных в платформе 1С выполняется внутри транзакции. Отправка почтовых сообщений через интернет-соединение внутри транзакции записи приводит к серьезным проблемам:

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

Вариант 1. Вынос логики отправки в общий модуль и прямой вызов

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

Рассмотрим пример правильной программной выборки и отправки:


// 1. Выбираем данные запросом с любыми условиями
Запрос = Новый Запрос;
Запрос.Текст = 
	"ВЫБРАТЬ
	|	НастройкаУведомлений.Получатель КАК Получатель,
	|	НастройкаУведомлений.Тема КАК Тема,
	|	НастройкаУведомлений.ТекстПисьма КАК ТекстПисьма
	|ИЗ
	|	РегистрСведений.НастройкаУведомлений КАК НастройкаУведомлений
	|ГДЕ
	|	НастройкаУведомлений.Оплачен = ЛОЖЬ";

РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

// 2. Обходим выборку и отправляем сообщения через общий модуль
Пока Выборка.Следующий() Цикл
	УведомленияСервер.ОтправитьЭлектронноеПисьмо(
		Выборка.Получатель, 
		Выборка.Тема, 
		Выборка.ТекстПисьма
	);
КонецЦикла;

Вариант 2. Точечная перезапись записей через МенеджерЗаписи

Если в регистре действительно необходимо изменить значения ресурсов или реквизитов (например, установить флаг выполнения), используем СоздатьМенеджерЗаписи() для точечной работы с конкретной записью:


Запрос = Новый Запрос;
Запрос.Текст = 
	"ВЫБРАТЬ
	|	НастройкаУведомлений.Идентификатор КАК Идентификатор
	|ИЗ
	|	РегистрСведений.НастройкаУведомлений КАК НастройкаУведомлений
	|ГДЕ
	|	НастройкаУведомлений.Оплачен = ЛОЖЬ";

Выборка = Запрос.Выполнить().Выбрать();

Пока Выборка.Следующий() Цикл
	МенеджерЗаписи = РегистрыСведений.НастройкаУведомлений.СоздатьМенеджерЗаписи();
	// Заполняем ключевые измерения записи
	МенеджерЗаписи.Идентификатор = Выборка.Идентификатор;
	МенеджерЗаписи.Прочитать();
	
	Если МенеджерЗаписи.Выбран() Тогда
		// Меняем необходимые данные
		МенеджерЗаписи.Оплачен = Истина;
		МенеджерЗаписи.Записать();
	КонецЕсли;
КонецЦикла;

Вариант 3. Организация асинхронной очереди сообщений (Рекомендуемый подход)

Наиболее надежный и масштабируемый способ организации отправки уведомлений в 1С — паттерн очереди сообщений:

  1. Фиксация события: При интерактивной или программной записи в регистр или документ создается запись в специальном вспомогательном регистре сведений (например, ОчередьИсходящихСообщений) с признаком НеОбработано. Это выполняется быстро и без сетевых вызовов.
  2. Фоновая обработка: Отдельное регламентное задание по расписанию (раз в 1–5 минут) считывает пачку записей из очереди, отправляет письма и меняет статус записи на Обработано (или удаляет отправленную запись).

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

← На главную