Как исправить ошибку «SMTP error code 550, Mailbox unavailable» при отправке почты группе получателей в 1С?

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

При организации автоматических рассылок из среды 1С:Предприятие разработчики часто сталкиваются с неприятной ситуацией. Нам необходимо отправить одно и то же письмо группе адресатов (например, 20 сотрудникам или клиентам). Мы подготавливаем одно почтовое сообщение, заполняем список получателей и вызываем метод Послать() объекта ИнтернетПочта. Однако, если среди этих 20 адресов окажется хотя бы один несуществующий, удаленный или временно заблокированный почтовый ящик, весь процесс отправки прерывается аварийно с ошибкой «SMTP error code 550, Mailbox unavailable». В итоге письмо не доходит ни до одного из получателей, даже если остальные 19 адресов абсолютно корректны.

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

Выясняем техническую причину ошибки

Для того чтобы понять, почему возникает эта ошибка, нам необходимо обратиться к принципам работы сетевого протокола SMTP. Когда 1С отправляет письмо группе адресатов, взаимодействие с почтовым сервером происходит в рамках одной SMTP-сессии. Платформа последовательно передает серверу команды RCPT TO для каждого получателя из списка.

Почтовый сервер получателя (или ваш исходящий SMTP-сервер) во время этой сессии проверяет статус каждого адреса. Если сервер обнаруживает заблокированный или несуществующий почтовый ящик, он мгновенно возвращает стандартный код ответа об ошибке: 550 Mailbox unavailable (или User unknown).

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

Давайте рассмотрим детально все возможные варианты решения этой проблемы — от низкоуровневых изменений в кодовой базе до административных настроек почтовой инфраструктуры.

Решение 1: Переход на современные версии платформы (1С 8.3.9 и выше)

Фирма «1С» со временем переработала этот механизм. Начиная с версии платформы 1С:Предприятие 8.3.9, поведение объекта ИнтернетПочта кардинально изменилось. Теперь частичная недоступность адресатов больше не вызывает аварийного завершения работы метода Послать().

Проанализируем новые особенности работы платформы:

  1. Отправка без прерывания: Если SMTP-сервер не может доставить письмо некоторым адресатам, транзакция не отменяется. Письмо успешно уходит всем корректным и доступным получателям.
  2. Возврат структуры ошибок: Вместо генерации исключения метод Послать() возвращает объект типа Соответствие. Если все письма ушли успешно, возвращается пустое соответствие. Если возникли ошибки, то ключом в возвращаемом соответствии будет адрес недоступного получателя, а значением — строка с текстом ошибки (например, «SMTP error code 550»).

Важное условие: Данное поведение работает только в том случае, если у вашей конфигурации Режим совместимости установлен в значение 8.3.9 или выше. Если оставить режим совместимости со старыми версиями (например, 8.3.8), платформа продолжит вызывать исключение.

Рассмотрим пример кода, реализующий обработку результатов отправки по новым правилам:


Профиль = Новый ИнтернетПочтовыйПрофиль;
// Заполняем параметры подключения к SMTP-серверу...
Профиль.АдресСервераSMTP = "smtp.yandex.ru";
Профиль.ПортSMTP = 465;
Профиль.ПользовательSMTP = "robot@domain.ru";
Профиль.ПарольSMTP = "MyPassword";
Профиль.ИспользоватьSSLSMTP = Истина;

Почта = Новый ИнтернетПочта;
Письмо = Новый ИнтернетПочтовоеСообщение;
Письмо.Отправитель.Адрес = "robot@domain.ru";

// Добавляем список получателей, включая заведомо некорректный
Письмо.Получатели.Добавить("valid_user1@domain.ru");
Письмо.Получатели.Добавить("blocked_user@domain.ru"); // Вызовет ошибку 550
Письмо.Получатели.Добавить("valid_user2@domain.ru");

Письмо.Тема = "Тестовая рассылка";
Письмо.Тексты.Добавить("Текст важного уведомления для всей группы.");

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

Решение 2: Использование стандартных механизмов БСП

Если вы разрабатываете решение на базе современных типовых конфигураций 1С (таких как ERP, УТ, КА, БП), в вашем распоряжении находится Библиотека стандартных подсистем (БСП). Разработчики БСП уже предусмотрели обертку над платформенными механизмами отправки.

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

Решение 3: Поштучная отправка писем (один получатель — одно письмо)

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

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

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

Посмотрим на пример кода:


Профиль = ПолучитьПрофильПодключения(); // Функция инициализации почтового профиля
Почта = Новый ИнтернетПочта;

МассивАдресатов = Новый Массив;
МассивАдресатов.Добавить("user1@domain.ru");
МассивАдресатов.Добавить("blocked@domain.ru");
МассивАдресатов.Добавить("user2@domain.ru");

Попытка
    Почта.Подключиться(Профиль);
Исключение
    Сообщить("Не удалось установить соединение с сервером: " + ОписаниеОшибки());
    Возврат;
КонецПопытки;

