Почему ИнтернетПочта.Послать() в 1С возвращает пустое соответствие или вызывает исключение при неверных адресах

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

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

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

Исходный код отправки писем

Рассмотрим типовой сценарий отправки почты, который часто используется в конфигурациях:


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

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

Причина 1: Особенности работы протокола SMTP и отложенная проверка

Чтобы понять логику работы платформы 1С, необходимо проанализировать, как функционирует сам протокол передачи почты SMTP. Сессия отправки письма состоит из последовательного обмена командами между клиентом (1С) и сервером (например, Яндекс, Mail.ru, Gmail):

  1. Передача команды MAIL FROM (указывается отправитель).
  2. Передача одной или нескольких команд RCPT TO (указываются получатели).
  3. Передача команды DATA (передается тело письма и вложения).

Если вы отправляете письмо на несуществующий внешний адрес (например, случайный набор букв на домене @gmail.com, используя при этом для отправки почтовый ящик на Яндексе), то ваш SMTP-сервер на этапе команды RCPT TO не знает и физически не может проверить, существует ли данный конкретный ящик на серверах Google.

Почтовый сервер Яндекса принимает этот адрес, возвращает платформе 1С статус успешного приема 250 OK и завершает сессию. С точки зрения 1С, сервер подтвердил отправку. Поэтому метод Послать() успешно завершает работу и возвращает пустое соответствие. Само сообщение о недоставке (так называемый Bounce Message) придет на ваш ящик отправителя значительно позже в виде системного письма, но код 1С об этом уже не узнает.

Причина 2: Единственный получатель в письме

Проанализируем поведение платформы в ситуации, когда SMTP-сервер все-таки способен мгновенно распознать неверный адрес (например, если вы отправляете письмо на несуществующий локальный адрес внутри того же домена, на котором авторизовались). На этапе команды RCPT TO сервер сразу возвращает ошибку (например, 550 User not found).

Здесь в силу вступает внутренняя логика работы платформы 1С:

Как правильно обрабатывать результаты отправки в коде

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


СерверИнтернетПочты = Новый ИнтернетПочта;
Попытка
    СерверИнтернетПочты.Подключиться(ПрофильИнтернетПочты);
КонецПопытки;
// Если подключиться не удалось, дальнейшая логика прерывается

РезультатОтправки = Неопределено;
ПисьмоОтправлено = Ложь;

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

Если ПисьмоОтправлено Тогда
    // Проверяем, были ли частично отклоненные адресаты
    Если ТипЗнч(РезультатОтправки) = Тип("Соответствие") И РезультатОтправки.Количество() > 0 Тогда
        Для Каждого СтрокаОшибки Из РезультатОтправки Цикл
            НепринятыйАдрес = СтрокаОшибки.Ключ; // Объект ИнтернетПочтовыйАдрес
            ТекстДиагностики = СтрокаОшибки.Value; // Диагностика SMTP-сервера
            
            Сообщить(СтрШаблон("Адрес %1 не принят сервером. Причина: %2", 
                НепринятыйАдрес.Адрес, ТекстДиагностики));
        КонецЦикла;
    КонецЕсли;
КонецЕсли;

СерверИнтернетПочты.Отключиться();

Альтернативный вариант: использование БСП

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

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

← На главную