Вставка файлов в письма на PHP

Раздел: Разработка на PHP -> Отправка почты

Обзор методов отправки файлов

Как наиболее эффективно отправить файл через PHP?

Наиболее надёжным и гибким решением является использование библиотеки PHPMailer. Она поддерживает все современные протоколы (SMTP, SSL/TLS), автоматически формирует MIME-сообщения с вложениями, обрабатывает кодировки и предоставляет понятный API. PHPMailer активно развивается и используется в большинстве современных проектов.

Установка через Composer: composer require phpmailer/phpmailer

Пример отправки письма с вложением:


<?php
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;

require 'vendor/autoload.php';

$mail = new PHPMailer(true);

try {
    $mail->isSMTP();
    $mail->Host = 'smtp.example.com';
    $mail->SMTPAuth = true;
    $mail->Username = 'user@example.com';
    $mail->Password = 'secret';
    $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
    $mail->Port = 587;

    $mail->setFrom('from@example.com', 'Отправитель');
    $mail->addAddress('to@example.com', 'Получатель');

    $mail->Subject = 'Письмо с вложением';
    $mail->Body = 'Текст письма с вложенным файлом.';

    // Добавление файла
    $mail->addAttachment('/path/to/file.pdf', 'Документ.pdf');

    $mail->send();
    echo 'Письмо отправлено';
} catch (Exception $e) {
    echo "Ошибка: {$mail->ErrorInfo}";
}
    

Php файл почтой (отправка файла по электронной почте в php)

Цель: быстрое добавление вложений без ручного формирования заголовков. Подходит для любого проекта, где требуется гарантированная доставка и поддержка различных MIME-типов.

Типичные проблемы и решения:

  • Ошибка SMTP connect() - проверьте доступность хоста и порта, убедитесь, что не блокируется исходящее соединение;
  • Файл не прикреплён - путь должен быть абсолютным или корректным относительно корня проекта;
  • Кодировка письма - PHPMailer автоматически ставит UTF-8, но если тело содержит другие кодировки, задайте их явно через $mail->CharSet = 'UTF-8'.

Как отправить файл без сторонних библиотек, используя только встроенную функцию mail()?

Этот вариант подходит для простых скриптов, когда нельзя устанавливать дополнительные пакеты. Необходимо вручную сформировать multipart/mixed MIME-сообщение. Основная сложность - правильное построение границ (boundary) и кодирование вложения в Base64.


<?php
$to = 'to@example.com';
$subject = 'Вложение из mail()';
$boundary = uniqid('boundary', true);

// Текстовое тело
$text = 'Текстовое содержимое письма.';

// Чтение файла
$filename = 'document.pdf';
$filepath = '/path/to/' . $filename;
$content = file_get_contents($filepath);
$encoded = chunk_split(base64_encode($content));

// Заголовки
$headers = "From: sender@example.com\r\n";
$headers .= "MIME-Version: 1.0\r\n";
$headers .= "Content-Type: multipart/mixed; boundary=\"$boundary\"\r\n";

// Формирование тела
$body = "--$boundary\r\n";
$body .= "Content-Type: text/plain; charset=UTF-8\r\n\r\n";
$body .= $text . "\r\n";
$body .= "--$boundary\r\n";
$body .= "Content-Type: application/octet-stream; name=\"$filename\"\r\n";
$body .= "Content-Disposition: attachment; filename=\"$filename\"\r\n";
$body .= "Content-Transfer-Encoding: base64\r\n\r\n";
$body .= $encoded . "\r\n";
$body .= "--$boundary--";

if (mail($to, $subject, $body, $headers)) {
    echo 'Письмо отправлено через mail()';
} else {
    echo 'Ошибка отправки';
}
    

Цель: использование в окружениях без менеджера пакетов. Не рекомендуется для вложений большого размера (более 10 МБ) из-за ограничений почтовых серверов и PHP.

Проблемы:

  • Некорректное отображение вложения - часто возникает из-за неправильного формирования границ или отсутствия переносов строк;
  • Письмо попадает в спам - ручные заголовки могут не соответствовать стандартам, рекомендуется добавить DKIM/SPF на сервере;
  • Проблемы с кириллицей в имени файла - имя следует кодировать в Base64 или использовать RFC2231.

Как использовать Symfony Mailer для отправки файлов?

Symfony Mailer - современная альтернатива PHPMailer, интегрируемая с Symfony и другими фреймворками. Работает через DSN (Data Source Name), поддерживает множество транспортов.


<?php
use Symfony\Component\Mailer\Transport;
use Symfony\Component\Mailer\Mailer;
use Symfony\Component\Mime\Email;

require 'vendor/autoload.php';

$transport = Transport::fromDsn('smtp://user:pass@smtp.example.com:587');
$mailer = new Mailer($transport);

$email = (new Email())
    ->from('from@example.com')
    ->to('to@example.com')
    ->subject('Письмо с вложением')
    ->text('Текст письма')
    ->attachFromPath('/path/to/file.pdf', 'Документ.pdf');

$mailer->send($email);
echo 'Отправлено через Symfony Mailer';
    

Цель: использование в проектах на Symfony или для тех, кто предпочитает компонентный подход. Легко конфигурируется и расширяется.

Типичные ошибки:

  • Неверный DSN - проверьте формат строки, она чувствительна к синтаксису;
  • Файл не найден - указывайте абсолютные пути или используйте attach() с содержимым;
  • SSL/TLS ошибки - укажите корректный порт и включите tls:// или ssl:// в DSN.

Расширенные примеры и практические сценарии

