При автоматизации бизнес-процессов часто возникает задача оперативного информирования пользователей или руководства. Отправлять полноценный отчет в формате Excel или PDF во вложении не всегда удобно, особенно если адресат читает почту со смартфона. Гораздо эффективнее вывести краткую выжимку или небольшую таблицу отчета непосредственно в тело электронного письма. В данной статье мы подробно разберем, как решить эту задачу в 1С, избежав искажения оформления в различных почтовых клиентах.
Самый очевидный способ, который часто используют разработчики на начальном этапе — это стандартная выгрузка сформированного табличного документа в формат HTML с последующей отправкой. Платформа 1С имеет встроенную поддержку такого экспорта.
Давайте посмотрим, как выглядит классическая реализация этого подхода с записью временного файла на диск:
// 1. Создаем и заполняем табличный документ
ТабДок = Новый ТабличныйДокумент;
// Здесь код построения вашего отчета (например, вывод макета или СКД)
// ...
// 2. Записываем его во временный файл в формате HTML
ПутьКФайлу = ПолучитьИмяВременногоФайла("html");
ТабДок.Записать(ПутьКФайлу, ТипФайлаТабличногоДокумента.HTML);
// 3. Читаем полученный HTML-код в текстовую строку
ТекстовыйДокумент = Новый ТекстовыйДокумент;
ТекстовыйДокумент.Прочитать(ПутьКФайлу, КодировкаТекста.UTF8);
ТекстПисьмаHTML = ТекстовыйДокумент.ПолучитьТекст();
// 4. Удаляем временный файл с диска
Попытка
УдалитьФайлы(ПутьКФайлу);
Исключение
// Запись лога об ошибке удаления файла при необходимости
КонецПопытки;
Этот метод прост в реализации, однако он имеет существенные недостатки, которые могут полностью испортить результат:
<style>, расположенный внутри заголовка <head>. Подавляющее большинство почтовых сервисов (таких как Mail.ru, Яндекс.Почта, Gmail, Outlook) в целях безопасности полностью вырезают блоки стилей из заголовков писем. В результате получатель увидит обычный черный текст без границ, выравнивания и фоновых выделений.Прежде чем перейти к исправлению верстки, давайте избавимся от создания временных файлов на диске. Начиная с версии платформы 1С 8.3, разработчикам доступен объект ПотокВПамяти. С его помощью мы можем получить HTML-код напрямую в оперативную память, что значительно повышает производительность и стабильность работы кода на сервере.
Рассмотрим, как реализовать этот алгоритм:
ТабДок = Новый ТабличныйДокумент;
// Код заполнения ТабДока
// ...
// Записываем табличный документ в поток памяти
Поток = Новый ПотокВПамяти();
ТабДок.Записать(Поток, ТипФайлаТабличногоДокумента.HTML);
// Извлекаем двоичные данные из потока и закрываем его
ДвоичныеДанныеHTML = Поток.ЗакрытьИПолучитьДвоичныеДанные();
// Преобразуем двоичные данные в строку с кодировкой UTF-8
ТекстHTML = ПолучитьСтрокуИзДвоичныхДанных(ДвоичныеДанныеHTML, КодировкаТекста.UTF8);
Этот способ работает гораздо быстрее, так как исключает накладные расходы на дисковые операции ввода-вывода (I/O) и полностью безопасен при работе в многопоточной серверной среде.
Чтобы таблица гарантированно отображалась во всех почтовых клиентах (включая мобильные приложения и веб-интерфейсы), все стили должны быть инлайновыми (Inline CSS). Это значит, что параметры оформления должны быть прописаны непосредственно внутри тегов <td> и <tr> с помощью атрибута style.
Для небольших отчетов лучшим решением является ручной обход таблицы значений или строк табличного документа в цикле и формирование "чистого" HTML-кода. Давайте разберем по шагам пример генерации такой таблицы:
// Предположим, у нас есть ТаблицаЗначений с данными отчета
ТаблицаДанных = Новый ТаблицаЗначений;
ТаблицаДанных.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("Строка"));
ТаблицаДанных.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число"));
ТаблицаДанных.Колонки.Добавить("Сумма", Новый ОписаниеТипов("Число"));
// Заполним тестовыми данными
НоваяСтрока = ТаблицаДанных.Добавить();
НоваяСтрока.Номенклатура = "Кирпич строительный красный";
НоваяСтрока.Количество = 1500;
НоваяСтрока.Сумма = 45000;
НоваяСтрока = ТаблицаДанных.Добавить();
НоваяСтрока.Номенклатура = "Цемент М500 (мешок 50кг)";
НоваяСтрока.Количество = 50;
НоваяСтрока.Сумма = 22500;
// Начинаем сборку HTML-кода
HTML_Код = "<html><body>";
HTML_Код = HTML_Код + "<p>Уважаемые коллеги, направляем вам сводный отчет по продажам:</p>";
// Инициализируем таблицу с инлайновыми стилями и явной границей для старых клиентов
HTML_Код = HTML_Код + "<table border=""1"" cellpadding=""5"" cellspacing=""0"" style=""border-collapse: collapse; width: 100%; max-width: 600px; font-family: Arial, sans-serif; font-size: 14px;"">";
// Формируем шапку таблицы
HTML_Код = HTML_Код + "<tr style=""background-color: #f2f2f2; font-weight: bold; text-align: left;"">";
HTML_Код = HTML_Код + "<th style=""border: 1px solid #cccccc; padding: 8px;"">Товар</th>";
HTML_Код = HTML_Код + "<th style=""border: 1px solid #cccccc; padding: 8px; text-align: right;"">Кол-во</th>";
HTML_Код = HTML_Код + "<th style=""border: 1px solid #cccccc; padding: 8px; text-align: right;"">Сумма, руб.</th>";
HTML_Код = HTML_Код + "</tr>";
// Заполняем строки данными
Для Каждого СтрокаДанных Из ТаблицаДанных Цикл
HTML_Код = HTML_Код + "<tr>";
HTML_Код = HTML_Код + "<td style=""border: 1px solid #cccccc; padding: 8px;"">" + СтрокаДанных.Номенклатура + "</td>";
HTML_Код = HTML_Код + "<td style=""border: 1px solid #cccccc; padding: 8px; text-align: right;"">" + СтрокаДанных.Количество + "</td>";
HTML_Код = HTML_Код + "<td style=""border: 1px solid #cccccc; padding: 8px; text-align: right;"">" + Формат(СтрокаДанных.Сумма, "ЧДЦ=2; ЧГ=3") + "</td>";
HTML_Код = HTML_Код + "</tr>";
КонецЦикла;
HTML_Код = HTML_Код + "</table>";
HTML_Код = HTML_Код + "<p>Отчет сформирован автоматически из системы 1С.</p>";
HTML_Код = HTML_Код + "</body></html>";
Проанализируем ключевые особенности этой верстки:
border-collapse: collapse; позволяет получить аккуратную тонкую одинарную рамку вместо стандартной двойной HTML-границы.max-width: 600px; гарантирует, что таблица будет отлично смотреться как на больших мониторах, так и на экранах смартфонов, сужаясь до ширины экрана без появления горизонтального скролла.<td> и <th> стили рамки border: 1px solid #cccccc; продублированы явно. Почтовый клиент гарантированно отобразит эти границы.Если структура табличного документа достаточно сложная (используются множественные объединения ячеек, сложные цвета, иерархические группировки) и писать ручной парсер слишком трудозатратно, можно применить комбинированный подход.
Мы можем сгенерировать стандартный HTML-код с помощью платформы 1С, загрузить полученную строку в объект ДокументHTML через ПостроительDOM, а затем программно перенести все стили из заголовка таблицы непосредственно в атрибуты style каждого узла ячейки. Этот процесс называется CSS-инлайнингом.
Ниже представлена концептуальная схема такого парсинга:
// Читаем сгенерированный платформой HTML в DOM-документ
ЧтениеHTML = Новый ЧтениеHTML;
ЧтениеHTML.УстановитьСтроку(ТекстHTML_Из_1С);
Построитель = Новый ПостроительDOM;
ДокументHTML = Построитель.Прочитать(ЧтениеHTML);
// Получаем все элементы ячеек "td"
Ячейки = ДокументHTML.ПолучитьЭлементыПоИмени("td");
Для Каждого Ячейка Из Ячейки Цикл
// Программный анализ класса ячейки и замена его на инлайновый стиль
// Здесь разработчик может сопоставить имя класса с таблицей стилей из тега <style>
// и применить метод: Ячейка.УстановитьАтрибут("style", "border: 1px solid #ccc; ...");
КонецЦикла;
Часто в шапке отчета присутствует логотип компании или иные графические элементы. Если просто сохранить табличный документ со встроенной картинкой в HTML, платформа создаст локальную папку с файлом изображения (например, image001.png). Почтовый клиент получателя не сможет отобразить такую картинку, так как ссылка ведет на локальный диск отправителя.
Существует два надежных способа интеграции графики в письма:
<img>. Код будет выглядеть следующим образом:
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..." />
Важно: Некоторые строгие почтовые фильтры и веб-интерфейсы корпоративных почтовых систем могут блокировать отображение картинок в формате Base64 из соображений безопасности.
Content-ID (например, logo_1c). В самом HTML-коде письма на нее делается внутренняя ссылка:
<img src="cid:logo_1c" />
Этот вариант является промышленным стандартом рассылки и отлично поддерживается всеми почтовыми сервисами.
Если перед вами стоит задача отправить сложный финансовый или аналитический отчет, содержащий большое количество колонок, группировок, иерархических уровней или диаграмм, то попытка поместить его непосредственно в тело письма обречена на неудачу. Сложная верстка неизбежно «развалится» на смартфонах или в некоторых веб-клиентах.
В таких ситуациях рекомендуется использовать следующую архитектуру:
ТабДок.Записать(Поток, ТипФайлаТабличногоДокумента.PDF). Этот формат гарантирует абсолютную точность отображения шрифтов, цветов и разметки независимо от используемого устройства.ИнтернетПочтовоеСообщение во вложения.Благодаря такому подходу, получатель сможет прямо из превью-экрана почты оценить ключевые цифры отчета, а при необходимости детального анализа — открыть вложенный файл PDF в исходном оформлении.