Практическое руководство: почтовые рассылки через PHP

Раздел: Веб-разработка -> Email отправка

Отправка почты через PHP

Для отправки электронных писем из PHP существует несколько основных подходов. Наиболее надёжным и гибким является использование специализированных библиотек, таких как PHPMailer, с подключением к внешнему SMTP-серверу. Однако в некоторых простых сценариях можно обойтись встроенной функцией mail(). Рассмотрим различные варианты.

PHPMailer + SMTP (рекомендуемый способ)

Как отправить письмо через внешний SMTP-сервер, например Gmail или Яндекс?

PHPMailer - это популярная библиотека, которая предоставляет удобный интерфейс для отправки почты через SMTP, с поддержкой вложений, HTML, альтернативных кодировок и аутентификации. Установка через Composer: composer require phpmailer/phpmailer.

require 'vendor/autoload.php';

$mail = new PHPMailer\PHPMailer\PHPMailer();
$mail->isSMTP();
$mail->Host = 'smtp.gmail.com';
$mail->Port = 587;
$mail->SMTPSecure = PHPMailer\PHPMailer\PHPMailer::ENCRYPTION_STARTTLS;
$mail->SMTPAuth = true;
$mail->Username = 'your@gmail.com';
$mail->Password = 'your-app-password';
$mail->setFrom('your@gmail.com', 'Sender');
$mail->addAddress('recipient@example.com', 'Recipient');
$mail->Subject = 'Test from PHPMailer';
$mail->Body = 'This is a <b>test</b> email.';
$mail->isHTML(true);

if ($mail->send()) {
    echo 'Mail sent successfully';
} else {
    echo 'Error: ' . $mail->ErrorInfo;
}

Php скрипт почты (отправка почты через php)

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

  • Ошибка аутентификации - неверный логин/пароль или требуется пароль приложения (для Gmail нужно включить двухфакторную аутентификацию и создать пароль приложения).
  • Блокировка SMTP - некоторые хостинги блокируют исходящие соединения на порты SMTP. Необходимо использовать порт 587 (STARTTLS) или 465 (SSL), или настроить ретрансляцию через локальный почтовый сервер.
  • Таймауты - если сервер не отвечает, увеличить таймаут: $mail->Timeout = 60;.

Вариант 1: Функция mail()

Как отправить письмо без установки дополнительных библиотек?

Функция mail() является встроенной в PHP и позволяет отправить письмо через локальный MTA (sendmail, Postfix и т.д.). Простейший пример:

$to = 'recipient@example.com';
$subject = 'Test mail';
$message = 'Hello!';
$headers = 'From: sender@example.com' . "\r\n" .
    'Reply-To: sender@example.com' . "\r\n" .
    'X-Mailer: PHP/' . phpversion();

if (mail($to, $subject, $message, $headers)) {
    echo 'Mail sent';
} else {
    echo 'Failed';
}

Ограничения и проблемы:

  • Письма часто попадают в спам, так как отсутствуют SPF/DKIM записи.
  • Сложно отправить HTML-письмо с корректными заголовками Content-Type.
  • Не поддерживает SMTP-аутентификацию - письмо отправляется от имени сервера, а не от указанного From, если сервер не настроен.
  • На некоторых хостингах функция mail() отключена.

Решение: использовать библиотеки или настроить sendmail с внешним SMTP-ретранслятором.

Вариант 2: swiftmailer (устаревший)

Как работать с библиотекой SwiftMailer для отправки писем?

SwiftMailer ранее была популярна, но сейчас её разработка прекращена в пользу Symfony Mailer. Пример:

require 'vendor/autoload.php';
$transport = (new Swift_SmtpTransport('smtp.gmail.com', 587, 'tls'))
    ->setUsername('your@gmail.com')
    ->setPassword('your-app-password');
$mailer = new Swift_Mailer($transport);
$message = (new Swift_Message('Subject'))
    ->setFrom(['your@gmail.com' => 'Sender'])
    ->setTo(['recipient@example.com'])
    ->setBody('Hello', 'text/plain');
$result = $mailer->send($message);

Проблема: библиотека больше не обновляется, рекомендуется перейти на Symfony Mailer.

Вариант 3: Symfony Mailer

Как отправлять письма в современных PHP-проектах?

Symfony Mailer - современная библиотека от Symfony, которая также может использоваться вне фреймворка. Установка: composer require symfony/mailer. Пример:

require 'vendor/autoload.php';
use Symfony\Component\Mailer\Transport;
use Symfony\Component\Mailer\Mailer;
use Symfony\Component\Mime\Email;

$transport = Transport::fromDsn('smtp://your@gmail.com:your-app-password@smtp.gmail.com:587');
$mailer = new Mailer($transport);
$email = (new Email())
    ->from('your@gmail.com')
    ->to('recipient@example.com')
    ->subject('Symfony Mailer test')
    ->text('Hello!');
$mailer->send($email);

Возможные проблемы: неправильный DSN формат, нехватка прав доступа. Рекомендуется использовать переменные окружения для паролей.

Вариант 4: Отправка через API SendGrid или Mailgun

