Почему перестала отправляться почта через CDO в 1С 7.7 и как решить эту проблему?

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

Автоматическая отправка писем и уведомлений непосредственно из учетной системы — это стандартная и критически важная функция для любого бизнеса. В среде 1С:Предприятие 7.7 классическим и самым популярным инструментом для решения этой задачи долгое время являлась встроенная библиотека Windows CDO (Collaboration Data Objects). Данное решение ценилось разработчиками за простоту внедрения, отсутствие необходимости устанавливать сторонние почтовые клиенты (такие как MS Outlook или Mozilla Thunderbird) и высокую скорость работы.

Однако современные почтовые сервисы (Yandex, Gmail, Mail.ru) непрерывно совершенствуют механизмы защиты от спама и несанкционированного доступа. Из-за этого стабильно работавшие годами обработки отправки почты в один момент перестают функционировать, выдавая бесконечное ожидание или ошибку "Не было отправлено". В этой статье мы подробно разберем, почему ломается отправка почты через CDO, проанализируем технические причины сбоев и рассмотрим несколько надежных способов восстановления работоспособности системы.

Выясняем причины: почему CDO перестает работать?

Прежде чем приступать к исправлению программного кода или перенастройке серверов, давайте детально проанализируем основные факторы, из-за которых современные почтовые провайдеры блокируют запросы от старых COM-объектов Windows:

  1. Несовпадение адреса отправителя с учетной записью SMTP. Это одна из самых частых причин сбоев, возникающая после модернизации ПО на стороне почтовых хостингов. Ранее правила безопасности позволяли авторизоваться под одной «системной» учетной записью, а в поле отправителя письма (From) указывать любой произвольный адрес (например, почту конкретного менеджера). Теперь большинство SMTP-серверов жестко блокируют такие письма с ошибками авторизации (например, 550 Sender address rejected) для защиты от спуфинга (подделки заголовков).
  2. Устаревание и отключение старых протоколов TLS. Библиотека CDO для установки защищенного соединения использует системные криптографические библиотеки ОС Windows (Schannel). Почтовые серверы полностью прекратили поддержку небезопасных протоколов шифрования TLS 1.0 и TLS 1.1, требуя строго TLS 1.2 или TLS 1.3. Если ваша 1С 7.7 запущена на относительно старой ОС (Windows Server 2008, Windows 7), система по умолчанию просто не умеет согласовывать шифрование нужного уровня, и соединение разрывается на этапе рукопожатия (Handshake).
  3. Отказ от базовой аутентификации (Basic Authentication). Публичные почтовые гиганты заблокировали авторизацию сторонних программ по основному паролю от учетной записи. Теперь для работы внешнего софта требуется обязательное включение двухфакторной аутентификации и генерация специальных «Паролей приложений».
  4. Глобальные спам-фильтры и политики безопасности (SPF, DKIM, DMARC). Почтовые провайдеры тщательно проверяют цифровую подпись домена отправителя. Если письмо отправляется через некорректно настроенный шлюз, оно либо сразу отклоняется сервером, либо безвозвратно попадает в спам.

Рассмотрим подробнее по шагам практические методы решения этих проблем.

Решение 1. Обеспечение соответствия адреса отправителя логину SMTP

Начнем с исправления самой распространенной логической ошибки. Нам необходимо скорректировать программный код в 1С 7.7 таким образом, чтобы адрес отправителя в заголовках письма строго совпадал с ящиком, под которым программа авторизуется на SMTP-сервере.

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


// Создаем объекты конфигурации и сообщения CDO
iConf = СоздатьОбъект("CDO.Configuration");
iMsg  = СоздатьОбъект("CDO.Message");

// Заполняем схему настроек отправки
cdoSendUsingMethod        = "http://schemas.microsoft.com/cdo/configuration/sendusing";
cdoSMTPServer             = "http://schemas.microsoft.com/cdo/configuration/smtpserver";
cdoSMTPServerPort         = "http://schemas.microsoft.com/cdo/configuration/smtpserverport";
cdoSMTPUseSSL             = "http://schemas.microsoft.com/cdo/configuration/smtpusessl";
cdoSMTPAuthenticate       = "http://schemas.microsoft.com/cdo/configuration/smtpauthenticate";
cdoSendUserName           = "http://schemas.microsoft.com/cdo/configuration/sendusername";
cdoSendPassword           = "http://schemas.microsoft.com/cdo/configuration/sendpassword";
cdoSendEmailAddress       = "http://schemas.microsoft.com/cdo/configuration/sendemailaddress";

