---
title: Блочное формирование HTML-писем
slug: общие-работа-с-почтой/блочное-формирование-html-писем
---

```bsl
#Область ПрограммныйИнтерфейс

// Функция - Сообщение HTML
//
// Параметры:
//  Заголовок					 - Строка	 - Строка, которая будет отображаться в шапке письма крупным шрифтом
//  МассивБлоковHTMLСообщения	 - Массив Из Строка	 - Массив строк, сформированных функциями "БлокHMTLСообщения_..."
//  ПараметрыОформления			 - Структура - см. ПараметрыОформленияHTMLСообщения. Если неопределено создаются параметры по умолчанию
// 
//	БлокОбъектов = Новый Массив;
//	// Абзац
//	БлокОбъектов.Добавить(ОбработкаОбъект.БлокHTMLСообщения_Абзац("Скажи-ка, дядя, ведь<>%$"""" ' недаром, Москва..." + Символы.ПС + "tot;ladkflasdhkf;as"));
//	
//	// Абзац с гиперссылкой
//	ПараметрыГиперссылки = Новый Соответствие;
//	ПараметрыГиперссылки.Вставить("с гиперссылкой", "https://www.google.com");
//	ПараметрыГиперссылки.Вставить("еще одной", "https://www.google.com");
//	БлокОбъектов.Добавить(ОбработкаОбъект.БлокHTMLСообщения_АбзацСГиперссылками("Абзацы можно добавлять [с гиперссылкой] и, если хочется, [еще одной]. Количество не ограничено", ПараметрыГиперссылки));
//	
//	БлокОбъектов.Добавить(ОбработкаОбъект.БлокHTMLСообщения_Абзац("Так будет выглядеть список. Формируется из массива"));
//	
//	// Список пунктов
//	МассивПунктов = Новый Массив;
//	МассивПунктов.Добавить("Пункт 1");
//	МассивПунктов.Добавить("Пункт 2");
//	
//	МассивПодпунктов = Новый Массив;
//	МассивПодпунктов.Добавить("Подпункт 1");
//	МассивПодпунктов.Добавить("Подпункт 2");
//	
//	МассивПодпунктов1 = Новый Массив;
//	МассивПодпунктов1.Добавить("Подпункт 1");
//	МассивПодпунктов1.Добавить("Подпункт 2");
//	МассивПодпунктов.Добавить(МассивПодпунктов1);
//	
//	МассивПунктов.Добавить(МассивПодпунктов);
//	МассивПунктов.Добавить("Пункт 3");
//	
//	БлокОбъектов.Добавить(ОбработкаОбъект.БлокHTMLСообщения_СписокНенумерованный(МассивПунктов));
//	
//	// В результате такая структура
//	//	Пункт 1
//	//	Пункт 2
//	//		Подпункт 1
//	//		Подпункт 2
//	//			Подпункт 1
//	//			Подпункт 2
//	//	Пункт 3
//
//
//	// Таблица
//	ТЗ = Новый ТаблицаЗначений;
//	ТЗ.Колонки.Добавить("НомерПоПорядку", , "№", 5); // ширину задаем, если нужна разная ширина колонок
//	ТЗ.Колонки.Добавить("Номенклатура");
//	ТЗ.Колонки.Добавить("Характеристика");
//	ТЗ.Колонки.Добавить("Количество", , "Кол-во" , 10);
//	
//	НоваяСтрока = ТЗ.Добавить();
//	НоваяСтрока.НомерПоПорядку = "1";
//	НоваяСтрока.Номенклатура = "Номенклатура 1";
//	НоваяСтрока.Характеристика = "";
//	НоваяСтрока.Количество = 10;
//	
//	НоваяСтрока = ТЗ.Добавить();
//	НоваяСтрока.НомерПоПорядку = "2";
//	НоваяСтрока.Номенклатура = "Номенклатура 2";
//	НоваяСтрока.Характеристика = "с характеристикой";
//	НоваяСтрока.Количество = "15";
//	
//	БлокОбъектов.Добавить(ОбработкаОбъект.БлокHTMLСообщения_Таблица(ТЗ));
//	
//  // Цитата
//	БлокОбъектов.Добавить(ОбработкаОбъект.БлокHTMLСообщения_Цитата("Это цитата"));
//	
//	Результат = ОбработкаОбъект.СообщениеHTML("Добрый день", БлокОбъектов);
// Возвращаемое значение:
//  Строка - сообщение, оформленное в HTML
//
Функция СообщениеHTML(Заголовок, МассивБлоковHTMLСообщения, ПараметрыОформления = Неопределено) Экспорт

	Шаблон = ШаблонHTMLСообщения(ПараметрыОформления);
	
	ПараметрыЗаполнения = Новый Структура("ТелоСообщения", СтрСоединить(МассивБлоковHTMLСообщения, Символы.ПС));
	ПараметрыЗаполнения.Вставить("Заголовок", НормализованныйТекстДляHTML(Заголовок));
	
	Результат = СтроковыеФункцииКлиентСервер.ВставитьПараметрыВСтроку(Шаблон, ПараметрыЗаполнения);
	
	Возврат Результат;
	
КонецФункции

// Функция - Параметры оформления HTMLСообщения. Содержит значения плейсхолдеров инлайновых стилей CSS в шаблоне.
//			Обязательны все для формирования работы метода СообщениеHTML.
// 
// Возвращаемое значение:
//  Структура - 
//	ТелоЦветЗаднегоФона 			- Строка - background. По умолчанию "rgb(245, 245, 245)"
//	ТелоШрифт 						- Строка - font-family. По умолчанию "Arial, sans-serif"
//	
//	АбзацВнутреннийОтступ 			- Строка - padding. По умолчанию "2px"
//	АбзацРазмерШрифта 				- Строка - font-size. По умолчанию "14px"
//	АбзацМежстрочныйИнтервал 		- Строка - line-height. По умолчанию "1.6"
//	АбзацЦветТекста 				- Строка - color. По умолчанию "rgb(51, 51, 51)"
//	АбзацВнешнийОтступ 				- Строка - margin. По умолчанию "5px"
//	
//	КонтейнерВнешнийОтступ 			- Строка - margin. По умолчанию	"40px"
//	КонтейнерЦветФона 				- Строка - background. По умолчанию "rgb(255, 255, 255)"
//	КонтейнерВнутреннийОтступ 		- Строка - padding. По умолчанию "20px"
//	КонтейнерСкругление 			- Строка - border-radius. По умолчанию "6px"
//	КонтейнерТень 					- Строка - box-shadow. По умолчанию "0 2px 4px rgba(0, 0, 0, 0.1)"
//	
//	ЗаголовокЦветТекста 			- Строка - color. По умолчанию "rgb(118, 34, 40)"
//	ЗаголовокВнутреннийОтступ 		- Строка - padding. По умолчанию "0px"
//	ЗаголовокВнешнийОтступ 			- Строка - margin. По умолчанию "10px"
//	
//	КонтентШирина 					- Строка - width. По умолчанию "1000"
//	КонтентВнутреннийОтступ 		- Строка - padding. По умолчанию "5px"
//	КонтентРазмерШрифта 			- Строка - font-size. По умолчанию "14px"
//	КонтентМежстрочныйИнтервал 		- Строка - line-height. По умолчанию "1.6"
//	КонтентЦветТекста 				- Строка - color. По умолчанию "rgb(51, 51, 51)"
//	
//	ТаблицаШирина 					- Строка - width. По умолчанию "960". ВНИМАНИЕ, Всегда указывайте как строковое представление числа, без "px, em" и пр.
//	ТаблицаВнешнийОтступ 			- Строка - margin. По умолчанию "10px"
//	ЯчейкаГраница 					- Строка - border. По умолчанию "1px solid rgb(204, 204, 204)"
//	ТаблицаЦветФонаЗаголовка 		- Строка - background. По умолчанию "rgb(230, 230, 230)"
//	ТаблицаЦветТекстаЗаголовка 		- Строка - color. По умолчанию "rgb(118, 34, 40)"
//	 
//	СсылкаЦветТекста 				- Строка - color. По умолчанию "rgb(118, 34, 40)"
//	СсылкаЦветФона 					- Строка - background. По умолчанию "rgb(249, 249, 249)"
//
//	ЦитатаВнутреннийОтступ 			- Строка - padding. По умолчанию "10px"
//	ЦитатаЦветФона 					- Строка - background. По умолчанию "rgb(249, 249, 249)"
//	ЦитатаГраницаСлева 				- Строка - border-left. По умолчанию "4px solid rgb(118, 34, 40)"
//	 
//	ПодвалОтступСверху 				- Строка - padding-top. По умолчанию "20px"
//	ПодвалРазмерШрифта 				- Строка - font-size. По умолчанию "11px"
//	ПодвалЦветТекста 				- Строка - color. По умолчанию "rgb(119, 119, 119)"
//
Функция ПараметрыОформленияHTMLСообщения() Экспорт

	
	ПараметрыОформления = Новый Структура;

	ПараметрыОформления.Вставить("ТелоЦветЗаднегоФона", 			"rgb(245, 245, 245)");
	ПараметрыОформления.Вставить("ТелоШрифт", 						"Arial, sans-serif");
	
	ПараметрыОформления.Вставить("АбзацВнутреннийОтступ", 			"2px");
	ПараметрыОформления.Вставить("АбзацРазмерШрифта", 				"14px");
	ПараметрыОформления.Вставить("АбзацМежстрочныйИнтервал", 		"1.6");
	ПараметрыОформления.Вставить("АбзацЦветТекста", 				"rgb(51, 51, 51)");
	ПараметрыОформления.Вставить("АбзацВнешнийОтступ", 				"5px");
	
	ПараметрыОформления.Вставить("КонтейнерВнешнийОтступ",			"40px");
	ПараметрыОформления.Вставить("КонтейнерЦветФона", 				"rgb(255, 255, 255)");
	ПараметрыОформления.Вставить("КонтейнерВнутреннийОтступ", 		"20px");
	ПараметрыОформления.Вставить("КонтейнерСкругление", 			"6px");
	ПараметрыОформления.Вставить("КонтейнерТень", 					"0 2px 4px rgba(0, 0, 0, 0.1)");
	
	ПараметрыОформления.Вставить("ЗаголовокЦветТекста", 			"rgb(118, 34, 40)");
	ПараметрыОформления.Вставить("ЗаголовокВнутреннийОтступ", 		"0px");
	ПараметрыОформления.Вставить("ЗаголовокВнешнийОтступ",			"10px");
	
	ПараметрыОформления.Вставить("КонтентШирина",					"1000");
	ПараметрыОформления.Вставить("КонтентВнутреннийОтступ", 		"5px");
	ПараметрыОформления.Вставить("КонтентРазмерШрифта", 			"14px");
	ПараметрыОформления.Вставить("КонтентМежстрочныйИнтервал", 		"1.6");
	ПараметрыОформления.Вставить("КонтентЦветТекста", 				"rgb(51, 51, 51)");
	
	ПараметрыОформления.Вставить("ТаблицаШирина",					"960");
	ПараметрыОформления.Вставить("ТаблицаВнешнийОтступ",			"10px auto");
	ПараметрыОформления.Вставить("ЯчейкаГраница", 					"1px solid rgb(204, 204, 204)");
	ПараметрыОформления.Вставить("ТаблицаЦветФонаЗаголовка", 		"rgb(230, 230, 230)");
	ПараметрыОформления.Вставить("ТаблицаЦветТекстаЗаголовка", 		"rgb(118, 34, 40)");
	 
	ПараметрыОформления.Вставить("СсылкаЦветТекста", 				"rgb(118, 34, 40)");
	ПараметрыОформления.Вставить("СсылкаЦветФона", 					"rgb(249, 249, 249)");

	ПараметрыОформления.Вставить("ЦитатаВнутреннийОтступ", 			"10px");
	ПараметрыОформления.Вставить("ЦитатаЦветФона", 					"rgb(249, 249, 249)");
	ПараметрыОформления.Вставить("ЦитатаГраницаСлева", 				"4px solid rgb(118, 34, 40)");
	 
	ПараметрыОформления.Вставить("ПодвалОтступСверху", 				"20px");
	ПараметрыОформления.Вставить("ПодвалРазмерШрифта", 				"11px");
	ПараметрыОформления.Вставить("ПодвалЦветТекста", 				"rgb(119, 119, 119)");

	Возврат ПараметрыОформления;
	
КонецФункции

// Функция - Блок HTMLСообщения заголовок
//
// Параметры:
//  ТекстЗаголовка		 - Строка	 - Текст, выводимый в блоке
//  Уровень				 - Число	 - уровень заголовка от 1 до 6. Рекомендуется использовать от 2 до 4.
//  ПараметрыОформления	 - Структура - см. ПараметрыОформленияHTMLСообщения
// 
// Возвращаемое значение:
//  Строка - Блок вида <h1...></h...>
//
Функция БлокHTMLСообщения_Заголовок(ТекстЗаголовка, Уровень = 2, ПараметрыОформления = Неопределено) Экспорт
	
	Если ПараметрыОформления = Неопределено Тогда
		ПараметрыОформления = ПараметрыОформленияHTMLСообщения();
	КонецЕсли;
	
	Если Уровень < 1 Или Уровень > 6 Тогда
		Уровень = 2;
	КонецЕсли;
	
	ШаблонЗаголовка = "<h%1 style=""margin: [ЗаголовокВнешнийОтступ]; padding: [ЗаголовокВнутреннийОтступ]; font-family: [ТелоШрифт]; color: [ЗаголовокЦветТекста]"">%2</h%1>
						|";
	Результат = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонЗаголовка, 
		Формат(Уровень, "ЧДЦ=0; ЧГ="),
		НормализованныйТекстДляHTML(ТекстЗаголовка));
	
	Возврат СтроковыеФункцииКлиентСервер.ВставитьПараметрыВСтроку(Результат, ПараметрыОформления);
	
КонецФункции

// Функция - Блок HTMLСообщения абзац
//
// Параметры:
//  ТекстАбзаца			 - Строка	 - Текст, который будет выведен в абзаце
//  ПараметрыОформления	 - Структура, Неопределено - см. ПараметрыОформленияHTMLСообщения(). 
//  Нормализовать		 - Булево	 - Служебный, определяет необходимость экранирования спец.символов
// 
// Возвращаемое значение:
//  Строка - Блок вида <p style="">Текст</p>
//
Функция БлокHTMLСообщения_Абзац(ТекстАбзаца, ПараметрыОформления = Неопределено, Нормализовать = Истина) Экспорт
	
	Если ПараметрыОформления = Неопределено Тогда
		ПараметрыОформления = ПараметрыОформленияHTMLСообщения();
	КонецЕсли;
	
	Результат = СтрШаблон("<p style=""margin: [АбзацВнешнийОтступ]; font-family: [ТелоШрифт]; padding: [АбзацВнутреннийОтступ]; font-size: [АбзацРазмерШрифта]; line-height: [АбзацМежстрочныйИнтервал]; color: [АбзацЦветТекста];"">%1</p>
						|",
						?(Нормализовать, НормализованныйТекстДляHTML(ТекстАбзаца), ТекстАбзаца));
						
	Возврат СтроковыеФункцииКлиентСервер.ВставитьПараметрыВСтроку(Результат, ПараметрыОформления);
	
КонецФункции

// Функция - Абзац сообщения с гиперссылками
//
// Параметры:
//  ШаблонАбзаца - Строка - Шаблон вида "Нажмите [на эту ссылку], чтобы узнать больше". [на эту ссылку] - ключ соответствия СписокСсылок
//  СписокСсылок - Соответствие	 - 
//		* Ключ - Строка - представление ссылки в письме. Т.е. ключ "на эту ссылку" заменит строку "[на эту ссылку]" в шаблоне
//		* Значение - Строка - ссылка для вставки
//  ПараметрыОформления	 - Структура, Неопределено - см. ПараметрыОформленияHTMLСообщения(). Если неопределено создаются параметры по умолчанию 
// 
// Возвращаемое значение:
// Строка  - Блок вида <p style="">Текст до ссылки <a href="Ссылка" style="">Представление ссылки</a> Текст после ссылки</p>
//
Функция БлокHTMLСообщения_АбзацСГиперссылками(Знач ШаблонАбзаца, СписокСсылок, ПараметрыОформления = Неопределено) Экспорт
	
	Если ПараметрыОформления = Неопределено Тогда
		ПараметрыОформления = ПараметрыОформленияHTMLСообщения();
	КонецЕсли;
	
	ШаблонАбзаца = НормализованныйТекстДляHTML(ШаблонАбзаца);
	
	Для Каждого КлючЗначение Из СписокСсылок Цикл
	    
	    Ключ = КлючЗначение.Ключ;
	    Значение = КлючЗначение.Значение;
		
		СсылкаДляВставки = СтрШаблон("<a href=""%1"" style=""font-family: [ТелоШрифт]; color: [СсылкаЦветТекста]; background: [СсылкаЦветФона]; text-decoration: underline; padding: [КонтентВнутреннийОтступ]; font-size: [КонтентРазмерШрифта]; line-height: [КонтентМежстрочныйИнтервал];"">%2</a>", 
			Значение,
			Ключ);
		
		ШаблонАбзаца = СтрЗаменить(ШаблонАбзаца, 
			СтрШаблон("[%1]", Ключ),
			СтроковыеФункцииКлиентСервер.ВставитьПараметрыВСтроку(СсылкаДляВставки, ПараметрыОформления));
	    
	КонецЦикла;
	
	Возврат БлокHTMLСообщения_Абзац(ШаблонАбзаца, ПараметрыОформления, Ложь);
	
КонецФункции

// Функция - Список ненумерованный
//
// Параметры:
//  МассивЗначений	 - Массив Из Строка, Массив Из Массив - Список элементов. Если нужен иерархический список, то добавляем не строку, а новый массив строк
//						Например, для массива [Привет, Вася, Как, Дела] будет сформирован список
//							* Привет
//							* Вася
//							* Как
//							* Дела
//						Если в этом массиве будет еще один, то список получится иерархический, Например
//						для массива [Привет, Вася, Как, Дела, [Все, Хорошо]]
//							* Привет
//							* Вася
//							* Как
//							* Дела
//								** Все
//								** Хорошо
// 
// Возвращаемое значение:
//  Строка - 
//
Функция БлокHTMLСообщения_СписокНенумерованный(МассивЗначений, ПараметрыОформления = Неопределено) Экспорт
	
	Если ПараметрыОформления = Неопределено Тогда
		ПараметрыОформления = ПараметрыОформленияHTMLСообщения();
	КонецЕсли;
	
	Текст = "";
	
	СформироватьСписокНенумерованныйHTMLРекурсивно(МассивЗначений, Текст, ПараметрыОформления);
	
	Возврат СтроковыеФункцииКлиентСервер.ВставитьПараметрыВСтроку(Текст, ПараметрыОформления);
	
КонецФункции

// Функция - Блок HTMLСообщения цитата
//
// Параметры:
//  ТекстЦитаты			 - Строка	 - Выводимый текст
//  ПараметрыОформления	 - Структура, Неопределено - см. ПараметрыОформленияHTMLСообщения(). Если неопределено создаются параметры по умолчанию 
// 
// Возвращаемое значение:
//  Строка - Блок, оформленный в виде цитаты
//
Функция БлокHTMLСообщения_Цитата(ТекстЦитаты, ПараметрыОформления = Неопределено) Экспорт
	
	
	Если ПараметрыОформления = Неопределено Тогда
		ПараметрыОформления = ПараметрыОформленияHTMLСообщения();
	КонецЕсли;
	
	Шаблон = "<table width=""100%"" cellpadding=""0"" cellspacing=""0"" border=""0"">
				|  <tr>
				|    <td style=""font-family: [ТелоШрифт]; padding: [ЦитатаВнутреннийОтступ]; background: [ЦитатаЦветФона]; border-left: [ЦитатаГраницаСлева]; font-style: italic;"">
				|      %1
				|    </td>
				|  </tr>
				|</table>";
	
	Результат = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(Шаблон, НормализованныйТекстДляHTML(ТекстЦитаты));
	
	Возврат СтроковыеФункцииКлиентСервер.ВставитьПараметрыВСтроку(Результат, ПараметрыОформления);
	
	
КонецФункции

// Функция - Блок HTMLСообщения таблица
//
// Параметры:
//  ТаблицаЗначений	 - ТаблицаЗначений	 -  Выводимая таблица. Если не заполнен заголовок, в шапке будет выведено имя,
//											если не заполнена ширина, то устанавливается ширина по умолчанию
// 
// Возвращаемое значение:
//  Строка - Таблица в HTML
//
Функция БлокHTMLСообщения_Таблица(ТаблицаЗначений, ПараметрыОформления = Неопределено) Экспорт

	
	Если ПараметрыОформления = Неопределено Тогда
		ПараметрыОформления = ПараметрыОформленияHTMLСообщения();	
	КонецЕсли;
	
	ОбщаяШиринаТаблицыСтрокой = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ПараметрыОформления, "ТаблицаШирина", "960");
	ОбщаяШиринаТаблицы = Число(ОбщаяШиринаТаблицыСтрокой);
	
	ЗначениеШириныКолонок = АбсолютнаяШиринаКолонок(ТаблицаЗначений, ОбщаяШиринаТаблицы);

	// Устанавливаем абсолютные значения ширины колонок
	Для Каждого ЗначениеШирины Из ЗначениеШириныКолонок Цикл
		ТаблицаЗначений.Колонки[ЗначениеШирины.Колонка].Ширина = ЗначениеШирины.ШиринаПикселей;
	КонецЦикла;
	
	// Подготавливаем заголовок таблицы
	ДанныеЯчеекЗаголовкаТаблицы = Новый Массив;
	Для Каждого Колонка Из ТаблицаЗначений.Колонки Цикл
		ТекстЗаполнения = ?(ЗначениеЗаполнено(Колонка.Заголовок), Колонка.Заголовок, Колонка.Имя);
		ДанныеЯчеекЗаголовкаТаблицы.Добавить(ЯчейкаЗаголовкаТаблицыHTML(ТекстЗаполнения, Колонка.Ширина));
	КонецЦикла;
	
	Заголовок = ЗаголовокТаблицыHTML(ДанныеЯчеекЗаголовкаТаблицы);

	// Подготавливаем строки
	ДанныеСтрокТаблицы = Новый Массив;
	Для Каждого Строка Из ТаблицаЗначений Цикл
		
		ДанныеЯчеекСтроки = Новый Массив;
		Для Каждого Колонка Из ТаблицаЗначений.Колонки Цикл
			ДанныеЯчеекСтроки.Добавить(ЯчейкаСтрокиОсновныхДанныхHTML(Строка[Колонка.Имя], Колонка.Ширина));
		КонецЦикла;
		
		ДанныеСтрокТаблицы.Добавить(СтрокаТаблицыHTML(ДанныеЯчеекСтроки));
		
	КонецЦикла;
	
	Таблица = ТаблицаHTML(Заголовок, ДанныеСтрокТаблицы);
	
	Возврат СтроковыеФункцииКлиентСервер.ВставитьПараметрыВСтроку(Таблица, ПараметрыОформления);
	
	
КонецФункции

#КонецОбласти

#Область СлужебныйПрограммныйИнтерфейс

Функция ШаблонHTMLСообщения(ПараметрыОформления = Неопределено) Экспорт
	
	Если ПараметрыОформления = Неопределено Тогда
		ПараметрыОформления = ПараметрыОформленияHTMLСообщения();
	КонецЕсли;
	
	Шаблон = 
	"<!DOCTYPE html>
	|<html lang=""ru"">
	|<head>
	|	<meta charset=""UTF-8"">
	|	<title>HTML Email</title>
	|</head>
	|<body style=""margin: 0; padding: 0; background: [ТелоЦветЗаднегоФона]; font-family: [ТелоШрифт];"">
	// Основной контейнер
	|	<table width=""100%"" cellpadding=""0"" cellspacing=""0"" border=""0"" style=""background: [ТелоЦветЗаднегоФона];"">
	|		<tr>
	|		  <td align=""center"">
	// Обертка
	|				<table cellpadding=""0"" cellspacing=""0"" border=""0"">
	|					<tr>
	|						<td align=""center"">
	// Начало контента
	|							<table width=""[КонтентШирина]"" cellpadding=""0"" cellspacing=""0"" border=""0"" style=""font-family: [ТелоШрифт]; background: [КонтейнерЦветФона]; padding: [КонтейнерВнутреннийОтступ]; border-radius: [КонтейнерСкругление]; box-shadow: [КонтейнерТень];"">
	|								<tr>
	|									<td style=""margin: 20px; font-family: [ТелоШрифт]; padding: [КонтентВнутреннийОтступ]; font-size: [КонтентРазмерШрифта]; line-height: [КонтентМежстрочныйИнтервал]; color: [КонтентЦветТекста];"">
	|										<h1 align=""center"" style=""margin: [ЗаголовокВнешнийОтступ]; padding: [ЗаголовокВнутреннийОтступ]; font-family: [ТелоШрифт]; color: [ЗаголовокЦветТекста]"">[Заголовок]</h1>
	|										[ТелоСообщения]
	|									</td>
	|								</tr>
	//
	// Отчерк
	|								<tr>
	|									<td height=""1"" style=""font-size: 1px; line-height: 1px; font-size: 0"">&nbsp;</td>
	|								</tr>
	|								<tr>
	|									<td style=""padding: 1px 0 0 0; border-top: 3px solid [ЗаголовокЦветТекста]; font-size: 0; line-height: 0;"">&nbsp;</td>
	|								</tr>
	// Конец отчерка
	//
	// Подпись и лого (insert base64 to src img)
	|								<tr>
	|									<td align=""center"" style=""font-family: [ТелоШрифт]; padding-top: [ПодвалОтступСверху]; font-size: [ПодвалРазмерШрифта]; color: [ПодвалЦветТекста];"">
	|										Это письмо сформировано автоматически. Пожалуйста, не отвечайте на него.
	|									</td>
	|								</tr>
	|								<tr>
	|									<td align=""center"" style=""line-height: 0; padding: 0; margin: 0;"">
	|										<img src=""""
	|											alt=""Logo""
	|											border=""0""
	|											style=""border: 0; display: block; margin: 0 auto;"">
	|									</td>
	|								</tr>
	// Конец подписи и лого
	|							</table>
	// Конец контента
	|						</td>
	|					</tr>
	|				</table>
	|			</td>
	|		</tr>
	|	</table>
	|</body>
	|</html>";
	
	Результат = СтроковыеФункцииКлиентСервер.ВставитьПараметрыВСтроку(Шаблон, ПараметрыОформления);
	
	Возврат Результат;

КонецФункции

// Функция - Нормализованный текст для HTML. Исплользуется в методах "БлокHTMLСообщения_.."
//
// Параметры:
//  Текст	 - Строка - 
// 
// Возвращаемое значение:
//  Строка - Текст с экранированными спец.символами
//
Функция НормализованныйТекстДляHTML(Знач Текст) Экспорт

	Текст = СтрЗаменить(Текст, "&", "&amp;");
	Текст = СтрЗаменить(Текст, "<", "&lt;");
	Текст = СтрЗаменить(Текст, ">", "&gt;");
	Текст = СтрЗаменить(Текст, """", "&quot;");
	Текст = СтрЗаменить(Текст, "'", "&#39;");
	
	Текст = СтрЗаменить(Текст, Символы.ПС, "<br>");
	Текст = СтрЗаменить(Текст, Символы.ВК, "<br>");
	Текст = СтрЗаменить(Текст, Символы.Таб, "    ");
	
	Возврат Текст;
	
КонецФункции

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

Процедура СформироватьСписокНенумерованныйHTMLРекурсивно(МассивЗначений, ТекстHTML = Неопределено, ПараметрыОформления = Неопределено)
	
	Если ТекстHTML = Неопределено Тогда
		ТекстHTML = "";	
	КонецЕсли;
	
	Если ПараметрыОформления = Неопределено Тогда
		ПараметрыОформления = ПараметрыОформленияHTMLСообщения();
	КонецЕсли;
	
	ТекстHTML = ТекстHTML 
		+ СтроковыеФункцииКлиентСервер.ВставитьПараметрыВСтроку(НачалоНенумерованногоСпискаHTML(), ПараметрыОформления) 
		+ Символы.ПС;
	
		Для Каждого ЭлементМассива Из МассивЗначений Цикл
			
			Если ТипЗнч(ЭлементМассива) = Тип("Массив") Тогда
				СформироватьСписокНенумерованныйHTMLРекурсивно(ЭлементМассива, ТекстHTML, ПараметрыОформления);
			Иначе				
				ТекстHTML = ТекстHTML + ЭлементНенумерованногоСпискаHTML(ЭлементМассива) + Символы.ПС;
			КонецЕсли
			
		КонецЦикла;
	
	ТекстHTML = ТекстHTML + "</ul>" + Символы.ПС;
	
КонецПроцедуры

Функция НачалоНенумерованногоСпискаHTML()
	Возврат "<ul style=""margin-left: 10px; padding-left: 10px; list-style-position: inside; font-family: [ТелоШрифт]; font-size: [КонтентРазмерШрифта]; line-height: [КонтентМежстрочныйИнтервал]; color: [КонтентЦветТекста];"">";
КонецФункции

Функция ЭлементНенумерованногоСпискаHTML(ТекстЗаполнения)
	
	
	Шаблон = "<li style=""font-family: [ТелоШрифт]; font-size: [КонтентРазмерШрифта]; line-height: [КонтентМежстрочныйИнтервал]; color: [КонтентЦветТекста];"">
			|	[ТекстЗаполнения]
			|</li>";
	
	НормализованныйТекст = НормализованныйТекстДляHTML(ТекстЗаполнения);
	Возврат СтроковыеФункцииКлиентСервер.ВставитьПараметрыВСтроку(Шаблон, Новый Структура("ТекстЗаполнения", НормализованныйТекст));
	
	
КонецФункции

Функция ТаблицаHTML(СтрокаЗаголовкаТаблицы, ДанныеСтрокТаблицы)
	
	Шаблон = 
	"<p style=""font-size: 5px; line-height: 5px; margin: 0;"">&nbsp;</p>
	|<table width=""[ТаблицаШирина]"" align=""center"" cellpadding=""0"" cellspacing=""0"" border=""0"" style=""margin: [ТаблицаВнешнийОтступ]; border-collapse: collapse;"">
	|	<thead>
	|		[СтрокаЗаголовкаТаблицы]
	|	</thead>
	|	<tbody>
	|		[ДанныеСтрокТаблицы]
	|	</tbody>
	|</table>
	|<p style=""font-size: 5px; line-height: 5px; margin: 0;"">&nbsp;</p>
	|";
	
	ТекстЗаполненияСтрокТаблицы = СтрСоединить(ДанныеСтрокТаблицы, Символы.ПС);
	
	ПараметрыЗаполнения = Новый Структура;
	ПараметрыЗаполнения.Вставить("СтрокаЗаголовкаТаблицы", СтрокаЗаголовкаТаблицы);
	ПараметрыЗаполнения.Вставить("ДанныеСтрокТаблицы", ТекстЗаполненияСтрокТаблицы);
	
	Возврат СтроковыеФункцииКлиентСервер.ВставитьПараметрыВСтроку(Шаблон, ПараметрыЗаполнения);
	
	
КонецФункции

Функция ЗаголовокТаблицыHTML(ДанныеЯчеекЗаголовка)

	Шаблон = "<tr style=""background: [ТаблицаЦветФонаЗаголовка]; color: [ТаблицаЦветТекстаЗаголовка];"">
			|	[ДанныеЯчеекЗаголовкаТаблицы]
			|</tr>";
			
	ДанныеЗаполнения = Новый Структура;
	ДанныеЗаполнения.Вставить("ДанныеЯчеекЗаголовкаТаблицы", СтрСоединить(ДанныеЯчеекЗаголовка, Символы.ПС));
	
	Возврат СтроковыеФункцииКлиентСервер.ВставитьПараметрыВСтроку(Шаблон, ДанныеЗаполнения);
	
КонецФункции

Функция ЯчейкаЗаголовкаТаблицыHTML(ТекстЗаголовка, ШиринаКолонкиПикселей)
	
	ТекстЗаполнения = НормализованныйТекстДляHTML(ТекстЗаголовка);
	
	Шаблон = "<th style=""width: [ШиринаКолонкиПикселей]px; font-family: [ТелоШрифт]; border: [ЯчейкаГраница]; padding: [КонтентВнутреннийОтступ]; font-size: [КонтентРазмерШрифта]; line-height: [КонтентМежстрочныйИнтервал]; text-align: left;"">
			|	[ТекстЗаполнения]
			|</th>";
	
	ПараметрыЗаполнения = Новый Структура;
	ПараметрыЗаполнения.Вставить("ШиринаКолонкиПикселей", Формат(ШиринаКолонкиПикселей, "ЧДЦ=0; ЧГ="));
	ПараметрыЗаполнения.Вставить("ТекстЗаполнения", ТекстЗаполнения);
	
	Возврат СтроковыеФункцииКлиентСервер.ВставитьПараметрыВСтроку(Шаблон, ПараметрыЗаполнения);
	
КонецФункции

Функция СтрокаТаблицыHTML(ДанныеЯчеекСтрокиТаблицы)
	
	Шаблон = "<tr style=""font-family: [ТелоШрифт]; border: [ЯчейкаГраница]; padding: [КонтентВнутреннийОтступ]; font-size: [КонтентРазмерШрифта]; line-height: [КонтентМежстрочныйИнтервал]; color: [КонтентЦветТекста];"">
			|	[ДанныеЯчеекСтрокиТаблицы]
			|</tr>";
	
	ТекстЗаполнения = СтрСоединить(ДанныеЯчеекСтрокиТаблицы, Символы.ПС);
	
	Результат = СтроковыеФункцииКлиентСервер.ВставитьПараметрыВСтроку(Шаблон, Новый Структура("ДанныеЯчеекСтрокиТаблицы", ТекстЗаполнения));
		
	Возврат Результат;
	
КонецФункции

Функция ЯчейкаСтрокиОсновныхДанныхHTML(ТекстЯчейки, ШиринаКолонкиПикселей)

	ТекстЗаполнения = НормализованныйТекстДляHTML(ТекстЯчейки);
	
	Шаблон = "<td style=""width: [ШиринаКолонкиПикселей]px; font-family: [ТелоШрифт]; border: [ЯчейкаГраница]; padding: [КонтентВнутреннийОтступ]; font-size: [КонтентРазмерШрифта]; line-height: [КонтентМежстрочныйИнтервал]; color: [КонтентЦветТекста];"">
			|	[ЗначениеЯчейкиСтрокиТаблицы]
			|</td>";
	ПараметрыЗаполнения = Новый Структура;
	ПараметрыЗаполнения.Вставить("ШиринаКолонкиПикселей", Формат(ШиринаКолонкиПикселей, "ЧДЦ=0; ЧГ="));
	ПараметрыЗаполнения.Вставить("ЗначениеЯчейкиСтрокиТаблицы", ТекстЗаполнения);
	
	Возврат СтроковыеФункцииКлиентСервер.ВставитьПараметрыВСтроку(Шаблон, ПараметрыЗаполнения);
	
КонецФункции

Функция АбсолютнаяШиринаКолонок(ТаблицаЗначений, ОбщаяШирина)

	Колонки = Новый Массив;
	Для Каждого Колонка Из ТаблицаЗначений.Колонки Цикл
		Колонки.Добавить(Новый Структура("Колонка, Ширина", Колонка.Имя, Колонка.Ширина));
	КонецЦикла;

    СуммаЗаданных = 0;
    КоличествоНезаполненных = 0;

    Для Каждого Колонка Из Колонки Цикл
        Если Колонка.Ширина > 0 Тогда
            СуммаЗаданных = СуммаЗаданных + Колонка.Ширина;
        Иначе
            КоличествоНезаполненных = КоличествоНезаполненных + 1;
        КонецЕсли;
    КонецЦикла;
 
    // Шаг 1: нормализация
	
    Если СуммаЗаданных = 0 Тогда
        Для Каждого Колонка Из Колонки Цикл
            Колонка.Вставить("ШиринаПроцентов", Окр(100 / Колонки.Количество(), 0));
        КонецЦикла;

    ИначеЕсли СуммаЗаданных <= 100 Тогда
        Свободно = 100 - СуммаЗаданных;
        Средняя = ?(КоличествоНезаполненных > 0, Свободно / КоличествоНезаполненных, 0);
        Для Каждого Колонка Из Колонки Цикл
            Если Колонка.Ширина = 0 Тогда
                Колонка.Вставить("ШиринаПроцентов", Окр(Средняя, 0));
            Иначе
                Колонка.Вставить("ШиринаПроцентов", Окр(Колонка.Ширина, 0));
            КонецЕсли;
        КонецЦикла;
    Иначе
        // Масштабирование
        Для Каждого Колонка Из Колонки Цикл
            Если Колонка.Ширина > 0 Тогда
                Пропорция = Колонка.Ширина / СуммаЗаданных * 100;
                Колонка.Вставить("ШиринаПроцентов", Окр(Пропорция, 0));
            Иначе
                Колонка.Вставить("ШиринаПроцентов", 0);
            КонецЕсли;
        КонецЦикла;

        // Заполнение оставшихся нулей
        НовыйСумма = 0;
        КоличествоНезаполненных = 0;
        Для Каждого Колонка Из Колонки Цикл
            Если Колонка.ШиринаПроцентов > 0 Тогда
                НовыйСумма = НовыйСумма + Колонка.ШиринаПроцентов;
            Иначе
                КоличествоНезаполненных = КоличествоНезаполненных + 1;
            КонецЕсли;
        КонецЦикла;

        Остаток = 100 - НовыйСумма;
        Средняя = ?(КоличествоНезаполненных > 0, Остаток / КоличествоНезаполненных, 0);
        Для Каждого Колонка Из Колонки Цикл
            Если Колонка.ШиринаПроцентов = 0 Тогда
                Колонка.ШиринаПроцентов = Окр(Средняя, 0);
            КонецЕсли;
        КонецЦикла;
    КонецЕсли;

    // Шаг 2: корректировка процентов

    ОбщаяСумма = 0;
    Для Каждого Колонка Из Колонки Цикл
        ОбщаяСумма = ОбщаяСумма + Колонка.ШиринаПроцентов;
    КонецЦикла;

    Ошибка = 100 - ОбщаяСумма;

    Пока Ошибка <> 0 Цикл
        Для Каждого Колонка Из Колонки Цикл
			Если Ошибка = 0 Тогда 
				Прервать;
			КонецЕсли;
            Изменение = ?(Ошибка > 0, 1, -1);
            Колонка.ШиринаПроцентов = Колонка.ШиринаПроцентов + Изменение;
            Ошибка = Ошибка - Изменение;
        КонецЦикла;
    КонецЦикла;

    // Шаг 3: абсолютная ширина

    ОбщаяПикселей = 0;
    Для Каждого Колонка Из Колонки Цикл
        Пикселей = Окр(ОбщаяШирина * Колонка.ШиринаПроцентов / 100, 0);
        Колонка.Вставить("ШиринаПикселей", Пикселей);
        ОбщаяПикселей = ОбщаяПикселей + Пикселей;
    КонецЦикла;

    // Шаг 4: корректировка до точной ширины
    Остаток = ОбщаяШирина - ОбщаяПикселей;
    Пока Остаток <> 0 Цикл
        Для Каждого Колонка Из Колонки Цикл
			Если Остаток = 0 Тогда 
				Прервать;
			КонецЕсли;
            Изменение = ?(Остаток > 0, 1, -1);
            Колонка.ШиринаПикселей = Колонка.ШиринаПикселей + Изменение;
            Остаток = Остаток - Изменение;
        КонецЦикла;
    КонецЦикла;
	
	Возврат Колонки;
	
КонецФункции

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

#КонецОбласти
```