Автоматическая отправка писем с вложенными файлами (актами сверки, печатными формами документов, отчетами) — одна из наиболее частых задач при интеграции 1С с внешними системами и автоматизации бизнес-процессов. Однако у начинающих разработчиков нередко возникают сложности при попытке прикрепить файлы, которые хранятся внутри базы данных в реквизитах с типом ХранилищеЗначения.
В этой статье мы подробно разберем, как правильно извлекать файлы из базы данных, передавать их в почтовое сообщение в виде двоичных данных или через временные файлы, а также рассмотрим критически важные настройки безопасности для современных почтовых серверов.
Основная ошибка при работе со встроенными файлами в 1С заключается в попытке передать сам объект ХранилищеЗначения непосредственно во вложение почтового сообщения. Объект ХранилищеЗначения — это лишь системная «обертка», сжатая платформа для хранения информации в базе данных. Чтобы получить реальные данные файла, эту обертку необходимо предварительно раскрыть.
Выясним причину проблемы на примере кода. Для извлечения информации мы должны использовать метод Получить() объекта ХранилищеЗначения. В результате выполнения этого метода мы получаем объект типа ДвоичныеДанные. Рассмотрим правильный способ извлечения данных из базы с помощью запроса на сервере:
&НаСервере
Функция ПолучитьДанныеФайлаИзБазы(СсылкаНаФайл)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Файлы.ИмяКП1 КАК ИмяФайла,
| Файлы.Файл КАК ХранилищеФайла
|ИЗ
| Справочник.Файлы КАК Файлы
|ГДЕ
| Файлы.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", СсылкаНаФайл);
РезультатЗапроса = Запрос.Выполнить();
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
СтруктураРезультата = Новый Структура("ИмяФайла, ДвоичныеДанные", "", Неопределено);
Если ВыборкаДетальныеЗаписи.Следующий() Тогда
СтруктураРезультата.ИмяФайла = ВыборкаДетальныеЗаписи.ИмяФайла;
// Получаем объект ХранилищеЗначения из выборки
ТекущееХранилище = ВыборкаДетальныеЗаписи.ХранилищеФайла;
Если ТипЗнч(ТекущееХранилище) = Тип("ХранилищеЗначения") Тогда
// Извлекаем непосредственно ДвоичныеДанные файла
СтруктураРезультата.ДвоичныеДанные = ТекущееХранилище.Получить();
КонецЕсли;
КонецЕсли;
Возврат СтруктураРезультата;
КонецФункции
Обратите внимание, что оборачивать извлеченные двоичные данные в объект Картинка (как иногда ошибочно делают разработчики при работе с изображениями) не требуется. Объект ИнтернетПочтовоеСообщение умеет напрямую работать с чистыми двоичными данными любых типов файлов: текстовых документов, PDF, Excel или архивов.
Рассмотрим подробнее синтаксис метода добавления вложений. Метод СообщениеПочты.Вложения.Добавить() крайне гибок и поддерживает два основных сценария работы:
ДвоичныеДанные вторым параметром, а первым — желаемое имя файла для отображения у получателя.Проанализируем пример кода для первого способа (наиболее быстрого и современного):
// Прямое добавление двоичных данных во вложение
СообщениеПочты = Новый ИнтернетПочтовоеСообщение;
СообщениеПочты.Тема = "Отправка вложенного файла";
СообщениеПочты.Получатели.Добавить("recipient@example.com");
// Добавляем вложение напрямую из оперативной памяти
СообщениеПочты.Вложения.Добавить(ДанныеФайла.ДвоичныеДанные, ДанныеФайла.ИмяФайла);
Если же файлы имеют внушительный объем, разберем по шагам безопасный алгоритм записи во временный каталог сервера с последующей отправкой и обязательной очисткой дискового пространства:
// Использование временного файла для тяжелых вложений
ИмяВременногоКаталога = КаталогВременныхФайлов();
ПолныйПутьКФайлу = ИмяВременногоКаталога + ДанныеФайла.ИмяФайла;
// Записываем двоичные данные на диск сервера
ДанныеФайла.ДвоичныеДанные.Записать(ПолныйПутьКФайлу);
СообщениеПочты = Новый ИнтернетПочтовоеСообщение;
СообщениеПочты.Вложения.Добавить(ПолныйПутьКФайлу, ДанныеФайла.ИмяФайла);
// Выполняем отправку почты...
// [Код отправки]
// Обязательно удаляем временный файл после закрытия почтового сеанса
Попытка
УдалитьФайлы(ПолныйПутьКФайлу);
Исключение
ЗаписьЖурналаРегистрации("ОтправкаПочты.ОшибкаУдаленияФайла",
УровеньЖурналаРегистрации.Предупреждение, , ,
ОписаниеОшибки());
КонецПопытки;
Даже написав идеальный код для работы с вложениями, вы гарантированно столкнетесь с ошибками аутентификации или блокировки со стороны современных почтовых серверов, если будете использовать старые незащищенные параметры подключения.
Проанализируем ключевые требования современных почтовых систем к безопасности внешних приложений:
ПарольSMTP.Посмотрим на пример правильного заполнения объекта ИнтернетПочтовыйПрофиль для работы с сервисом Яндекс.Почта:
Профиль = Новый ИнтернетПочтовыйПрофиль;
Профиль.АдресСервераSMTP = "smtp.yandex.ru";
Профиль.ПортSMTP = 465;
Профиль.ИспользоватьSSLSMTP = Истина; // Обязательное использование защищенного соединения
Профиль.АутентификацияSMTP = СпособSMTPАутентификации.Login;
Профиль.ПользовательSMTP = "my_mailbox@yandex.ru";
// Вместо реального пароля указываем сгенерированный пароль приложения
Профиль.ПарольSMTP = "abcd-efgh-ijkl-mnop";
Профиль.ВремяОжидания = 30; // Увеличиваем таймаут для работы с вложениями
Сетевые операции отправки почты критически зависимы от стабильности интернет-соединения, корректности работы локального DNS-сервера и настроек брандмауэра операционной системы. Поэтому весь блок взаимодействия с почтовым сервером необходимо оборачивать в конструкцию контроля ошибок Попытка...Исключение.
Объединим все наши наработки в единую надежную серверную процедуру:
&НаСервере
Процедура ОтправитьПисьмоСВложениемНаСервере(СсылкаНаФайл, АдресПолучателя, ТемаПисьма, ТекстПисьма)
// 1. Получаем данные файла из базы
ДанныеФайла = ПолучитьДанныеФайлаИзБазы(СсылкаНаФайл);
Если ДанныеФайла.ДвоичныеДанные = Неопределено Тогда
ВызватьИсключение "Не удалось получить двоичные данные файла из справочника.";
КонецЕсли;
// 2. Настраиваем профиль подключения
Профиль = Новый ИнтернетПочтовыйПрофиль;
Профиль.АдресСервераSMTP = "smtp.yandex.ru";
Профиль.ПортSMTP = 465;
Профиль.ИспользоватьSSLSMTP = Истина;
Профиль.АутентификацияSMTP = СпособSMTPАутентификации.Login;
Профиль.ПользовательSMTP = "my_mailbox@yandex.ru";
Профиль.ПарольSMTP = "abcd-efgh-ijkl-mnop";
Профиль.ВремяОжидания = 60;
// 3. Формируем сообщение
Сообщение = Новый ИнтернетПочтовоеСообщение;
Сообщение.Отправитель.Адрес = "my_mailbox@yandex.ru";
Сообщение.Отправитель.ОтображаемоеИмя = "Робот 1С";
Сообщение.Получатели.Добавить(АдресПолучателя);
Сообщение.Тема = ТемаПисьма;
Сообщение.Тексты.Добавить(ТекстПисьма, ТипТекстаПочтовогоСообщения.ПростойТекст);
// Добавляем вложение напрямую из оперативной памяти как двоичные данные
Сообщение.Вложения.Добавить(ДанныеФайла.ДвоичныеДанные, ДанныеФайла.ИмяФайла);
// 4. Подключаемся и отправляем
Почта = Новый ИнтернетПочта;
Попытка
Почта.Подключиться(Профиль);
Почта.Послать(Сообщение);
Почта.Отключиться();
Сообщить("Письмо успешно отправлено адресату " + АдресПолучателя);
Исключение
// Логируем ошибку и отключаем сессию в случае сбоя во время отправки
Если Почта.Подключено() Тогда
Почта.Отключиться();
КонецЕсли;
ЗаписьЖурналаРегистрации("ОтправкаПочты.ОшибкаОтправки",
УровеньЖурналаРегистрации.Ошибка, , ,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
ВызватьИсключение "Не удалось отправить почтовое сообщение. Подробности смотрите в Журнале регистрации.";
КонецПопытки;
КонецПроцедуры
Если вы ведете разработку в современных типовых конфигурациях (таких как «1С:ERP», «1С:Комплексная автоматизация», «1С:Управление торговлей» или «1С:Бухгалтерия»), то писать низкоуровневый код работы с протоколом SMTP вручную не рекомендуется. Платформа 1С содержит встроенную подсистему работы с почтой в составе БСП.
Использование БСП значительно сокращает трудозатраты разработчика, берет на себя всю рутину по обработке ошибок, ведению логов и позволяет отправлять письма асинхронно в фоновом режиме через настроенную в интерфейсе учетную запись электронной почты.
Рассмотрим, как выглядит отправка письма с вложением через программный интерфейс БСП:
// Пример отправки письма средствами БСП
ПараметрыПисьма = Новый Структура;
ПараметрыПисьма.Вставить("Кому", "recipient@example.com");
ПараметрыПисьма.Вставить("Тема", "Документы по сделке");
ПараметрыПисьма.Вставить("Тело", "Добрый день! Во вложении файлы документов.");
// Подготавливаем массив вложений в формате БСП
МассивВложений = Новый Массив;
СтруктураВложения = Новый Структура;
СтруктураВложения.Вставить("Наименование", ДанныеФайла.ИмяФайла);
СтруктураВложения.Вставить("Данные", ДанныеФайла.ДвоичныеДанные); // Передаем ДвоичныеДанные
МассивВложений.Добавить(СтруктураВложения);
ПараметрыПисьма.Вставить("Вложения", МассивВложений);
// Получаем системную или предопределенную учетную запись почты в ИБ
УчетнаяЗапись = Справочники.УчетныеЗаписиЭлектроннойПочты.СистемнаяУчетнаяЗаписьЭлектроннойПочты;
// Вызываем стандартный метод отправки БСП
РаботаСПочтовымиСообщениями.ОтправитьПочтовоеСообщение(УчетнаяЗапись, ПараметрыПисьма);
Использование БСП является наиболее надежным, отказоустойчивым и предпочтительным методом разработки в современной экосистеме решений «1С:Предприятие 8».