CoderNotes - заметки программиста

Публикации  »  PHP
Скидка 65% на Skillbox

Получите скидку 65% на любой курс программирования на популярной образовательной платформе Skillbox!

Подробнее
Бесплатный хостинг + SSL-сертификат

Зарегистрируйте домен и получите 2 месяца бесплатного хостинга и SSL-сертификат на 1 год в подарок

Подробнее

Отправка писем с помощью PHPMailer

PHPMailer - очень удобная и популярная библиотека для отправки e-mail сообщений с вашего сайта. В этой статье рассказаны основные настройки библиотеки и приведены примеры кода для отправки сообщений. PHPMailer имеет в своем ассортименте пожалуй всё, что можно пожелать от работы с почтой: отправка разными способами, через разные серверы в т.ч. через smtp, возможность шифровать и подписывать ваши письма, чтобы не попадали в спам и многое другое.

Скачать библиотеку PHPMailer можно с https://github.com/PHPMailer/PHPMailer (кнопка "Code" -> "Download ZIP").

Для начала разберу пару простых примеров, чтобы было понятно, как отправлять письма с помощью PHPMailer.

Отправка писем через функцию mail() с помощью PHPMailer

Если вы хотите отправлять письма со своего хостинга через свой почтовый сервер, то всё довольно просто и будет выглядеть примерно так:

// Подключаем библиотеку PHPMailer
use PHPMailer\PHPMailer\PHPMailer;
require 'PHPMailer/PHPMailer.php';

