Отправка электронных писем с вложениями – это обыденная задача в работе информационных систем. Однако в среде 1С:Предприятие, особенно при работе в клиент-серверном режиме и использовании типовых механизмов, таких как модуль РаботаСПочтовымиСообщениями, могут возникнуть сложности. Давайте разберем, как правильно сформировать параметры письма с вложениями, когда файл находится на локальном диске пользователя, а отправка происходит на сервере.
Основная сложность заключается в том, что сервер 1С не имеет прямого доступа к локальным файлам клиентской машины. Следовательно, для передачи файла с клиента на сервер, чтобы он мог быть использован в качестве вложения, необходимо сначала поместить его во временное хранилище 1С. После этого адрес файла во временном хранилище уже можно передавать серверной части для формирования почтового сообщения.
Прежде чем мы перейдем к формированию параметров письма, важно понять механизм работы с файлами в клиент-серверной архитектуре 1С. Если ваш код, который читает файл (например, Новый ДвоичныеДанные(ПутьКФайлу)), выполняется на клиенте, а код отправки письма – на сервере, то путь к файлу на клиенте (например, "D:\test\test.txt") будет для сервера недоступен. Для преодоления этой ситуации мы используем механизм временного хранилища:
ДвоичныеДанные.ДвоичныеДанные помещаются во временное хранилище с помощью функции ПоместитьВоВременноеХранилище(). Эта функция возвращает уникальный адрес, по которому эти данные доступны уже на сервере.Функция ПоместитьВоВременноеХранилище(Значение, УникальныйИдентификатор) позволяет сохранить двоичные данные или другой сериализуемый объект в специальном хранилище. Параметр УникальныйИдентификатор часто используется для привязки данных к конкретной форме, чтобы они автоматически удалялись при ее закрытии, тем самым управляя потреблением памяти. Если идентификатор не указан, данные могут быть удалены при следующем серверном вызове, поэтому лучше указывать его для контроля жизненного цикла данных.
РаботаСПочтовымиСообщениями.ОтправитьПочтовоеСообщение с параметрамиЭто наиболее распространенный и рекомендуемый способ, использующий стандартную библиотеку подсистем (БСП) в 1С. Мы будем формировать структуру ПараметрыПисьма, в которую будем передавать все необходимые данные, включая информацию о вложениях.
Предположим, у нас есть полный путь к файлу на диске пользователя (например, D:\test\test.txt), и нам нужно его отправить. Если этот путь формируется на клиенте, то и получение двоичных данных должно происходить на клиенте.
// Пусть ПутьКФайлу - это полный путь к файлу на диске клиента
// Например: "D:\test\test.txt"
// Этот код должен выполняться на клиенте
ПереданныйПутьКФайлу = "D:\test\test.txt";
ИмяФайла = "test.txt"; // Имя, которое будет отображаться получателю
// Проверяем существование файла, если это необходимо
Если Не ФайлСуществует(ПереданныйПутьКФайлу) Тогда
Сообщить("Файл по указанному пути не найден: " + ПереданныйПутьКФайлу);
Возврат;
КонецЕсли;
// Создаем объект ДвоичныеДанные из файла
ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ПереданныйПутьКФайлу);
Теперь, когда у нас есть ДвоичныеДанные файла, нам необходимо поместить их во временное хранилище, чтобы сервер мог к ним обратиться. Этот шаг также выполняется на клиенте, если ДвоичныеДанныеФайла получены на клиенте. В качестве второго параметра УникальныйИдентификаторТекущейФормы можно использовать, например, УникальныйИдентификатор текущей формы для управления жизненным циклом данных.
// Помещаем двоичные данные файла во временное хранилище
// УникальныйИдентификаторТекущейФормы - это идентификатор формы, которая вызывает отправку письма.
// Это позволяет платформе автоматически очищать временное хранилище при закрытии формы.
АдресВоВременномХранилище = ПоместитьВоВременноеХранилище(ДвоичныеДанныеФайла, УникальныйИдентификаторТекущейФормы);
Каждое вложение в массиве Вложения внутри ПараметрыПисьма должно быть представлено структурой. Эта структура должна содержать как минимум два поля: Представление (имя файла для отображения получателю) и АдресВоВременномХранилище (полученный на предыдущем шаге).
// Создаем структуру для описания одного вложения
ОписаниеВложения = Новый Структура;
ОписаниеВложения.Вставить("Представление", ИмяФайла); // Имя файла, которое увидит получатель
ОписаниеВложения.Вставить("АдресВоВременномХранилище", АдресВоВременномХранилище);
Если у вас несколько вложений, каждое из них формируется по шагам 1-3 и добавляется в массив Вложения. Если вложение одно, то массив будет состоять из одной такой структуры.
// Создаем массив для всех вложений
МассивВложений = Новый Массив;
МассивВложений.Добавить(ОписаниеВложения); // Добавляем наше вложение
ПараметрыПисьмаТеперь мы собираем все данные для письма в единую структуру ПараметрыПисьма. Обязательные поля включают Кому, Тему, Тело и, конечно же, наш массив Вложения.
// Создаем общую структуру параметров письма
ПараметрыПисьма = Новый Структура;
// Заполняем основные поля письма
ПараметрыПисьма.Вставить("Кому", "recipient@example.com"); // Адресат (можно передать Массив адресов или строку)
// Для нескольких адресатов 'Кому' может быть массивом структур с полями 'Адрес' и 'Представление'
// Например:
// Получатели = Новый Массив;
// Получатели.Добавить(Новый Структура("Адрес, Представление", "recipient1@example.com", "Иван Иванов"));
// Получатели.Добавить(Новый Структура("Адрес, Представление", "recipient2@example.com", "Петр Петров"));
// ПараметрыПисьма.Вставить("Кому", Получатели);
ПараметрыПисьма.Вставить("Тема", "Письмо с вложением из 1С");
ПараметрыПисьма.Вставить("Тело", "Здравствуйте! Во вложении вы найдете запрошенный файл.");
ПараметрыПисьма.Вставить("ТипТекста", "ПростойТекст"); // Или "HTML" для HTML-формата
// Учетная запись отправителя (должна быть предварительно настроена в 1С)
УчетнаяЗаписьПочты = РаботаСПочтовымиСообщениями.СистемнаяУчетнаяЗапись; // Или другая конкретная учетная запись
ПараметрыПисьма.Вставить("УчетнаяЗапись", УчетнаяЗаписьПочты);
// Добавляем наш массив вложений в параметры письма
ПараметрыПисьма.Вставить("Вложения", МассивВложений);
// Можно добавить другие параметры, например:
// ПараметрыПисьма.Вставить("Копии", "copy@example.com");
// ПараметрыПисьма.Вставить("СкрытыеКопии", "bcc@example.com");
// ПараметрыПисьма.Вставить("АдресОтвета", "replyto@example.com");
// ПараметрыПисьма.Вставить("Важность", "Высокая");
После того как все параметры сформированы, мы вызываем экспортную процедуру РаботаСПочтовымиСообщениями.ОтправитьПочтовоеСообщение(), передавая ей учетную запись и параметры письма.
Попытка
РаботаСПочтовымиСообщениями.ОтправитьПочтовоеСообщение(УчетнаяЗаписьПочты, ПараметрыПисьма);
Сообщить("Письмо успешно отправлено!");
Исключение
Сообщить("Ошибка при отправке письма: " + ОписаниеОшибки());
КонецПопытки;
Таким образом, полный пример формирования и отправки письма с вложением из локального файла клиента будет выглядеть следующим образом:
// Пример из сообщения 13, адаптированный
Процедура ОтправитьПисьмоСФайлом(ПутьКФайлу, ИмяФайлаДляВложения, УникальныйИдентификаторТекущейФормы) Экспорт
// 1. Проверяем существование файла и получаем ДвоичныеДанные
Если Не ФайлСуществует(ПутьКФайлу) Тогда
Сообщить("Файл по указанному пути не найден: " + ПутьКФайлу);
Возврат;
КонецЕсли;
ДвоичныеДанные = Новый ДвоичныеДанные(ПутьКФайлу);
// 2. Помещаем ДвоичныеДанные во временное хранилище
// Это должно быть сделано на клиенте, если ПутьКФайлу - клиентский
АдресВоВременномХранилище = ПоместитьВоВременноеХранилище(ДвоичныеДанные, УникальныйИдентификаторТекущейФормы);
// 3. Формируем массив вложений
Вложения = Новый Массив;
Вложение = Новый Структура("Представление, АдресВоВременномХранилище");
Вложение["Представление"] = ИмяФайлаДляВложения;
Вложение["АдресВоВременномХранилище"] = АдресВоВременномХранилище;
Вложения.Добавить(Вложение);
// 4. Определяем получателей
Получатели = Новый Массив;
Получатели.Добавить(Новый Структура("Адрес, Представление", "recipient@example.com", "Иван Иванов"));
// 5. Определяем учетную запись
// Можно получить системную, или конкретную из справочника "УчетныеЗаписиЭлектроннойПочты"
УчетнаяЗаписьПочты = РаботаСПочтовымиСообщениями.СистемнаяУчетнаяЗапись;
Если УчетнаяЗаписьПочты = Неопределено Тогда
Сообщить("Не удалось получить системную учетную запись электронной почты.");
Возврат;
КонецЕсли;
// 6. Формируем структуру ПараметрыПисьма
ТекстПисьма = "Уважаемые коллеги, во вложении находится запрошенный документ.";
ПараметрыПисьма = Новый Структура;
ПараметрыПисьма.Вставить("УчетнаяЗапись", УчетнаяЗаписьПочты);
ПараметрыПисьма.Вставить("Кому", Получатели);
ПараметрыПисьма.Вставить("Тема", "Отчет по продажам");
ПараметрыПисьма.Вставить("Тело", ТекстПисьма);
ПараметрыПисьма.Вставить("ТипТекста", "ПростойТекст");
ПараметрыПисьма.Вставить("Вложения", Вложения);
// 7. Отправляем почтовое сообщение
Попытка
РаботаСПочтовымиСообщениями.ОтправитьПочтовоеСообщение(УчетнаяЗаписьПочты, ПараметрыПисьма);
Сообщить("Письмо с вложением '" + ИмяФайлаДляВложения + "' успешно отправлено!");
Исключение
Сообщить("Ошибка при отправке письма: " + ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
РаботаСПочтовымиСообщениями.ОтправитьСообщение (для УТ 11.0)В некоторых конфигурациях, например, как было отмечено в УТ 11.0, структура для вложений в ПараметрыПисьма может отличаться. Вместо массива структур, где каждая структура описывает вложение через Представление и АдресВоВременномХранилище, может использоваться Соответствие. В этом случае ключом соответствия является Представление (имя файла), а значением — структура, содержащая непосредственно ДвоичныеДанные файла (полученные из временного хранилища) и, возможно, Идентификатор для внутреннего использования.
Разберем этот вариант подробнее:
АдресВоВременномХранилище для каждого файла на клиенте.ДвоичныеДанные из временного хранилища по его адресу с помощью функции ПолучитьИзВременногоХранилища().ДвоичныеДанные и, при необходимости, Идентификатор.Вложения в ПараметрыПисьма будет Новый Соответствие. Ключом в этом соответствии будет Представление файла, а значением — сформированная структура с ДвоичнымиДанными.Посмотрим на пример из типовой конфигурации УТ 11.0:
// Пример из сообщения 14, адаптированный
Процедура ОтправитьПисьмоСФайлом_УТ11(СписокПутейКФайлам, УчетнаяЗаписьПочты, УникальныйИдентификаторТекущейФормы) Экспорт
// Предполагается, что СписокПутейКФайлам - это Массив строк,
// где каждая строка - полный путь к файлу на клиенте.
// Будем собирать временные адреса
ВременныеАдресаФайлов = Новый Соответствие; // Ключ: ИмяФайла, Значение: АдресВоВременномХранилище
Для Каждого ПутьКФайлу Из СписокПутейКФайлам Цикл
Если Не ФайлСуществует(ПутьКФайлу) Тогда
Сообщить("Файл не найден: " + ПутьКФайлу);
Продолжить;
КонецЕсли;
ИмяФайла = ИмяФайла(ПутьКФайлу);
ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ПутьКФайлу);
АдресВХранилище = ПоместитьВоВременноеХранилище(ДвоичныеДанныеФайла, УникальныйИдентификаторТекущейФормы);
ВременныеАдресаФайлов.Вставить(ИмяФайла, АдресВХранилище);
КонецЦикла;
// Проверяем, есть ли что отправлять
Если ВременныеАдресаФайлов.Количество() = 0 Тогда
Сообщить("Нет файлов для отправки.");
Возврат;
КонецЕсли;
// Формируем параметры письма
ПараметрыПисьма = Новый Структура;
ПараметрыПисьма.Вставить("Тема", "Документы из УТ 11");
ПараметрыПисьма.Вставить("Тело", "Уважаемые партнеры, высылаем запрошенные документы.");
ПараметрыПисьма.Вставить("ТипТекста", "ПростойТекст");
ПараметрыПисьма.Вставить("УчетнаяЗапись", УчетнаяЗаписьПочты);
// Формируем Вложения как Соответствие
ВложенияСоответствие = Новый Соответствие;
Для Каждого Элемент Из ВременныеАдресаФайлов Цикл
ПредставлениеФайла = Элемент.Ключ; // Имя файла
АдресИзХранилища = Элемент.Значение;
// Получаем ДвоичныеДанные обратно из временного хранилища на сервере
ДвоичныеДанныеВложения = ПолучитьИзВременногоХранилища(АдресИзХранилища);
Если ДвоичныеДанныеВложения = Неопределено Тогда
Сообщить("Не удалось получить двоичные данные для файла " + ПредставлениеФайла + " из временного хранилища.");
Продолжить;
КонецЕсли;
// Формируем структуру для текущего вложения
НовоеВложениеСтруктура = Новый Структура("ДвоичныеДанные, Идентификатор");
НовоеВложениеСтруктура.ДвоичныеДанные = ДвоичныеДанныеВложения;
// Идентификатор используется, например, для встраивания изображений в HTML тело письма
НовоеВложениеСтруктура.Идентификатор = "Вложение_" + СтрЗаменить(ПредставлениеФайла, ".", "_");
// Добавляем в Соответствие
ВложенияСоответствие.Вставить(ПредставлениеФайла, НовоеВложениеСтруктура);
КонецЦикла;
ПараметрыПисьма.Вставить("Вложения", ВложенияСоответствие);
// Определяем получателей
Получатели = Новый Массив;
Получатели.Добавить(Новый Структура("Адрес, Представление", "recipient@example.com", "Получатель УТ"));
ПараметрыПисьма.Вставить("Кому", Получатели);
// Отправляем почтовое сообщение
Попытка
РаботаСПочтовымиСообщениями.ОтправитьПочтовоеСообщение(УчетнаяЗаписьПочты, ПараметрыПисьма);
Сообщить("Письмо успешно отправлено (вариант для УТ 11)!");
Исключение
Сообщить("Ошибка при отправке письма (вариант для УТ 11): " + ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
Обратите внимание, что в этом варианте ДвоичныеДанные для вложения помещаются напрямую в структуру соответствия, а не АдресВоВременномХранилище. Это означает, что ПолучитьИзВременногоХранилища() вызывается явным образом на сервере для каждого вложения.
ИнтернетПочтовоеСообщение совместно с РаботаСПочтовымиСообщениямиХотя автор вопроса изначально хотел избежать прямого использования объектов ИнтернетПочта и ИнтернетПочтовоеСообщение, предпочитая работу с параметрами, типовой модуль РаботаСПочтовымиСообщениями часто предоставляет процедуры, которые принимают уже сформированный объект ИнтернетПочтовоеСообщение. Это может быть полезно, если вам требуется более тонкая настройка письма, чем позволяет структура ПараметрыПисьма.
Рассмотрим, как это реализовано в примере из типовой конфигурации УНФ:
ИнтернетПочтовоеСообщение.Тема, Получатели, Тексты.Письмо.Вложения. Метод Добавить() этой коллекции позволяет добавить файл, указывая его двоичные данные (или путь к файлу на сервере) и имя представления. Поскольку файл опять же находится во временном хранилище, мы используем ПолучитьИзВременногоХранилища().РаботаСПочтовымиСообщениями.ОтправитьПисьмо(УчетнаяЗапись, Письмо), который принимает уже готовое почтовое сообщение и учетную запись.Посмотрим на пример:
// Пример из сообщения 2, адаптированный
Процедура ОтправитьПисьмоСФайлом_ЧерезОбъект(ПутьКФайлуНаКлиенте, ИмяФайлаДляВложения, ПолучательEmail, УникальныйИдентификаторТекущейФормы) Экспорт
Попытка
// 1. Получаем двоичные данные файла и помещаем во временное хранилище (на клиенте)
Если Не ФайлСуществует(ПутьКФайлуНаКлиенте) Тогда
Сообщить("Файл не найден: " + ПутьКФайлуНаКлиенте);
Возврат;
КонецЕсли;
ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ПутьКФайлуНаКлиенте);
АдресВХранилище = ПоместитьВоВременноеХранилище(ДвоичныеДанныеФайла, УникальныйИдентификаторТекущейФормы);
// 2. Создаем объект ИнтернетПочтовоеСообщение (на сервере)
Письмо = Новый ИнтернетПочтовоеСообщение;
Письмо.Тема = "Справка из 1С УНФ";
Письмо.Тексты.Добавить("Здравствуйте! Во вложении вы найдете запрошенную справку.");
// 3. Добавляем получателей
Письмо.Получатели.Добавить(ПолучательEmail);
// 4. Добавляем вложение из временного хранилища
// Получаем двоичные данные из временного хранилища на сервере
ДвоичныеДанныеВложения = ПолучитьИзВременногоХранилища(АдресВХранилище);
Если ДвоичныеДанныеВложения = Неопределено Тогда
Сообщить("Не удалось получить двоичные данные для вложения из временного хранилища.");
Возврат;
КонецЕсли;
// Добавляем вложение в письмо
Письмо.Вложения.Добавить(ДвоичныеДанныеВложения, ИмяФайлаДляВложения);
// 5. Получаем учетную запись
УчетнаяЗапись = РаботаСПочтовымиСообщениями.СистемнаяУчетнаяЗапись;
Если УчетнаяЗапись = Неопределено Тогда
Сообщить("Не удалось получить системную учетную запись электронной почты.");
Возврат;
КонецЕсли;
// 6. Отправляем письмо с помощью типового механизма
РаботаСПочтовымиСообщениями.ОтправитьПисьмо(УчетнаяЗапись, Письмо);
Сообщить("Копия справки успешно отправлена на почту " + ПолучательEmail);
Исключение
Сообщить("Не удалось автоматически отправить копию справки на почту: " + ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
Этот метод также является вполне типовым и часто используется в БСП, предоставляя гибкость в формировании самого почтового сообщения через объект ИнтернетПочтовоеСообщение.
Попытка...Исключение при работе с почтой. Это позволит корректно реагировать на проблемы с подключением, неверные учетные данные, ошибки сервера или другие непредвиденные ситуации.УчетнаяЗапись электронной почты корректно настроена в справочнике "Учетные записи электронной почты" вашей конфигурации и имеет необходимые права для отправки почты. Часто используется РаботаСПочтовымиСообщениями.СистемнаяУчетнаяЗапись, но можно получить любую другую по ее наименованию или другим параметрам.ТипТекста ("ПростойТекст" или "HTML") в зависимости от содержимого вашего письма. Для форматированного текста используйте "HTML".Представления для вложения или имени файла для метода Вложения.Добавить(), используйте осмысленные имена, чтобы получателю было понятно, что за файл он получает.УникальныйИдентификаторТекущейФормы при вызове ПоместитьВоВременноеХранилище(), то после закрытия формы данные будут автоматически удалены. Если такой привязки нет, данные могут оставаться в хранилище дольше, потенциально занимая место.D:\test\test.txt).Разбирая эти методы, мы видим, что ключевым моментом для успешной отправки вложений из клиентского файла в 1С является правильное использование временного хранилища для передачи данных между клиентом и сервером. Выбор конкретного метода отправки (через структуру ПараметрыПисьма или объект ИнтернетПочтовоеСообщение) будет зависеть от ваших предпочтений и специфики конфигурации, но принципы работы с вложениями остаются схожими.