// Указываем отправку через сетевой SMTP-сервер (значение 2)
iConf.Fields.Item(cdoSendUsingMethod).Value = 2;
iConf.Fields.Item(cdoSMTPServer).Value      = "smtp.yandex.ru";
iConf.Fields.Item(cdoSMTPServerPort).Value  = 465; // Защищенный порт SSL
iConf.Fields.Item(cdoSMTPUseSSL).Value      = 1;   // Активируем использование SSL
iConf.Fields.Item(cdoSMTPAuthenticate).Value = 1;   // Тип авторизации - Basic (обычный)

// Данные авторизации (должны совпадать!)
УчетнаяЗапись = "robot_sender@yandex.ru";
// Ниже указывается специальный "пароль приложения", а не обычный пароль от ящика
ПарольДоступа = "xxxx_xxxx_xxxx_xxxx"; 

iConf.Fields.Item(cdoSendUserName).Value     = УчетнаяЗапись;
iConf.Fields.Item(cdoSendPassword).Value     = ПарольДоступа;
iConf.Fields.Item(cdoSendEmailAddress).Value = УчетнаяЗапись;

// Записываем обновленные поля конфигурации
iConf.Fields.Update();
iMsg.Configuration = iConf;

// Заполняем заголовки письма
// КРИТИЧЕСКИ ВАЖНО: Поле From должно быть идентично УчетнойЗаписи!
iMsg.From     = УчетнаяЗапись; 
iMsg.To       = "client_address@gmail.com"; // Получатель письма
iMsg.Subject  = "Тестовая отправка актов сверки";
iMsg.TextBody = "Во вложении находится файл акта сверки взаиморасчетов.";

// При необходимости прикрепляем файлы
// iMsg.AddAttachment("C:\Otchety\Akt.pdf");

Попытка
    iMsg.Send();
    Предупреждение("Письмо успешно отправлено!");
Исключение
    Предупреждение("Не удалось отправить письмо! Ошибка: " + ОписаниеОшибки());
КонецПопытки;

Если в вашей организации требуется, чтобы письма уходили от имени конкретных сотрудников, правильным подходом будет создание справочника учетных записей сотрудников в 1С. При отправке писем параметры sendusername, sendpassword и From должны динамически подставляться из настроек текущего пользователя.

Решение 2. Обход проблем шифрования через утилиту Stunnel

Если ваша база 1С 7.7 крутится на старом сервере, операционная система которого не поддерживает новые протоколы рукопожатия TLS, прямая отправка через CDO на защищенные порты (465, 587) станет невозможной. Настройка реестра операционной системы помогает далеко не всегда, особенно на "чистых" старых сборках Windows Server 2003 или 2008.

В этом случае отличным выходом является использование бесплатной утилиты Stunnel. Разберем принцип ее работы подробно. Stunnel выступает в роли локального прокси-сервера шифрования. Он принимает незашифрованный трафик от 1С на локальном порту (например, 25), самостоятельно "заворачивает" его в шифрованный пакет в соответствии со всеми современными требованиями безопасности TLS 1.2 / TLS 1.3 и передает дальше — на реальный сервер Яндекса или Google.

Для настройки этой схемы выполним следующие шаги:

  1. Скачаем и установим дистрибутив Stunnel для Windows.
  2. Перейдем в каталог установки и откроем файл конфигурации stunnel.conf. Очистим стандартный текст и запишем настройки перенаправления. Например, для работы с Яндексом:
    
    [yandex-smtp]
    client = yes
    accept = 127.0.0.1:25
    connect = smtp.yandex.ru:465
    delay = yes
    
  3. Запустим службу Stunnel через системное меню или командную строку от имени Администратора.
  4. Теперь скорректируем наш код в 1С 7.7. Нам больше не нужно заставлять CDO шифровать данные. Мы будем отправлять почту в открытом виде на локальный адрес 127.0.0.1 на порт 25:

iConf = СоздатьОбъект("CDO.Configuration");
iMsg  = СоздатьОбъект("CDO.Message");

// Настройки перенаправляем на локальный порт Stunnel
iConf.Fields.Item("http://schemas.microsoft.com/cdo/configuration/sendusing").Value = 2;
iConf.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpserver").Value = "127.0.0.1";
iConf.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpserverport").Value = 25; // Порт Stunnel
iConf.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpusessl").Value = 0; // CDO шлет данные без SSL

// Авторизация по-прежнему нужна (Stunnel передаст ее прозрачно)
iConf.Fields.Item("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate").Value = 1;
iConf.Fields.Item("http://schemas.microsoft.com/cdo/configuration/sendusername").Value = "robot_sender@yandex.ru";
iConf.Fields.Item("http://schemas.microsoft.com/cdo/configuration/sendpassword").Value = "xxxx_xxxx_xxxx_xxxx";

iConf.Fields.Update();
iMsg.Configuration = iConf;

iMsg.From = "robot_sender@yandex.ru";
iMsg.To   = "client_address@gmail.com";
iMsg.Subject = "Отправка через прокси-шифрование Stunnel";
iMsg.TextBody = "Тело сообщения отправлено локально на Stunnel.";

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

Этот метод гарантированно решает проблему совместимости протоколов, так как за криптографию отвечает современная, постоянно обновляемая утилита Stunnel, а не устаревшие библиотеки Windows.

Решение 3. Принудительное включение TLS 1.2 на уровне операционной системы

Если вы не хотите устанавливать стороннее ПО на сервер и ваша ОС поддерживает работу с TLS 1.2, необходимо принудительно включить согласование этого протокола по умолчанию для всех COM-соединений WinHTTP в системе.

Для этого выполним редактирование реестра Windows по следующей схеме:

  1. Откроем редактор реестра regedit с правами Администратора.
  2. Перейдем к разделу безопасности сетевых протоколов: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\
  3. Создадим новый раздел с именем TLS 1.2. Внутри него создадим два подраздела: Client и Server.
  4. В подразделах Client и Server создадим по два параметра типа DWORD (32 бита):
    • Enabled со значением 1
    • DisabledByDefault со значением 0
  5. Настроим WinHTTP на использование сильного шифрования по умолчанию. Для этого перейдем к ветке: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\WinHttp\ (и к разделу HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Internet Settings\WinHttp\ на 64-битных ОС).
  6. Создадим параметр DWORD (32 бита) с именем DefaultSecureProtocols и присвоим ему шестнадцатеричное значение 00000800 (активация TLS 1.2).
  7. Обязательно перезагрузим операционную систему для применения внесенных изменений.

Решение 4. Получение "Паролей приложений" для авторизации

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

Рассмотрим алгоритм действий на примере двух популярных платформ:

Решение 5. Современная альтернатива CDO — отправка через PowerShell

Если администрирование операционной системы вызывает сложности, а библиотека CDO постоянно сбоит, отличным современным решением станет полный отказ от использования COM-объекта CDO в пользу системного скрипта PowerShell. PowerShell по умолчанию интегрирован во все современные версии ОС Windows и отлично поддерживает актуальные стандарты шифрования.

Рассмотрим, как запустить скрипт отправки почты через PowerShell прямо из сессии 1С 7.7:


// Формируем тело скрипта PowerShell
ТекстСкрипта = "
|$passwd = ConvertTo-SecureString 'xxxx_xxxx_xxxx_xxxx' -AsPlainText -Force;
|$creds  = New-Object System.Management.Automation.PSCredential ('robot_sender@yandex.ru', $passwd);
|Send-MailMessage -From 'robot_sender@yandex.ru' -To 'client_address@gmail.com' -Subject 'Акт сверки из 1С 7.7' -Body 'Добрый день! Во вложении файлы документов.' -SmtpServer 'smtp.yandex.ru' -Port 587 -UseSsl -Credential $creds;
|";

// Записываем скрипт во временный текстовый файл на диске
ПутьКФайлу = КаталогВременныхФайлов() + "sendmail.ps1";
Текст = СоздатьОбъект("Текст");
Текст.ДобавитьСтроку(ТекстСкрипта);
Текст.Записать(ПутьКФайлу);

// Вызываем выполнение скрипта через объект WScript.Shell
Шелл = СоздатьОбъект("Wscript.Shell");
СтрокаЗапуска = "powershell.exe -NoProfile -ExecutionPolicy Bypass -File """ + ПутьКФайлу + """";

// Запускаем скрытно (параметр 0) и ожидаем завершения выполнения (параметр 1)
РезультатВыполнения = Шелл.Run(СтрокаЗапуска, 0, 1);

Если РезультатВыполнения = 0 Тогда
    Предупреждение("Письмо успешно отправлено через PowerShell!");
Иначе
    Предупреждение("Ошибка выполнения скрипта PowerShell! Код возврата: " + РезультатВыполнения);
КонецЕсли;

// Удаляем временный файл скрипта с диска
ФС.УдалитьФайл(ПутьКФайлу);

Использование PowerShell позволяет обойти все ограничения устаревшей библиотеки CDO, не требует регистрации сторонних DLL в системе и гарантирует стабильную отправку почтовых сообщений на любые современные сервера.

← На главную