1. PHPMailer: отправка с несколькими вложениями и встроенными изображениями

Пример демонстрирует добавление двух файлов (PDF и изображение) и встраивание картинки в тело письма.

Пример

<?php
use PHPMailer\PHPMailer\PHPMailer;
use PHpmailer\PHPMailer\Exception;

require 'vendor/autoload.php';

$mail = new PHPMailer(true);
$mail->isSMTP();
$mail->Host = 'smtp.mailtrap.io';    // тестовый SMTP
$mail->SMTPAuth = true;
$mail->Username = 'username';
$mail->Password = 'password';
$mail->SMTPSecure = 'tls';
$mail->Port = 2525;

$mail->setFrom('from@example.com', 'Отправитель');
$mail->addAddress('to@example.com');

$mail->Subject = 'Несколько вложений';

// HTML тело с встроенным изображением
$mail->isHTML(true);
$mail->Body = '<h1>Пример</h1><br><img src="cid:logo_cid">';
$mail->AltBody = 'Текстовая версия письма.';

// Добавление вложений
$mail->addAttachment('/tmp/report.pdf', 'Отчёт.pdf');
$mail->addAttachment('/tmp/photo.jpg', 'Фото.jpg');

// Встраивание изображения с Content-ID
$mail->addEmbeddedImage('/tmp/logo.png', 'logo_cid', 'logo.png');

try {
    $mail->send();
    echo 'Письмо с несколькими вложениями и встроенным изображением отправлено.';
} catch (Exception $e) {
    echo "Ошибка: {$mail->ErrorInfo}";
}
Письмо с несколькими вложениями и встроенным изображением отправлено.

2. mail() с вложением из строки (без сохранения файла на диск)

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

Пример

<?php
// Предположим, $pdfContent уже содержит бинарные данные PDF
$pdfContent = '%PDF-1.4...';  // данные

$to = 'user@example.com';
$subject = 'Счёт из строки';
$boundary = '==BOUNDARY_' . md5(time());

$headers = "From: sender@example.com\r\n";
$headers .= "MIME-Version: 1.0\r\n";
$headers .= "Content-Type: multipart/mixed; boundary=\"$boundary\"\r\n";

$text = "Счёт прикреплён.";

$encoded = chunk_split(base64_encode($pdfContent));

$body = "--$boundary\r\n";
$body .= "Content-Type: text/plain; charset=UTF-8\r\n\r\n$text\r\n";
$body .= "--$boundary\r\n";
$body .= "Content-Type: application/pdf; name=\"invoice.pdf\"\r\n";
$body .= "Content-Disposition: attachment; filename=\"invoice.pdf\"\r\n";
$body .= "Content-Transfer-Encoding: base64\r\n\r\n$encoded\r\n";
$body .= "--$boundary--";

mail($to, $subject, $body, $headers);

Примечание:

При таком подходе нужно следить за длиной строк и возможными ограничениями на размер письма у провайдера.

3. Symfony Mailer: использование потока (resource) для вложения

Можно прикрепить файл не из пути, а из потока, например из php://memory.

Пример

<?php
use Symfony\Component\Mailer\Transport;
use Symfony\Component\Mailer\Mailer;
use Symfony\Component\Mime\Email;

require 'vendor/autoload.php';

$transport = Transport::fromDsn('native://default'); // использует sendmail
$mailer = new Mailer($transport);

$data = 'Content of the file to attach';
$handle = fopen('php://memory', 'rw');
fwrite($handle, $data);
rewind($handle);

$email = (new Email())
    ->from('from@example.com')
    ->to('to@example.com')
    ->subject('Вложение из потока')
    ->text('Текст')
    ->attach($handle, 'file.txt', 'text/plain');

$mailer->send($email);
fclose($handle);
Письмо отправлено, файл file.txt прикреплён.

4. Обработка ошибок и отладка в PHPMailer

Для отладки подключения можно включить вывод протокола SMTP.

Пример

<?php
$mail = new PHPMailer(true);
try {
    $mail->SMTPDebug = 2;                  // вывод всех сообщений
    $mail->Debugoutput = function($str, $level) {
        file_put_contents('/tmp/smtp.log', $str, FILE_APPEND);
    };
    // остальная настройка...
} catch (Exception $e) {
    echo "Ошибка: {$mail->ErrorInfo}";
}

Результат:

В файл /tmp/smtp.log будут записаны команды и ответы SMTP-сервера.

5. Отправка с помощью Pear Mail_Mime (устаревший, но рабочий вариант)

PEAR Mail_Mime позволяет быстро сформировать multipart-сообщение без установки PHPMailer. Однако пакет больше не поддерживается.

Пример

<?php
require_once 'Mail.php';
require_once 'Mail/mime.php';

$params = array(
    'host' => 'smtp.example.com',
    'auth' => true,
    'username' => 'user',
    'password' => 'pass'
);
$mail = Mail::factory('smtp', $params);

$headers = array(
    'From' => 'from@example.com',
    'To' => 'to@example.com',
    'Subject' => 'Вложение из PEAR'
);

$mime = new Mail_mime();
$mime->setTXTBody('Текст письма');
$mime->addAttachment('/path/file.zip', 'application/zip');

$body = $mime->get();
$headers = $mime->headers($headers);

$mail->send($recipients = 'to@example.com', $headers, $body);

Важно:

PEAR Mail_Mime требует установки через pear install Mail_Mime и может конфликтовать с современными версиями PHP.

Отправка файла по электронной почте в PHP - comments

En
Php файл почтой (php)