// Создаем письмо
$mail = new PHPMailer();
$mail->setFrom('test@domain.ru', 'Иван Иванов'); // от кого (email и имя)
$mail->addAddress('test@ya.ru', 'Вася Петров');  // кому (email и имя)
$mail->Subject = 'Тест';                         // тема письма
// html текст письма
$mail->msgHTML("<html><body>
                <h1>Здравствуйте!</h1>
                <p>Это тестовое письмо.</p>
                </html></body>");
// Отправляем
if ($mail->send()) {
  echo 'Письмо отправлено!';
} else {
  echo 'Ошибка: ' . $mail->ErrorInfo;
}  

Как видим, всё довольно просто: подключаем библиотеку, заполняем от кого, кому, тему и текст письма и отправляем. Отправка писем таким способом будет работать только с почтовых адресов вашего домена (если только они не привязаны к другим почтовикам).

Отправка писем через SMTP с помощью PHPMailer на примере Yandex и Google

Можно так же отправить письмо через другой почтовик, например, через Яндекс. Код будет выглядеть примерно так:

// Подключаем библиотеку PHPMailer
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
require 'PHPMailer/PHPMailer.php';
require 'PHPMailer/SMTP.php';

// Создаем письмо
$mail = new PHPMailer();
$mail->isSMTP();                   // Отправка через SMTP
$mail->Host   = 'smtp.yandex.ru';  // Адрес SMTP сервера
$mail->SMTPAuth   = true;          // Enable SMTP authentication
$mail->Username   = 'login';       // ваше имя пользователя (без домена и @)
$mail->Password   = 'password';    // ваш пароль
$mail->SMTPSecure = 'ssl';         // шифрование ssl
$mail->Port   = 465;               // порт подключения

$mail->setFrom('login@ya.ru', 'Иван Иванов');    // от кого
$mail->addAddress('test@ya.ru', 'Вася Петров'); // кому

$mail->Subject = 'Тест';
$mail->msgHTML("<html><body>
                <h1>Здравствуйте!</h1>
                <p>Это тестовое письмо.</p>
                </html></body>");
// Отправляем
if ($mail->send()) {
  echo 'Письмо отправлено!';
} else {
  echo 'Ошибка: ' . $mail->ErrorInfo;
}

Отправка писем через Google имеет один нюанс: нужно в аккаунте google разрешить доступ ненадежным приложениям. Для этого нужно зайти в свой аккаунт https://myaccount.google.com, перейти в безопасность, зайти в раздел "Ненадежные приложения, у которых есть доступ к аккаунту" и там переключить в "Разрешено". На момент написания статьи это страница https://myaccount.google.com/u/0/lesssecureapps.

Дальше в php-программе отправка писем через PHPMailer происходит аналогично как через yandex, нужно только заменить настройки SMTP так:

$mail->Host   = 'smtp.gmail.com';  // Адрес SMTP сервера
$mail->SMTPAuth   = true;          // Enable SMTP authentication
$mail->Username   = 'login';       // ваше имя пользователя
$mail->Password   = 'password';    // ваш пароль
$mail->SMTPSecure = 'ssl';         // шифрование ssl
$mail->Port   = 465;               // порт подключения

Если первый раз запускаете программу отправки через smtp, тогда желательно перед отправкой дополнительно использовать $mail->SMTPDebug = 1; чтобы получать все сообщения клиента и smtp-сервера, т.е. на экран выведется весь процесс подключения, авторизации и т.д., что очень полезно для отладки вашей программы.

Отправка письма с вложением с помощью PHPMailer

Здесь всё довольно просто, нужно лишь использовать метод addAttachment. Приведу пример, заодно продемонстрировав еще несколько дополнительных возможностей:

// Подключаем библиотеку PHPMailer
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
require 'PHPMailer/PHPMailer.php';
require 'PHPMailer/Exception.php';

// Создаем письмо
$mail = new PHPMailer;
$mail->CharSet = 'UTF-8';
$mail->setFrom('test@test.ru', 'Иван Иванов');     // от кого
$mail->addReplyTo('test@test.ru', 'Иван Иванов');  // обратный адрес
$mail->addAddress('test@ya.ru', 'Вася Петров');    // кому
$mail->Subject = 'Тест';                           // тема
$mail->msgHTML(file_get_contents('contents.html'), __DIR__);  // получаем "тело" письма из файла
$mail->AltBody = 'Письмо обычным текстом';  // письмо обычным текстом, если клиент не поддерживает html
$mail->addAttachment('my_file.txt');        // прикрепляем один файл
$mail->addAttachment('phpmailer.jpg');      // прикрепляем второй файл

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

Адресов получателей можно добавить несколько с помощью addAddress. Или, если необходимо, можно наоборот, очистить все адреса получателей методом clearAddresses(). Очистить все вложения можно с помощью clearAttachments().

Так же можно использовать AddEmbeddedImage чтобы добавить в письмо вложение (обычно изображения), которое предназначено для использования в html-коде и не будет доступно для скачивания. Пример использования картинки в письме, не доступной для скачивания:

// Подключаем библиотеку PHPMailer
use PHPMailer\PHPMailer\PHPMailer;
require 'PHPMailer/PHPMailer.php';

//Создаем письмо
$mail = new PHPMailer;
$mail->IsHTML(true);
$mail->setFrom('test@test.ru', 'Иван Иванов');
$mail->addAddress('test@ya.ru', 'Вася Петров');
$mail->Subject = 'Test';
$mail->AddEmbeddedImage('phpmailer.jpg','testImage');
$mail->Body = '<p>Изображение в html-коде <img src="cid:testImage"></p>';

// Отправляем
$mail->send();

Таким образом, вы можете отправлять письма с изображениями, которые есть только в теле письма, но их нельзя скачать как вложение. Эти изображения можно использовать в любом месте html-кода письма, нужно лишь указывать вместо url-адреса cid изображения, который вы использовали в AddEmbeddedImage.

Отправка подписанного и зашифрованного письма через PHPMailer

По-умолчанию, PHPMailer шифрует все отправляемые письма. Отключить шифрование письма можно только при отправке писем через SMTP использовав код:

$mail->SMTPSecure = false;
$mail->SMTPAutoTLS = false;

Чтобы подписать письмо подписью DKIM, необходимо выполнить несколько действий:

  • Сгенерировать приватный (private) и публичный (public) ключи для вашего домена
  • Добавить DNS-запись для домена типа TXT с публичным ключом
  • Настроить DKIM подпись в PHPMailer перед отправкой письма

Теперь опишу каждый шаг немного подробнее.

Генерация приватного и публичного ключей

Если у вас Linux-хостинг и есть доступ в Shell, то сгенерировать файлы ключей проще простого, нужно выполнить всего 2 команды с обычными правами своего пользователя:

openssl genrsa -out test-private.pem 1024
openssl rsa -in test-private.pem -out test-public.pem -pubout

Соответственно, test-private.pem и test-public.pem - это приватный и публичный ключи. Сохранить их нужно в папке, которая будет не доступна посетителям сайта или кому-то еще кроме вас.

Если нет возможности выполнить команды в shell, тогда чтобы сгенерировать приватный (private) и публичный (public) ключи и сохранить их в файлы, можно воспользоваться следующим кодом:

$domain = 'test.ru';                   // ваш домен
$privatekeyfile = 'test-private.pem';  // имя файла, в который будет записан приватный ключ
$publickeyfile = 'test-public.pem';    // имя файла, в который будет записан публичный ключ

if (file_exists($privatekeyfile)) {
  echo "<p>Using existing keys</p>";
  $privatekey = file_get_contents($privatekeyfile);
  $publickey = file_get_contents($publickeyfile);
} else {
  echo "<p>Create keys</b>";
  $pk = openssl_pkey_new(
      [
          'digest_alg' => 'sha256',
          'private_key_bits' => 2048,
          'private_key_type' => OPENSSL_KEYTYPE_RSA,
      ]
  );
  openssl_pkey_export_to_file($pk, $privatekeyfile);
  $pubKey = openssl_pkey_get_details($pk);
  $publickey = $pubKey['key'];
  file_put_contents($publickeyfile, $publickey);
  $privatekey = file_get_contents($privatekeyfile);
}
echo "<p>Private key (keep this private!):</p><pre>" . $privatekey . "</pre>";
echo "<p>Public key:</p><pre>" . $publickey . "</pre>";

Внимание! Не забудьте убедиться, что папка, в которую будут сохраняться файлы, доступна для записи.

Добавление DNS-записи с публичным ключом

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

Нужно добавить DNS-запись следующего вида:

Имя записи: mail._domainkey.test.ru. (в конце точка ".")

TTL: 3600 (или какое будет по-умолчанию)

Тип записи: TXT

Значение: v=DKIM1; h=sha256; t=s; p=ВАШ_ПУБЛИЧНЫЙ_КЛЮЧ

В имени записи test.ru нужно заменить на имя вашего домена. Слова "ВАШ_ПУБЛИЧНЫЙ_КЛЮЧ" вы заменяете на текст, который вы получили на предыдущем шаге после "Public key", без "-----BEGIN PUBLIC KEY-----" и "-----END PUBLIC KEY-----", только сам ключ. При этом все строчки ключа нужно соединить в одну длинную строку, чтобы переводов строки не было.

Настройка подписи DKIM в PHPMailer и отправка письма

Теперь осталось лишь сделать несколько настроек PHPMailer перед отправкой письма и оно будет подписано. Думаю, на приведенном примере будет всё понятно:

// Подключаем библиотеку
use PHPMailer\PHPMailer\PHPMailer;
require 'PHPMailer/PHPMailer.php';

// Создаем письмо
$mail = new PHPMailer;
$mail->CharSet = 'UTF-8';
$mail->setFrom('test@test.ru');
$mail->addAddress('test@ya.ru');
$mail->Subject = 'Это тест';
$mail->msgHTML('<p>Это тест</p>');

// Настройка DKIM подписи
$mail->DKIM_domain = 'test.ru';
$mail->DKIM_private = 'test-private.pem';
$mail->DKIM_selector = 'mail';

// Отправляем
$mail->send();

Разумеется, test.ru вы должны поменять на имя своего домена, а test-private.pem на полный путь и имя файла приватного ключа, который был создан на этапе генерации ключей.

Теперь, ваши письма, отправляемые через PHPMailer будут подписаны подписью DKIM вашим приватным ключом.

 

Категория: PHP

Книги по теме:

Посмотреть все книги по программированию

Комментарии к статье:

08.04.20   Гость Огромное спасибо!
26.07.20   Путин Я был здесь
02.09.20   Лукашенко Хэлп ми, бро!
12.09.20   Андрей Спасибо за мое сэкономленное время!
14.12.20   Foxemi AddAttachment не работает в старых версиях phpmailer (для php версии 5.3 и ниже).
31.01.21   Гость Дай Бог тебе здоровья, добрый человек!
25.03.21   Гость Спасибо!
07.06.21   Гость Теперь другой вопрос... как проверить, что я правильно сделал ключ
09.06.21   Гость Для проверки ключа https://www.reg.ru/support/ssl-sertifikaty/ustanovka-ssl-sertifikata/kak-proverit-sootvetstvie-privatnogo-klyucha-ssl-sertifikatu
А чтобы проверить, что phpmailer использует ваш ключ нужно, отправить письмо на какой-нибудь ящик в yandex-е или mail.ru.
В их интерфейсе рядом с адресом отправителя должен быть замочек, при наведении на который можно увидеть "Отправитель подтвержден и проверен" или что-то в этом роде.
09.06.21   Абема Я черножопый блять
11.06.21   Гость Ничего не работает. Этих настроек недостаточно для подписи письма.
11.06.21   Гость Ошибка в заголовке:
dkim=fail reason=signature_incorrect header.d=site.ru
и
X-DKIM-FAIL: DKIM test failed: bad signature (address=no-reply@site.ru domain=site.ru).
29.07.21   Гость фукруфКП
02.08.21   Гость олаху - кебап!
12.08.21   Лукашенко Встречаемся в Крыму зимой
01.02.22   Гость на гитхабе читал ридми и толком ни чего не работает тут тоже а в итоге надо всего лишь путь правильно указать к скриптам
ну что же вы так все абы как пишите трудно добавить в код dirname(__FILE__)
21.02.22   Аня Аня
22.02.22   Александр Александр
10.03.22   Иван Иван
17.03.22   Вован Вован
20.03.22   mazafaker А примеры с обработкой данных с fetch есть?
24.03.22   Мария Мария
28.03.22   Екатерина Екатерина
03.04.22   Гость олщш
05.04.22   Елена Елена
13.05.22   Наталия Наталия
18.05.22   Денис Денис
20.05.22   Рустам Рустам
26.05.22   Ксения Ксения
26.05.22   Ксения Ксения
26.05.22   Ксения Ксения
29.05.22   Екатерина Екатерина
30.05.22   Ксюша Ксюша
02.06.22   Ксения Ксения
06.06.22   Ашот Ашот
15.06.22   Денис Денис
15.06.22   Денис Денис
17.06.22   Женя Женя
14.07.22   Иван Иван
05.08.22   Аркадий Паровозов
23.08.22   Виктор Виктор
21.09.22   Гость kkk
04.10.22   Гость ыф
07.10.22   Гость фы
26.11.22   Гость Ваще норм
06.02.23   Влад Спасибо мужик, очень помог. Теперь благодаря настройке отправке почты с DKIM подписью мои письма приходят во входящие для любых почтовых серверов (и для gmail.com, и mail.ru и даже для самого помешанного на борьбе со спамом yandex.ru)
16.07.23   Гость thx
07.09.23   Гость СПАСИБО
23.09.24   Гость Чиьп
01.10.24   Гость x
13.10.24   Веро Благодарю! Помогло.
23.10.24   Максимыч классная статья!
15.11.24   Дима Госпади, автор, ты сделал мой день) Оч подробно все разобрано!
Наконец-то все заработало!
23.11.24   Гость вШюЬь

Добавить комментарий: