Автоматическая отправка писем и уведомлений непосредственно из учетной системы — это стандартная и критически важная функция для любого бизнеса. В среде 1С:Предприятие 7.7 классическим и самым популярным инструментом для решения этой задачи долгое время являлась встроенная библиотека Windows CDO (Collaboration Data Objects). Данное решение ценилось разработчиками за простоту внедрения, отсутствие необходимости устанавливать сторонние почтовые клиенты (такие как MS Outlook или Mozilla Thunderbird) и высокую скорость работы.
Однако современные почтовые сервисы (Yandex, Gmail, Mail.ru) непрерывно совершенствуют механизмы защиты от спама и несанкционированного доступа. Из-за этого стабильно работавшие годами обработки отправки почты в один момент перестают функционировать, выдавая бесконечное ожидание или ошибку "Не было отправлено". В этой статье мы подробно разберем, почему ломается отправка почты через CDO, проанализируем технические причины сбоев и рассмотрим несколько надежных способов восстановления работоспособности системы.
Прежде чем приступать к исправлению программного кода или перенастройке серверов, давайте детально проанализируем основные факторы, из-за которых современные почтовые провайдеры блокируют запросы от старых COM-объектов Windows:
550 Sender address rejected) для защиты от спуфинга (подделки заголовков).Рассмотрим подробнее по шагам практические методы решения этих проблем.
Начнем с исправления самой распространенной логической ошибки. Нам необходимо скорректировать программный код в 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 должны динамически подставляться из настроек текущего пользователя.
Если ваша база 1С 7.7 крутится на старом сервере, операционная система которого не поддерживает новые протоколы рукопожатия TLS, прямая отправка через CDO на защищенные порты (465, 587) станет невозможной. Настройка реестра операционной системы помогает далеко не всегда, особенно на "чистых" старых сборках Windows Server 2003 или 2008.
В этом случае отличным выходом является использование бесплатной утилиты Stunnel. Разберем принцип ее работы подробно. Stunnel выступает в роли локального прокси-сервера шифрования. Он принимает незашифрованный трафик от 1С на локальном порту (например, 25), самостоятельно "заворачивает" его в шифрованный пакет в соответствии со всеми современными требованиями безопасности TLS 1.2 / TLS 1.3 и передает дальше — на реальный сервер Яндекса или Google.
Для настройки этой схемы выполним следующие шаги:
stunnel.conf. Очистим стандартный текст и запишем настройки перенаправления. Например, для работы с Яндексом:
[yandex-smtp]
client = yes
accept = 127.0.0.1:25
connect = smtp.yandex.ru:465
delay = yes
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.
Если вы не хотите устанавливать стороннее ПО на сервер и ваша ОС поддерживает работу с TLS 1.2, необходимо принудительно включить согласование этого протокола по умолчанию для всех COM-соединений WinHTTP в системе.
Для этого выполним редактирование реестра Windows по следующей схеме:
regedit с правами Администратора.HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2. Внутри него создадим два подраздела: Client и Server.Client и Server создадим по два параметра типа DWORD (32 бита):
Enabled со значением 1DisabledByDefault со значением 0HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\WinHttp\ (и к разделу HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Internet Settings\WinHttp\ на 64-битных ОС).DefaultSecureProtocols и присвоим ему шестнадцатеричное значение 00000800 (активация TLS 1.2).Попытка использовать стандартный пароль от ящика (даже сложный и надежный) приведет к ошибке авторизации, если вы используете крупные публичные почтовые сервисы. Нам необходимо сгенерировать специальный пароль для сторонней программы.
Рассмотрим алгоритм действий на примере двух популярных платформ:
sendpassword.Если администрирование операционной системы вызывает сложности, а библиотека 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 в системе и гарантирует стабильную отправку почтовых сообщений на любые современные сервера.