Почему при отправке почты из 1С вложение (PDF) приходит пустым и как это исправить?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В практике разработки на платформе 1С:Предприятие 8 часто возникает задача автоматической рассылки печатных форм (счетов, актов, отчетов) по электронной почте. Одной из самых коварных проблем является ситуация, когда само письмо доходит до адресата, вложение в нем присутствует, но при попытке открытия документ оказывается абсолютно пустым (размером 0 байт или с пустыми страницами). Особенно часто это проявляется при выполнении кода на стороне сервера или в рамках регламентного задания.

В данной статье мы подробно разберем, почему так происходит, проанализируем типичные ошибки в коде и рассмотрим несколько надежных способов гарантированной доставки корректных PDF-файлов.

Анализ исходной ситуации

Рассмотрим типичный фрагмент кода, который часто становится источником проблем. Разработчик формирует табличный документ, сохраняет его во временный файл и пытается прикрепить этот файл к письму, используя путь к нему.


// Формируем печатную форму
Таб = СформироватьПечатнуюФормуАктСДаннымиКонтрагента(Док.Ссылка, ОбъектыПечати, Ложь); 

// Получаем путь к временному файлу
ВремФайл = ПолучитьИмяВременногоФайла("pdf"); 

// Сохраняем табличный документ на диск сервера
Таб.Записать(ВремФайл, ТипФайлаТабличногоДокумента.PDF); 

// Настройка почтового профиля
Профиль = Новый ИнтернетПочтовыйПрофиль;
Профиль.АдресСервераSMTP = "smtp.yandex.ru";
// ... (другие настройки профиля)

// Создаем письмо
Письмо = Новый ИнтернетПочтовоеСообщение;
Письмо.Вложения.Добавить(ВремФайл); // Вот здесь часто кроется ошибка
Письмо.Тема = "Акт сверки";

// Отправка
Почта = Новый ИнтернетПочта;
Почта.Подключиться(Профиль);
Почта.Послать(Письмо);

На первый взгляд код выглядит логично: метод Добавить() у коллекции Вложения принимает строку, которая является путем к файлу. Однако именно в этом месте система часто дает сбой.

Причина №1: Особенности метода Добавить() и блокировка файлов

Когда мы передаем в метод Добавить() простую строку с путем к файлу, объект ИнтернетПочтовоеСообщение не всегда считывает данные мгновенно. Чтение файла с диска может произойти позже — в момент вызова метода Послать(). Если к этому моменту файл еще заблокирован процессом записи (например, методом Записать() табличного документа), или если операционная система не успела завершить сброс данных из буфера на диск (так называемый Flush), 1С может прочитать «пустой» дескриптор файла.

Решение: Использование объекта ДвоичныеДанные. Это самый надежный способ, так как он заставляет 1С прочитать содержимое файла в оперативную память немедленно. Проанализируем исправленный вариант:


// Вместо передачи строки пути, читаем данные в память
ДанныеФайла = Новый ДвоичныеДанные(ВремФайл);
Письмо.Вложения.Добавить(ДанныеФайла, "Акт_сверки.pdf");

В этом случае мы явно указываем системе: «возьми эти байты и используй их как вложение». После этого файл на диске можно удалять, он больше не нужен для отправки.

Причина №2: Права доступа серверного контекста

Если код выполняется в регламентном задании, он работает от имени пользователя операционной системы, под которым запущен «Агент сервера 1С:Предприятия» (обычно это USR1CV8). Выясним, почему это важно:

  1. Доступ к папкам: Метод ПолучитьИмяВременногоФайла() возвращает путь в системную временную папку этого пользователя. Если у службы недостаточно прав на чтение из этой папки или если путь сформирован некорректно для серверной ОС (особенно на Linux), файл физически не будет создан.
  2. Проверка существования: Перед тем как добавлять вложение, обязательно проверьте, что файл действительно существует и имеет ненулевой размер.

Рассмотрим пример защищенного кода:


Таб.Записать(ВремФайл, ТипФайлаТабличногоДокумента.PDF);

ФайлНаДиске = Новый Файл(ВремФайл);
Если ФайлНаДиске.Существует() Тогда
    Размер = ФайлНаДиске.Размер();
    Если Размер > 0 Тогда
        Письмо.Вложения.Добавить(Новый ДвоичныеДанные(ВремФайл), "Документ.pdf");
    Иначе
        ЗаписьЖурналаРегистрации("ОтправкаПочты", УровеньЖурналаРегистрации.Ошибка, , , "Файл сформирован, но он пустой.");
    КонецЕсли;
Иначе
    ЗаписьЖурналаРегистрации("ОтправкаПочты", УровеньЖурналаРегистрации.Ошибка, , , "Файл не был создан на диске сервера.");
КонецЕсли;

Причина №3: Отсутствие шрифтов на сервере (Linux/Windows Server)

Иногда файл PDF создается, имеет нормальный вес (например, 50 Кб), но при открытии в нем видны только пустые листы или «квадратики» вместо текста. Это специфическая проблема генерации PDF на стороне сервера.

Для корректного рендеринга PDF движок 1С использует шрифты, установленные в операционной системе. Если вы используете сервер на базе Linux, необходимо убедиться, что установлены шрифты Microsoft (пакет ttf-mscorefonts-installer). Без них 1С не сможет отрисовать текст в PDF-контейнере, и документ визуально будет пустым.

Также проверьте настройки печати самого табличного документа. Рекомендуется явно устанавливать параметры страницы перед записью:


Таб.АвтоМасштаб = Истина;
Таб.ОриентацияСтраницы = ОриентацияСтраницы.Портрет;

Причина №4: Смешивание ручной отправки и БСП

В современных конфигурациях (УТ 11, БП 3.0, ERP) для работы с почтой используется Библиотека Стандартных Подсистем (БСП). Ошибка часто возникает, когда разработчик пытается совместить низкоуровневые объекты ИнтернетПочта и высокоуровневые функции БСП типа РаботаСПочтовымиСообщениями.ОтправитьПисьмо().

Проанализируем ситуацию: если вы передаете вручную созданный объект письма в типовую функцию БСП, она может пересобрать это письмо по своим внутренним алгоритмам, потеряв ваши вложения. Если вы используете БСП, лучше формировать структуру параметров, как того требует библиотека:


ПараметрыПисьма = Новый Структура;
ПараметрыПисьма.Вставить("Кому", "client@email.com");
ПараметрыПисьма.Вставить("Тема", "Акт сверки");
ПараметрыПисьма.Вставить("Тело", "Добрый день! Во вложении ваш акт.");

// Формируем массив вложений в формате БСП
МассивВложений = Новый Массив;
Вложение = Новый Структура;
Вложение.Вставить("Данные", Новый ДвоичныеДанные(ВремФайл));
Вложение.Вставить("ИмяФайла", "Акт.pdf");
МассивВложений.Добавить(Вложение);

ПараметрыПисьма.Вставить("Вложения", МассивВложений);

// Отправка через БСП
РаботаСПочтовымиСообщениями.ОтправитьПисьмо(СистемнаяУчетнаяЗапись, ПараметрыПисьма);

Итоги и рекомендации

Подведем итог нашему исследованию. Чтобы вложение в письме никогда не было пустым, придерживайтесь следующих правил:

Следуя этим шагам, мы исключим влияние асинхронности файловой системы и особенностей серверного контекста, обеспечив надежную доставку документов вашим контрагентам. Для реализации этой задачи можно также применить готовое расширение для отправки сообщений с вложениями.

← На главную