Как отправлять письма через внешние почтовые сервисы, избегая проблем с SMTP?

Сервисы SendGrid, Mailgun, Amazon SES предоставляют HTTP API. Пример через cURL (SendGrid):

$url = 'https://api.sendgrid.com/v3/mail/send';
$apiKey = 'YOUR_API_KEY';
$data = [
    'personalizations' => [
        ['to' => [['email' => 'recipient@example.com']]]
    ],
    'from' => ['email' => 'sender@example.com'],
    'subject' => 'Test via SendGrid',
    'content' => [['type' => 'text/plain', 'value' => 'Hello']]
];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer ' . $apiKey,
    'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 202) { echo 'Sent'; } else { echo 'Error: ' . $response; }

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

Дополнительные примеры и расширенные сценарии

Пример 1: Отправка письма с вложением и inline-изображением (PHPMailer)

Этот пример демонстрирует добавление файла для скачивания и встраивание изображения прямо в тело письма.

Пример
require 'vendor/autoload.php';
$mail = new PHPMailer\PHPMailer\PHPMailer();
$mail->isSMTP();
$mail->Host = 'smtp.gmail.com';
$mail->Port = 587;
$mail->SMTPSecure = 'tls';
$mail->SMTPAuth = true;
$mail->Username = 'your@gmail.com';
$mail->Password = 'your-app-password';
$mail->setFrom('your@gmail.com', 'Sender');
$mail->addAddress('recipient@example.com');
$mail->Subject = 'With attachment and inline image';

// Добавляем вложение
$mail->addAttachment('/path/to/document.pdf', 'document.pdf');
// Встраиваем изображение
$mail->addEmbeddedImage('/path/to/logo.png', 'logo_cid');
// HTML тело письма ссылается на изображение по cid
$mail->Body = '

Вложение

Посмотрите документ в приложении.

'; $mail->isHTML(true); if ($mail->send()) { echo 'Письмо отправлено успешно'; } else { echo 'Ошибка: ' . $mail->ErrorInfo; }
Письмо отправлено успешно

Пример 2: Массовая рассылка с задержкой и логированием ошибок

При отправке большого количества писем важно соблюдать лимиты SMTP-сервера и фиксировать неудачные попытки.

Пример
$recipients = ['a@example.com', 'b@example.com', 'c@example.com'];
$logFile = 'send_log.txt';

foreach ($recipients as $to) {
    try {
        $mail = new PHPMailer\PHPMailer\PHPMailer(true); // true включает исключения
        // Настройки SMTP (вынесены в функцию для краткости)
        // ... $mail->isSMTP(), Host, Port, Auth, Username, Password ...
        $mail->setFrom('sender@example.com');
        $mail->addAddress($to);
        $mail->Subject = 'Bulk test';
        $mail->Body = 'Hello ' . $to;
        $mail->send();
        $log = date('Y-m-d H:i:s') . " - Success: $to\n";
        file_put_contents($logFile, $log, FILE_APPEND);
        sleep(2); // пауза между письмами
    } catch (Exception $e) {
        $log = date('Y-m-d H:i:s') . " - Failed: $to - " . $mail->ErrorInfo . "\n";
        file_put_contents($logFile, $log, FILE_APPEND);
        echo "Ошибка при отправке $to: " . $mail->ErrorInfo . "\n";
    }
}
(в файл send_log.txt записываются строки)
2025-04-03 12:00:00 - Success: a@example.com
2025-04-03 12:00:02 - Success: b@example.com
2025-04-03 12:00:04 - Failed: c@example.com - SMTP Error: ...

Пример 3: Использование DKIM подписи для улучшения доставляемости (PHPMailer)

DKIM добавляет цифровую подпись к письму, подтверждая, что оно отправлено с вашего домена. Требуется закрытый ключ и открытый DNS-запись.

Пример
$mail = new PHPMailer\PHPMailer\PHPMailer();
// базовые настройки SMTP...

$mail->DKIM_domain = 'example.com';
$mail->DKIM_private = '/path/to/private.key';
$mail->DKIM_selector = 'default'; // должно совпадать с DNS записью
$mail->DKIM_passphrase = ''; // если ключ защищен паролем
// после настройки $mail->send() автоматически добавит заголовок DKIM-Signature
(заголовки отправленного письма будут содержать DKIM-Signature: ...)

Пример 4: Отправка письма с multipart/alternative (текст+HTML) без библиотек

Этот пример показывает, как вручную сформировать письмо с двумя частями через функцию mail().

Пример
$to = 'recipient@example.com';
$subject = 'Multipart example';

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

$body = "--$boundary\r\n";
$body .= "Content-Type: text/plain; charset=UTF-8\r\n\r\n";
$body .= "Текстовая версия письма.\r\n";
$body .= "--$boundary\r\n";
$body .= "Content-Type: text/html; charset=UTF-8\r\n\r\n";
$body .= "

HTML версия

Текст

\r\n"; $body .= "--$boundary--\r\n"; mail($to, $subject, $body, $headers);
Письмо отправлено (результат зависит от локального MTA)

Отправка почты через PHP - comments

En
Php скрипт почты (php)