При реализации автоматической рассылки отчетов, расчетных листков или табелей учета рабочего времени разработчики часто сталкиваются с задачей формирования файлов во временном каталоге. Чтобы избежать конфликтов доступа и блокировок при одновременной работе нескольких пользователей или фоновых заданий, файл сохраняется на диск с помощью функции ПолучитьИмяВременногоФайла. В результате получается физический файл со случайным системным именем, например v8_AFE0_ef.xlsx.
Для конечного получателя такое название в письме выглядит неинформативно. Логично передать во второй параметр метода Добавить коллекции вложений понятное человеку наименование, например «Транспортный цех.xlsx». Однако на практике почтовые клиенты (Outlook, Thunderbird, веб-интерфейсы Яндекс, Mail.ru, Gmail) продолжают отображать исходное имя временного файла. Разберем, почему это происходит и как правильно передавать вложения с нужным именем.
Выясним причину такого поведения на уровне почтовых протоколов и формирования заголовков MIME-сообщения:
Сообщение.Вложения.Добавить(ПутьКФайлу, "ИмяДляПользователя") путь к файлу на диске, платформа 1С записывает переданную строку во внутренний заголовок Content-Type: ...; name="...", а реальное имя файла с жесткого диска помещает в служебный заголовок Content-Disposition: attachment; filename="...".filename из заголовка Content-Disposition, полностью игнорируя параметр name из Content-Type. В результате адресат видит имя сгенерированного временного файла v8_AFE0_ef.xlsx.ИмяФайла объекта ИнтернетПочтовоеВложение при добавлении файла с диска доступно только для чтения, поэтому изменить его напрямую после добавления невозможно.Для того чтобы обойти разделение имен между заголовками, необходимо исключить передачу дискового пути в почтовое сообщение. Если вместо строкового пути передать объект ДвоичныеДанные, у платформы не будет информации о физическом файле на диске. В этом случае 1С использует строку из второго параметра для заполнения обоих MIME-заголовков.
Посмотрим на пример правильного формирования вложения:
// Создаем временный файл отчета
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xlsx");
ТабличныйДокумент.Записать(ИмяВременногоФайла, ТипФайлаТабличногоДокумента.XLSX);
// Читаем файл в двоичные данные
ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ИмяВременногоФайла);
// Формируем почтовое сообщение
Сообщение = Новый ИнтернетПочтовоеСообщение;
Сообщение.Отправитель = Отправитель;
Сообщение.ИмяОтправителя = "Роботизированная рассылка";
Сообщение.Получатели.Добавить(ЭлектроннаяПочтаПолучателя);
Сообщение.Тема = "Табель учета рабочего времени";
// Важно: передаем двоичные данные и желаемое имя с расширением
ИмяДляПолучателя = "Транспортный цех.xlsx";
Вложение = Сообщение.Вложения.Добавить(ДвоичныеДанныеФайла, ИмяДляПолучателя);
// При необходимости указываем кодировку для корректного отображения кириллицы
Вложение.Кодировка = "utf-8";
// Отправляем письмо через установленное почтовое соединение
ПочтовоеСоединение.Послать(Сообщение);
// Удаляем временный файл с диска
УдалитьФайлы(ИмяВременногоФайла);
При использовании этого метода обратим внимание на обязательные технические детали:
Добавить необходимо обязательно указывать расширение файла (например, .xlsx или .pdf). Если передать просто строку "Транспортный цех", почтовый клиент не сможет определить тип файла и сохранит его без расширения либо назначит системное расширение по умолчанию (.bin, .dat). В результате пользователь не сможет открыть файл двойным кликом.\ / : * ? " < > |.Вложение.Кодировка = "utf-8";.Если табличный документ формируется программно, можно вообще отказаться от использования временных файлов на диске. Платформа 1С позволяет записать результат в поток памяти и сразу получить двоичные данные. Это ускоряет работу, снижает нагрузку на дисковую подсистему сервера и исключает проблемы с очисткой временных файлов при аварийном завершении регламентных заданий.
Разберем реализацию через работу с потоками:
// Записываем табличный документ напрямую в поток памяти
ПотокВПамяти = Новый ПотокВПамяти;
ТабличныйДокумент.Записать(ПотокВПамяти, ТипФайлаТабличногоДокумента.XLSX);
// Извлекаем двоичные данные из закрытого потока
ДвоичныеДанныеОтчета = ПотокВПамяти.ЗакрытьИПолучитьДвоичныеДанные();
// Добавляем вложение в сообщение
ИмяФайлаВложения = "Табель_Транспортный_цех.xlsx";
Сообщение.Вложения.Добавить(ДвоичныеДанныеОтчета, ИмяФайлаВложения);
Если конфигурация разработана на основе «1С:Библиотеки стандартных подсистем» (БСП), ручную работу с объектами ИнтернетПочта и ИнтернетПочтовоеСообщение лучше заменить на вызовы штатных методов общего модуля РаботаСЭлектроннойПочтой. Механизмы БСП автоматически корректно формируют почтовые заголовки, упаковывают вложения и контролируют кодировки.
Посмотрим на пример отправки через подсистему БСП:
ПараметрыПисьма = Новый Структура;
ПараметрыПисьма.Вставить("Кому", АдресПолучателя);
ПараметрыПисьма.Вставить("Тема", "Табель учета рабочего времени");
ПараметрыПисьма.Вставить("Тело", "Добрый день! Во вложении табель подразделения.");
// Формируем список вложений
Вложения = Новый Массив;
ОписаниеВложения = Новый Структура;
ОписаниеВложения.Вставить("Представление", "Транспортный цех.xlsx");
ОписаниеВложения.Вставить("Данные", ДвоичныеДанныеФайла);
Вложения.Добавить(ОписаниеВложения);
ПараметрыПисьма.Вставить("Вложения", Вложения);
// Отправляем письмо через системную или пользовательскую учетную запись
РаботаСЭлектроннойПочтой.ОтправитьПисьмо(УчетнаяЗапись, ПараметрыПисьма);
Такой подход обеспечивает полную кроссплатформенную совместимость и избавляет от необходимости вручную настраивать параметры MIME-сообщений.