Отправка электронной почты
Собираетесь отправлять электронные письма, например, рассылки или подтверждения заказов? Фреймворк Nette предоставляет необходимые инструменты с очень удобным API. Мы покажем:
- как создать электронное письмо, включая вложения
- как его отправить
- как связать электронные письма и шаблоны
Установка
Вы можете скачать и установить библиотеку с помощью Composer:
composer require nette/mail
Создание электронного письма
Электронное письмо — это объект класса Nette\Mail\Message. Создадим его, например, так:
$mail = new Nette\Mail\Message;
$mail->setFrom('Franta <franta@example.com>')
->addTo('petr@example.com')
->addTo('jirka@example.com')
->setSubject('Подтверждение заказа')
->setBody("Добрый день,\nваш заказ принят.");
Все вводимые параметры должны быть в кодировке UTF-8.
Помимо указания получателя с помощью метода addTo()
, можно
указать получателя копии addCc()
или получателя скрытой копии
addBcc()
. Во всех этих методах, включая setFrom()
, мы можем
записать адрес тремя способами:
$mail->setFrom('franta@example.com');
$mail->setFrom('franta@example.com', 'Franta');
$mail->setFrom('Franta <franta@example.com>');
Тело электронного письма, написанное в HTML, передается с помощью
метода setHtmlBody()
:
$mail->setHtmlBody('<p>Добрый день,</p><p>ваш заказ принят.</p>');
Текстовую альтернативу создавать не нужно, Nette сгенерирует её
автоматически за вас. И если у письма не установлена тема, она
попытается взять её из элемента <title>
.
В HTML-тело также можно очень легко вставлять изображения. Достаточно передать вторым параметром путь, где физически находятся изображения, и Nette автоматически включит их в письмо:
// автоматически добавит /path/to/images/background.gif в письмо
$mail->setHtmlBody(
'<b>Hello</b> <img src="background.gif">',
'/path/to/images',
);
Алгоритм вставки изображений ищет следующие шаблоны:
<img src=...>
, <body background=...>
, url(...)
внутри
HTML-атрибута style
и специальный синтаксис [[...]]
.
Может ли отправка писем быть еще проще?
Электронное письмо — это что-то вроде открытки. Никогда не отправляйте пароли или другие учетные данные по электронной почте.
Вложения
В электронное письмо, конечно, можно вставлять вложения. Для этого
служит метод addAttachment(string $file, ?string $content = null, ?string $contentType = null)
.
// вставляет в письмо файл /path/to/example.zip под именем example.zip
$mail->addAttachment('/path/to/example.zip');
// вставляет в письмо файл /path/to/example.zip с именем info.zip
$mail->addAttachment('info.zip', file_get_contents('/path/to/example.zip'));
// вставляет в письмо файл example.txt с содержимым "Hello John!"
$mail->addAttachment('example.txt', 'Hello John!');
Шаблоны
Если вы отправляете HTML-письма, очень удобно писать их в системе шаблонов Latte. Как это сделать?
$latte = new Latte\Engine;
$params = [
'orderId' => 123,
];
$mail = new Nette\Mail\Message;
$mail->setFrom('Franta <franta@example.com>')
->addTo('petr@example.com')
->setHtmlBody(
$latte->renderToString('/path/to/email.latte', $params),
'/path/to/images',
);
Файл email.latte
:
<html>
<head>
<meta charset="utf-8">
<title>Подтверждение заказа</title>
<style>
body {
background: url("background.png")
}
</style>
</head>
<body>
<p>Добрый день,</p>
<p>Ваш заказ номер {$orderId} был принят.</p>
</body>
</html>
Nette автоматически вставит все изображения, установит тему согласно
элементу <title>
и сгенерирует текстовую альтернативу
для HTML.
Использование в Nette Application
Если вы используете электронные письма совместно с Nette Application, то есть
с презентерами, вы можете захотеть создавать ссылки в шаблонах с
помощью атрибута n:href
или тега {link}
. Latte по умолчанию их не
знает, но их очень легко добавить. Создавать ссылки умеет объект
Nette\Application\LinkGenerator
, к которому можно получить доступ, запросив
его через dependency injection:
use Nette;
class MailSender
{
public function __construct(
private Nette\Application\LinkGenerator $linkGenerator,
private Nette\Bridges\ApplicationLatte\TemplateFactory $templateFactory,
) {
}
private function createTemplate(): Nette\Application\UI\Template
{
$template = $this->templateFactory->createTemplate();
$template->getLatte()->addProvider('uiControl', $this->linkGenerator);
return $template;
}
public function createEmail(): Nette\Mail\Message
{
$template = $this->createTemplate();
$html = $template->renderToString('/path/to/email.latte', $params);
$mail = new Nette\Mail\Message;
$mail->setHtmlBody($html);
// ...
return $mail;
}
}
В шаблоне затем создаем ссылки так, как мы привыкли. Все ссылки, созданные через LinkGenerator, будут абсолютными.
<a n:href="Presenter:action">Ссылка</a>
Отправка электронного письма
Mailer — это класс, обеспечивающий отправку электронных писем. Он реализует интерфейс Nette\Mail\Mailer, и доступно несколько готовых мейлеров, которые мы рассмотрим.
Фреймворк автоматически добавляет в DI-контейнер сервис типа
Nette\Mail\Mailer
, собранный на основе #конфигурация, и
к которому можно получить доступ, запросив его через dependency injection.
SendmailMailer
Мейлер по умолчанию — это SendmailMailer, который использует PHP-функцию mail. Пример использования:
$mailer = new Nette\Mail\SendmailMailer;
$mailer->send($mail);
Если вы хотите установить returnPath
, а сервер его постоянно
перезаписывает, используйте $mailer->commandArgs = '-fMuj@email.cz'
.
SmtpMailer
Для отправки почты через SMTP-сервер служит SmtpMailer
.
$mailer = new Nette\Mail\SmtpMailer(
host: 'smtp.gmail.com',
username: 'franta@gmail.com',
password: '*****',
encryption: 'ssl',
);
$mailer->send($mail);
Конструктору можно передать следующие дополнительные параметры:
port
– если не установлен, используется по умолчанию 25 или 465 дляssl
timeout
– тайм-аут для SMTP-соединенияpersistent
– использовать постоянное соединениеclientHost
– установка заголовка Host клиентаstreamOptions
– позволяет установить SSL context options для соединения
FallbackMailer
Не отправляет электронные письма напрямую, а осуществляет отправку через набор мейлеров. В случае, если один мейлер выходит из строя, повторяет попытку со следующим. Если и последний выходит из строя, начинает снова с первого.
$mailer = new Nette\Mail\FallbackMailer([
$smtpMailer,
$backupSmtpMailer,
$sendmailMailer,
]);
$mailer->send($mail);
В качестве дополнительных параметров в конструкторе можно указать количество повторов и время ожидания в миллисекундах.
DKIM
DKIM (DomainKeys Identified Mail) — это технология для повышения доверия к электронным письмам, которая также помогает выявлять поддельные сообщения. Отправленное сообщение подписывается приватным ключом домена отправителя, и эта подпись сохраняется в заголовке письма. Сервер получателя сравнивает эту подпись с публичным ключом, хранящимся в DNS-записях домена. Соответствие подписи доказывает, что письмо действительно пришло из домена отправителя и что во время передачи сообщение не было изменено.
Подписание писем можно настроить для мейлера прямо в конфигурации. Если вы не используете dependency injection, это делается следующим образом:
$signer = new Nette\Mail\DkimSigner(
domain: 'nette.org',
selector: 'dkim',
privateKey: file_get_contents('../dkim/dkim.key'),
passPhrase: '****',
);
$mailer = new Nette\Mail\SendmailMailer; // или SmtpMailer
$mailer->setSigner($signer);
$mailer->send($mail);
Конфигурация
Обзор опций конфигурации для Nette Mail. Если вы не используете весь фреймворк, а только эту библиотеку, прочитайте, как загрузить конфигурацию.
Для отправки электронных писем по умолчанию используется мейлер
Nette\Mail\SendmailMailer
, который далее не конфигурируется. Однако мы
можем переключить его на Nette\Mail\SmtpMailer
:
mail:
# использовать SmtpMailer
smtp: true # (bool) по умолчанию false
host: ... # (string)
port: ... # (int)
username: ... # (string)
password: ... # (string)
timeout: ... # (int)
encryption: ... # (ssl|tls|null) по умолчанию null (имеет псевдоним 'secure')
clientHost: ... # (string) по умолчанию $_SERVER['HTTP_HOST']
persistent: ... # (bool) по умолчанию false
# контекст для подключения к SMTP-серверу, по умолчанию stream_context_get_default()
context:
ssl: # обзор опций на https://www.php.net/manual/en/context.ssl.php
allow_self_signed: ...
...
http: # обзор опций на https://www.php.net/manual/en/context.http.php
header: ...
...
С помощью опции context › ssl › verify_peer: false
можно отключить проверку
SSL-сертификатов. Настоятельно не рекомендуем это делать, так как
приложение станет уязвимым. Вместо этого добавьте сертификаты в
хранилище.
Для повышения доверия мы можем подписывать электронные письма с помощью технологии DKIM:
mail:
dkim:
domain: myweb.com
selector: lovenette
privateKey: %appDir%/cert/dkim.priv
passPhrase: ...
Сервисы DI
Эти сервисы добавляются в DI-контейнер:
Имя | Тип | Описание |
---|---|---|
mail.mailer |
Nette\Mail\Mailer | класс, отправляющий электронные письма |
mail.signer |
Nette\Mail\Signer | Подписание DKIM |