Для Каждого Адрес Из МассивАдресатов Цикл
    Письмо = Новый ИнтернетПочтовоеСообщение;
    Письмо.Отправитель.Адрес = "robot@domain.ru";
    Письмо.Получатели.Добавить(Адрес);
    Письмо.Тема = "Индивидуальное уведомление";
    Письмо.Тексты.Добавить("Уважаемый пользователь, это сообщение сформировано автоматически.");
    
    Попытка
        Почта.Послать(Письмо);
        Сообщить("Успешно отправлено на адрес: " + Адрес);
    Исключение
        // Ловим ошибку 550 конкретного адресата, не прерывая рассылку остальным
        Сообщить("Ошибка отправки на адрес " + Адрес + ": " + ОписаниеОшибки());
    КонецПопытки;
КонецЦикла;

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

Преимущества: Полная независимость от версии платформы 1С и настроек сторонних почтовых серверов. Доставка гарантирована всем существующим адресатам.

Недостатки: Возрастает нагрузка на почтовый сервер и трафик, так как для каждого получателя отправляется отдельный экземпляр письма, вместо передачи одного письма с перечислением адресов.

Решение 4: Создание почтовых групп на стороне почтового сервера

Если вам критически важно отправлять именно одно письмо, а не плодить дубликаты для каждого получателя, перенесите логику группировки адресатов на сторону почтового сервера. Для этого используется механизм Почтовых групп (списков рассылки).

Рассмотрим этот подход подробнее:

  1. Системный администратор на почтовом сервере (например, Exchange, CommuniGate, Postfix) создает специальный служебный адрес, к примеру, all_managers@domain.ru.
  2. В настройках этой группы на сервере указываются реальные адреса всех сотрудников, которые должны получать эти уведомления.
  3. В коде 1С вы отправляете ровно одно письмо на адрес группы all_managers@domain.ru.
  4. Почтовый сервер принимает это письмо (адрес группы всегда валиден и не заблокирован) и самостоятельно осуществляет его дублирование и доставку конечным пользователям внутри своей локальной сети. Если один из ящиков сотрудников внутри группы заблокирован, сервер сам обработает эту ошибку, и это никак не повлияет на доставку письма остальным членам группы и не вызовет ошибку в 1С.

Решение 5: Настройка политики обработки ошибок на почтовом сервере (SMTP-релей)

Для крупных инфраструктурных решений оптимальным выходом будет администрирование промежуточного SMTP-сервера. Вы можете развернуть локальный почтовый релей (например, IIS SMTP, Postfix, Exim) на том же сервере, где функционирует сервер приложений 1С.

В таком сценарии 1С отправляет почту на локальный адрес localhost. Локальный SMTP-сервер настроен так, чтобы моментально принимать абсолютно любые письма от 1С (всегда отвечая кодом 250 OK). Метод Послать() в 1С будет отрабатывать за доли секунды и всегда без ошибок. После приема писем локальный релей самостоятельно занимается их доставкой внешним адресатам в асинхронном режиме. В случае недоступности какого-либо ящика релей сформирует стандартный технический отчет о недоставке (NDR — Non-Delivery Report) и отправит его на ящик отправителя.

Решение 6: Использование Windows COM-объекта CDO.Message

В операционных системах Windows для отправки почты можно использовать системную библиотеку CDO (Collaboration Data Objects). Преимущество этого COM-объекта заключается в более гибком взаимодействии со службами SMTP по сравнению со старым объектом ИнтернетПочта в 1С 8.2.

Проанализируем пример кода с использованием CDO.Message:


// Создаем конфигурацию подключения
CDO_Config = Новый COMОбъект("CDO.Configuration");
Fields = CDO_Config.Fields;

// Задаем параметры SMTP-сервера
Fields.Item("http://schemas.microsoft.com/cdo/configuration/sendusing").Value = 2; // Порт отправки
Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpserver").Value = "smtp.yourserver.ru";
Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpserverport").Value = 25;
Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate").Value = 1; // Авторизация
Fields.Item("http://schemas.microsoft.com/cdo/configuration/sendusername").Value = "user@yourserver.ru";
Fields.Item("http://schemas.microsoft.com/cdo/configuration/sendpassword").Value = "password";
Fields.Update();

// Создаем сообщение
CDO_Message = Новый COMОбъект("CDO.Message");
CDO_Message.Configuration = CDO_Config;
CDO_Message.From = "user@yourserver.ru";

// Задаем список получателей через запятую или точку с запятой
CDO_Message.To = "active_user1@domain.ru; blocked_user@domain.ru; active_user2@domain.ru";
CDO_Message.Subject = "Проверка отправки через CDO";
CDO_Message.TextBody = "Текст сообщения, отправленный в обход стандартной ИнтернетПочты.";

Попытка
    CDO_Message.Send();
    Сообщить("Запрос на отправку успешно передан службе CDO!");
Исключение
    Сообщить("Ошибка отправки через CDO: " + ОписаниеОшибки());
КонецПопытки;

Этот способ позволяет обойти жесткие ограничения старых платформ 1С на обработку сетевых исключений SMTP-протокола, перекладывая управление сессией на системную библиотеку Windows.

Резюме и рекомендации

Мы подробно разобрали природу возникновения ошибки 550 Mailbox unavailable при рассылках из 1С. Подводя итог, дадим несколько практических рекомендаций по выбору оптимального решения:

← На главную