При автоматизации бизнес-процессов разработчики часто сталкиваются с задачей отправки уведомлений на электронную почту. Обычное текстовое письмо выглядит неинформативно, поэтому наиболее предпочтительным форматом является структурированная HTML-таблица. Для начинающего программиста 1С задача связать результат запроса к базе данных, динамически сформировать HTML-код и отправить его адресату может показаться сложной. Сегодня мы разберем эту задачу от начала до конца, изучим два альтернативных метода генерации HTML-таблицы и научимся отправлять готовые письма как стандартными средствами платформы 1С, так и с помощью встроенных механизмов Библиотеки Стандартных Подсистем (БСП).
Прежде чем перейти к написанию кода, определим важное архитектурное правило: вся работа с запросами, формирование структуры документа и отправка почтовых сообщений должны выполняться строго на сервере (в контексте процедуры &НаСервере). На клиенте работа с запросами и объектами почты недоступна по соображениям безопасности и производительности.
Этот способ является наиболее гибким, красивым и профессиональным. Вместо того чтобы вручную писать десятки строк HTML-тегов в кодовой строке, мы воспользуемся стандартным механизмом платформы. Мы визуально оформим таблицу в макете 1С (зададим шрифты, цвета ячеек, границы, выравнивание), а затем программно преобразуем полученный результат в валидный HTML-код. Платформа сделает всю рутинную работу за нас.
Выполним задачу по шагам:
МакетПисьма.Шапка — здесь нарисуем шапку нашей таблицы (колонки: №, Дата, Клиент, Сумма, Менеджер). Оформим её жирным шрифтом и зальем фоновым цветом.Строка — область, которая будет циклически выводиться для каждой записи из базы данных. В ячейках этой области укажем имена параметров в угловых скобках: &Номер, &Дата, &Клиент, &Сумма, &Менеджер. Обязательно настроим тип заполнения этих ячеек как «Параметр».Рассмотрим детальный пример программного кода, который реализует эту логику:
&НаСервере
Функция СформироватьHTMLИзТабличногоДокумента()
// 1. Инициализируем табличный документ в оперативной памяти
ТабДок = Новый ТабличныйДокумент;
// Получаем макет нашей обработки
Макет = ПолучитьМакет("МакетПисьма");
// Выводим шапку таблицы в итоговый документ
ОбластьШапка = Макет.ПолучитьОбласть("Шапка");
ТабДок.Вывести(ОбластьШапка);
// 2. Выполняем запрос к базе данных с параметрами с формы
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЗаказКлиента.Номер КАК Номер,
| ЗаказКлиента.Дата КАК Дата,
| ЗаказКлиента.Контрагент.Наименование КАК Клиент,
| ЗаказКлиента.СуммаДокумента КАК Сумма,
| ЗаказКлиента.Менеджер.Наименование КАК Менеджер
|ИЗ
| Документ.ЗаказКлиента КАК ЗаказКлиента
|ГДЕ
| ЗаказКлиента.Дата >= &ДатаНачала
| И ЗаказКлиента.СуммаДокумента >= &МинимальнаяСумма";
// Предполагается, что ДатаОтбора и СуммаОтбора — это реквизиты формы нашей обработки
Запрос.УстановитьПараметр("ДатаНачала", Объект.ДатаОтбора);
Запрос.УстановитьПараметр("МинимальнаяСумма", Объект.СуммаОтбора);
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
// 3. Обходим выборку в цикле и заполняем строки макета
ОбластьСтрока = Макет.ПолучитьОбласть("Строка");
Пока Выборка.Следующий() Цикл
// Заполняем параметры области макета значениями полей выборки
ОбластьСтрока.Параметры.Заполнить(Выборка);
// Выводим заполненную строку в табличный документ
ТабДок.Вывести(ОбластьСтрока);
КонецЦикла;
// 4. Сохраняем табличный документ во временный HTML-файл
ИмяФайла = ПолучитьИмяВременногоФайла("html");
// Важно: используем формат HTML4, так как он наиболее корректно отображается почтовыми клиентами
ТабДок.Записать(ИмяФайла, ТипФайлаТабличногоДокумента.HTML4);
// Читаем полученный файл в текстовую строку
ТекстовыйДок = Новый ТекстовыйДокумент;
ТекстовыйДок.Прочитать(ИмяФайла, КодировкаТекста.UTF8);
HTMLТекст = ТекстовыйДок.ПолучитьТекст();
// Удаляем временный файл с диска компьютера
Попытка
УдалитьФайлы(ИмяФайла);
Исключение
ЗаписьЖурналаРегистрации("ОтправкаПочты", УровеньЖурналаРегистрации.Предупреждение, , , "Не удалось удалить временный файл: " + ОписаниеОшибки());
КонецПопытки;
Возврат HTMLТекст;
КонецФункции
Использование ТипФайлаТабличногоДокумента.HTML4 гарантирует, что оформление ячеек, цвета и рамки, которые вы настроили в конфигураторе, перенесутся в письмо максимально точно. Большинство современных почтовых провайдеров (Яндекс.Почта, Mail.ru, Gmail) прекрасно распознают этот формат разметки.
Если вам не хочется создавать макет в конфигураторе или перед вами стоит задача сформировать максимально простую таблицу без изысков в дизайне, можно собрать строку HTML вручную. Этот метод работает быстрее, так как не задействует дисковую подсистему для сохранения временных файлов.
Разберем, как правильно реализовать этот подход. При ручной сборке HTML крайне важно использовать инлайновые стили CSS (стили, прописанные прямо внутри атрибута style у тегов <td> и <th>). Почтовые веб-клиенты часто вырезают глобальные блоки стилей <style> из соображений безопасности.
Проанализируем пример кода с ручным формированием строки:
&НаСервере
Функция СформироватьHTMLВручную()
// 1. Задаем начало HTML-документа со стилями таблицы
HTMLТекст = "
|<html>
|<body>
| <h3>Список заказов по вашему запросу</h3>
| <table style=""border-collapse: collapse; width: 100%; font-family: Arial, sans-serif; font-size: 14px;"">
| <tr style=""background-color: #4CAF50; color: white;"">
| <th style=""border: 1px solid #ddd; padding: 10px; text-align: left;"">№</th>
| <th style=""border: 1px solid #ddd; padding: 10px; text-align: left;"">Дата</th>
| <th style=""border: 1px solid #ddd; padding: 10px; text-align: left;"">Клиент</th>
| <th style=""border: 1px solid #ddd; padding: 10px; text-align: right;"">Сумма</th>
| <th style=""border: 1px solid #ddd; padding: 10px; text-align: left;"">Менеджер</th>
| </tr>";
// 2. Выполняем аналогичный запрос к базе данных
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЗаказКлиента.Номер КАК Номер,
| ЗаказКлиента.Дата КАК Дата,
| ЗаказКлиента.Контрагент.Наименование КАК Клиент,
| ЗаказКлиента.СуммаДокумента КАК Сумма,
| ЗаказКлиента.Менеджер.Наименование КАК Менеджер
|ИЗ
| Документ.ЗаказКлиента КАК ЗаказКлиента
|ГДЕ
| ЗаказКлиента.Дата >= &ДатаНачала
| И ЗаказКлиента.СуммаДокумента >= &МинимальнаяСумма";
Запрос.УстановитьПараметр("ДатаНачала", Объект.ДатаОтбора);
Запрос.УстановитьПараметр("МинимальнаяСумма", Объект.СуммаОтбора);
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
ЧетнаяСтрока = Ложь;
// 3. Обходим выборку и конструируем строки таблицы
Пока Выборка.Следующий() Цикл
// Сделаем чередование цветов строк для лучшей читаемости (зебра)
ЦветФона = ?(ЧетнаяСтрока, "#f2f2f2", "#ffffff");
ЧетнаяСтрока = НЕ ЧетнаяСтрока;
// Форматируем дату и сумму для красивого вывода
СтрокаДаты = Формат(Выборка.Дата, "ДФ=dd.MM.yyyy");
СтрокаСуммы = Формат(Выборка.Сумма, "ЧДЦ=2; ЧГ=3");
HTMLТекст = HTMLТекст + "
|<tr style=""background-color: " + ЦветФона + ";"">
| <td style=""border: 1px solid #ddd; padding: 8px;"">" + Выборка.Номер + "</td>
| <td style=""border: 1px solid #ddd; padding: 8px;"">" + СтрокаДаты + "</td>
| <td style=""border: 1px solid #ddd; padding: 8px;"">" + Выборка.Клиент + "</td>
| <td style=""border: 1px solid #ddd; padding: 8px; text-align: right;"">" + СтрокаСуммы + "</td>
| <td style=""border: 1px solid #ddd; padding: 8px;"">" + Выборка.Менеджер + "</td>
|</tr>";
КонецЦикла;
// Закрываем теги документа
HTMLТекст = HTMLТекст + "
| </table>
|</body>
|</html>";
Возврат HTMLТекст;
КонецФункции
Обратите внимание на явное преобразование типов с помощью функции Формат(). Если выводить дату или число напрямую без форматирования, то в письме вы увидите системные разделители (например, «10.09.2019 0:00:00» вместо лаконичной даты «10.09.2019»), что снизит презентабельность отчета.
Если ваша обработка должна быть полностью автономной и не зависеть от конфигурации базы данных, вы можете настроить отправку через стандартные объекты платформы ИнтернетПочта и ИнтернетПочтовоеСообщение. Для этого вам потребуются параметры авторизации вашего почтового ящика.
Важное предупреждение: Современные почтовые сервисы (Yandex, Mail.ru, Gmail) требуют использования SSL-шифрования и блокируют авторизацию по обычному паролю от вашего ящика. Вам необходимо зайти в личный кабинет вашей почты в браузере, перейти в раздел безопасности и сгенерировать специальный «Пароль для внешних приложений» (пароль для SMTP/IMAP). Именно этот пароль нужно указывать в коде 1С.
Рассмотрим пример отправки готового HTML-текста стандартными средствами 1С:
&НаСервере
Процедура ОтправитьПисьмоНапрямую(HTMLТекстПисьма)
// 1. Настраиваем профиль подключения к почтовому серверу
Профиль = Новый ИнтернетПочтовыйПрофиль;
Профиль.АдресСервераSMTP = "smtp.yandex.ru"; // SMTP-сервер вашего провайдера
Профиль.ПортSMTP = 465; // Стандартный SSL-порт
Профиль.ИспользоватьSSLSMTP = Истина;
Профиль.ПользовательSMTP = "my_email_account@yandex.ru";
// Указываем специальный сгенерированный пароль приложения, а не пароль от почты!
Профиль.ПарольSMTP = "xxxx-xxxx-xxxx-xxxx";
Профиль.АутентификацияSMTP = СпособSMTPАутентификации.Login;
// 2. Создаем почтовое сообщение
Письмо = Новый ИнтернетПочтовоеСообщение;
Письмо.Отправитель.Адрес = "my_email_account@yandex.ru";
Письмо.Отправитель.ОтображаемоеИмя = "Робот 1С";
// Добавляем получателя (можно добавить несколько)
НовыйПолучатель = Письмо.Получатели.Добавить("customer_mail@mail.ru");
НовыйПолучатель.ОтображаемоеИмя = "Уважаемый клиент";
Письмо.Тема = "Отчет по заказам клиентов от " + Формат(ТекущаяДата(), "ДЛФ=D");
// 3. КРИТИЧЕСКИ ВАЖНО: Добавляем подготовленный HTML и указываем правильный тип текста
ТекстСообщения = Письмо.Тексты.Добавить(HTMLТекстПисьма);
ТекстСообщения.ТипТекста = ТипТекстаПочтовогоСообщения.HTML;
// 4. Подключаемся и отправляем
Почта = Новый ИнтернетПочта;
Попытка
Почта.Подключиться(Профиль);
Почта.Послать(Письмо);
Почта.Отключиться();
ВызватьИсключение "Письмо успешно отправлено!"; // Перехватим сообщение для вывода пользователю
Исключение
ВызватьИсключение "Произошла ошибка при отправке: " + ОписаниеОшибки();
КонецПопытки;
КонецПроцедуры
Если вы разрабатываете обработку для современной типовой конфигурации (например, 1С:Управление торговлей 11, ERP, Комплексная автоматизация или 1С:Бухгалтерия), в ней гарантированно присутствует встроенная библиотека БСП. В этом случае писать низкоуровневый код авторизации SMTP не требуется. Настройки почтового сервера уже внесены администратором в информационную базу. Нам достаточно обратиться к готовым процедурам БСП.
Рассмотрим, как отправить письмо через системную учетную запись конфигурации:
&НаСервере
Процедура ОтправитьПисьмоЧерезБСП(HTMLТекстПисьма)
// 1. Получаем предопределенную системную учетную запись
СистемнаяУчетка = Справочники.УчетныеЗаписиЭлектроннойПочты.СистемнаяУчетнаяЗаписьЭлектроннойПочты;
Если НЕ ЗначениеЗаполнено(СистемнаяУчетка) Тогда
ВызватьИсключение "В системе не настроена системная учетная запись электронной почты!";
КонецЕсли;
// 2. Формируем структуру параметров письма согласно стандартам БСП
ПараметрыПисьма = Новый Структура;
ПараметрыПисьма.Вставить("Кому", "customer_mail@mail.ru");
ПараметрыПисьма.Вставить("Тема", "Сводный отчет по заказам клиентов");
// Передаем HTML-строку напрямую в тело
ПараметрыПисьма.Вставить("Тело", HTMLТекстПисьма);
// Указываем БСП, что тело письма имеет формат разметки HTML
ПараметрыПисьма.Вставить("ТипТекста", "HTML");
// 3. Вызываем процедуру БСП для отправки почты
Попытка
РаботаСПочтовымиСообщениями.ОтправитьПочтовоеСообщение(СистемнаяУчетка, ПараметрыПисьма);
Сообщить("Письмо успешно отправлено через механизмы БСП!");
Исключение
Сообщить("Ошибка отправки средствами БСП: " + ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
Использование БСП значительно сокращает размер программного кода, повышает надежность системы и исключает необходимость жестко прописывать логины и пароли в самой обработке, что является правилом хорошего тона при разработке на платформе 1С:Предприятие.
При промышленной эксплуатации почтовых рассылок из 1С обязательно учитывайте следующие технические рекомендации:
Вложение в 1С).ФоновыеЗадания.Выполнить().Мы подробно разобрали, как решить проблему увязки результатов запроса, генерации читабельной HTML-верстки таблицы и последующей доставки её до адресата. Используйте макеты табличных документов для сложных отчетов с логотипами и цветным оформлением, а быстрый ручной сбор тегов — для оперативных простых сводок.