При разработке функционала отправки электронных писем из среды 1С:Предприятие программисты часто сталкиваются с непонятными ошибками на этапе подключения к почтовому серверу. Одной из самых коварных является ошибка «Значение не является значением объектного типа» при вызове методов Подключиться() или Послать(). В этой статье мы разберем не только причину этой технической ошибки, но и выясним, почему отправка почты в момент проведения документа — это критическая архитектурная ошибка, способная парализовать работу системы.
Проанализируем ситуацию: в коде создается объект ИнтернетПочта, заполняется профиль, но при попытке вызвать метод Почта.Подключиться(УчетнаяЗапись) система выдает ошибку. Выясним причину этого поведения. В платформе 1С существует строгая иерархия имен. Если в вашем документе, в котором написан код, существует реквизит с именем Почта, или на форме есть элемент с таким же названием, то внутри модуля переменная Почта будет ссылаться именно на этот объект (строку, ссылку или элемент формы), а не на созданный вами программный объект Новый ИнтернетПочта.
Рассмотрим пример кода, который вызывает ошибку:
// В документе есть реквизит "Почта" (тип Строка)
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
Почта = Новый ИнтернетПочта; // Происходит неявное переопределение или конфликт
// ... заполнение профиля ...
Почта.Подключиться(УчетнаяЗапись); // Ошибка: Значение не является значением объектного типа
КонецПроцедуры
Чтобы избежать этой проблемы, всегда используйте уникальные префиксы для локальных переменных. Изменим код, используя более безопасное имя переменной, например ПочтовыйАгент:
ПочтовыйАгент = Новый ИнтернетПочта;
Попытка
ПочтовыйАгент.Подключиться(УчетнаяЗапись);
ПочтовыйАгент.Послать(Письмо);
ПочтовыйАгент.Отключиться();
Исключение
Сообщить("Ошибка почтовой службы: " + ОписаниеОшибки());
КонецПопытки;
Теперь перейдем к более важному — архитектурному вопросу. Многие начинающие разработчики пытаются вставить код отправки уведомлений прямо в процедуру проведения документа. Рассмотрим, какие опасности это таит в себе:
ОбработкаПроведения выполняется внутри транзакции базы данных. Пока 1С ждет ответа от сервера Rambler или Mail.ru (а это может занять до 120 секунд по таймауту), все таблицы, задействованные в проведении, заблокированы. Другие пользователи не смогут проводить документы или строить отчеты.Почта.Послать(), но через строку ниже код 1С обнаружил нехватку товара на складе и установил Отказ = Истина. Транзакция откатывается, документ не проведен, но письмо уже отправлено. Пользователь исправит ошибку, нажмет «Провести» снова — и клиент получит второе (дублирующее) письмо.C:\Users\Admin\Desktop\...), сервер 1С его не найдет, так как у него своя файловая система и свои права доступа.Проанализируем, как реализовать этот функционал профессионально. Вместо прямой отправки, мы будем использовать регистр сведений в качестве очереди.
Шаг 1. Запись намерения в транзакции:
В процедуре ОбработкаПроведения мы просто фиксируем факт того, что письмо должно быть отправлено. Запись в регистр произойдет только в том случае, если документ будет успешно проведен.
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
// Проверка условий (билеты, баллы и т.д.)
Если РезОтветов >= 2 Тогда
// Записываем данные для отправки в специальный РегистрСведений.ОчередьПисем
НоваяЗапись = РегистрыСведений.ОчередьПисем.СоздатьМенеджерЗаписи();
НоваяЗапись.Период = ТекущаяДата();
НоваяЗапись.Документ = Ссылка;
НоваяЗапись.АдресПолучателя = "client@yandex.ru";
НоваяЗапись.Статус = Перечисления.СтатусыОтправки.ВТорговле;
НоваяЗапись.Записать();
КонецЕсли;
КонецПроцедуры
Шаг 2. Отправка через регламентное задание:
Создадим отдельную процедуру в общем модуле, которая будет запускаться сервером в фоновом режиме раз в минуту. Она будет выбирать из регистра все необработанные записи и отправлять их.
Процедура ОтправитьПочтуИзОчереди() Экспорт
Выборка = РегистрыСведений.ОчередьПисем.Выбрать(Новый Структура("Статус", Перечисления.СтатусыОтправки.ВТорговле));
ПочтовыйПрофиль = ПолучитьНастройкиПочты(); // Функция возвращает ИнтернетПочтовыйПрофиль
Почта = Новый ИнтернетПочта;
Попытка
Почта.Подключиться(ПочтовыйПрофиль);
Пока Выборка.Следующий() Цикл
// Формируем и отправляем письмо
// ... код формирования сообщения ...
Почта.Послать(Сообщение);
// Помечаем как отправленное
Менеджер = Выборка.ПолучитьМенеджерЗаписи();
Менеджер.Статус = Перечисления.СтатусыОтправки.Отправлено;
Менеджер.Записать();
КонецЦикла;
Почта.Отключиться();
Исключение
// Логируем ошибку, чтобы не прерывать работу пользователей
ЗаписьЖурналаРегистрации("ОтправкаПочты", УровеньЖурналаРегистрации.Ошибка, , , ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
Разберем еще один критический момент: почему даже правильный код может выдавать «Ошибку авторизации». Современные сервисы (Rambler, Yandex, Gmail) запрещают использование основного пароля от почты в сторонних программах.
Что нужно проверить в настройках почтового ящика:
ИспользоватьSSLSMTP = Истина и порт 465.Подведем итог: для стабильной работы почты в 1С всегда используйте уникальные имена переменных для объекта ИнтернетПочта, выносите отправку за пределы транзакции проведения с помощью очередей и не забывайте про настройки безопасности почтовых сервисов.