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
{
	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">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: ...

Послуги з проведення розслідувань

Ці сервіси додаються до контейнера DI:

Назва Тип Опис
mail.mailer Nette\Mail\Mailer клас відправлення електронноїпошти
mail.signer Nette\Mail\Signer підписання DKIM
версію: 4.0