Mail

Отправка
Электронные письма

Отправка электронных писем

Собираетесь ли вы отправлять электронные письма, например, информационные бюллетени или подтверждения заказов? Фреймворк Nette предоставляет необходимые инструменты с очень удобным API. Мы покажем:

  • как создать электронное письмо, включая вложения
  • как отправить
  • как объединить электронные письма и шаблоны

Установка

Загрузите и установите пакет с помощью Composer:

composer require nette/mail

Создание электронных писем

Email – это объект Nette\Mail\Message:

$mail = new Nette\Mail\Message;
$mail->setFrom('John <john@example.com>')
	->addTo('peter@example.com')
	->addTo('jack@example.com')
	->setSubject('Подтверждение заказа')
	->setBody("Здравствуйте. Ваш заказ принят.");

Все параметры должны быть закодированы в UTF-8.

Помимо указания получателей с помощью метода addTo(), вы также можете указать получателя копии с помощью addCc(), или получателя скрытой копии с помощью addBcc(). Все эти методы, включая setFrom(), принимают адресата тремя способами:

$mail->setFrom('john.doe@example.com');
$mail->setFrom('john.doe@example.com', 'John Doe');
$mail->setFrom('John Doe <john.doe@example.com>');

Тело письма, написанное в формате HTML, передается с помощью метода setHtmlBody():

$mail->setHtmlBody('<p>Hello,</p><p>Ваш заказ принят.</p>');

Вам не нужно создавать текстовый вариант письма, Nette сгенерирует его автоматически за вас. А если у письма нет темы, она будет взята из элемента <title>.

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

// автоматически добавляет /path/to/images/background.gif к письму
$mail->setHtmlBody(
	'<b>Привет</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('John <john@example.com>')
	->addTo('jack@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

Если вы используете электронную почту вместе с Nette Application, т. е. презентерами, вы можете захотеть создать ссылки в шаблонах, используя атрибут n:href или тег {link}. Latte в принципе их не знает, но их очень легко добавить. Созданием ссылок может заниматься объект Nette\Application\LinkGenerator, который вы получите, передав его с помощью внедрения зависимостей.

use Nette;

class MailSender
{
	private Nette\Application\LinkGenerator $linkGenerator;
	private Nette\Bridges\ApplicationLatte\TemplateFactory $templateFactory;

	public function __construct(
		Nette\Application\LinkGenerator $linkGenerator,
		Nette\Bridges\ApplicationLatte\TemplateFactory $templateFactory,
	)
	{
		$this->linkGenerator = $linkGenerator;
		$this->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">Link</a>

Отправка электронных писем

Mailer – это класс, отвечающий за отправку электронных писем. Он реализует интерфейс Nette\Mail\Mailer и предлагает несколько готовых почтовых программ, которые мы представим.

Фреймворк автоматически добавляет сервис Nette\Mail\Mailer на основе configuration в контейнер DI, который вы получаете, передавая его с помощью внедрения зависимостей.

SendmailMailer

По умолчанию используется SendmailMailer, который использует функцию PHP mail. Пример использования:

$mailer = new Nette\Mail\SendmailMailer;
$mailer->send($mail);

Если вы хотите установить returnPath, но сервер всё равно перезаписывает его, используйте $mailer->commandArgs = '-fmy@email.com'.

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 – назначение клиента
  • streamOptions – позволяет установить опции контекста SSL для соединения

FallbackMailer

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

$mailer = new Nette\Mail\FallbackMailer([
	$smtpMailer,
	$backupSmtpMailer,
	$sendmailMailer,
]);
$mailer->send($mail);

Другие параметры в конструкторе включают число повторов и время ожидания в милисекундах.

DKIM

DKIM (DomainKeys Identified Mail) – это технология надежной электронной почты, которая также помогает обнаружить поддельные сообщения. Отправленное сообщение подписывается закрытым ключом домена отправителя, и эта подпись сохраняется в заголовке электронной почты. Сервер получателя сравнивает эту подпись с открытым ключом, хранящимся в DNS-записях домена. Сверяя подпись, можно доказать, что электронное письмо действительно пришло из домена отправителя и что сообщение не было изменено во время его передачи.

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

$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
	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: ...
			...

Вы можете отключить проверку подлинности SSL-сертификата с помощью опции context › ssl › verify_peer: false. Настоятельно рекомендуется не делать этого, так как это сделает приложение уязвимым. Вместо этого, добавьте сертификаты в хранилище доверия.

Чтобы повысить доверие, мы можем подписывать электронные письма с помощью технологии DKIM:

mail:
	dkim:
		domain: myweb.com
		selector: lovenette
		privateKey: %appDir%/cert/dkim.priv
		passPhrase: ...