Nette Documentation Preview

syntax
Отправка электронной почты
**************************

<div class=perex>

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

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

</div>


Установка
=========

Вы можете скачать и установить библиотеку с помощью [Composer|best-practices:composer]:

```shell
composer require nette/mail
```


Создание электронного письма
============================

Электронное письмо — это объект класса [api:Nette\Mail\Message]. Создадим его, например, так:

```php
$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()`, мы можем записать адрес тремя способами:

```php
$mail->setFrom('franta@example.com');
$mail->setFrom('franta@example.com', 'Franta');
$mail->setFrom('Franta <franta@example.com>');
```

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

```php
$mail->setHtmlBody('<p>Добрый день,</p><p>ваш заказ принят.</p>');
```

Текстовую альтернативу создавать не нужно, Nette сгенерирует её автоматически за вас. И если у письма не установлена тема, она попытается взять её из элемента `<title>`.

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

```php
// автоматически добавит /path/to/images/background.gif в письмо
$mail->setHtmlBody(
	'<b>Hello</b> <img src="background.gif">',
	'/path/to/images',
);
```

Алгоритм вставки изображений ищет следующие шаблоны: `<img src=...>`, `<body background=...>`, `url(...)` внутри HTML-атрибута `style` и специальный синтаксис `[[...]]`.

Может ли отправка писем быть еще проще?

.[tip]
Электронное письмо — это что-то вроде открытки. Никогда не отправляйте пароли или другие учетные данные по электронной почте.


Вложения
--------

В электронное письмо, конечно, можно вставлять вложения. Для этого служит метод `addAttachment(string $file, ?string $content = null, ?string $contentType = null)`.

```php
// вставляет в письмо файл /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:]. Как это сделать?

```php
$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`:

```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 |dependency-injection:passing-dependencies]:

```php
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, будут абсолютными.

```latte
<a n:href="Presenter:action">Ссылка</a>
```


Отправка электронного письма
============================

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

Фреймворк автоматически добавляет в DI-контейнер сервис типа `Nette\Mail\Mailer`, собранный на основе [конфигурации |#konfigurace], и к которому можно получить доступ, запросив его через [dependency injection |dependency-injection:passing-dependencies].


SendmailMailer
--------------

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

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

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


SmtpMailer
----------

Для отправки почты через SMTP-сервер служит `SmtpMailer`.

```php
$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":https://www.php.net/manual/en/context.ssl.php для соединения


FallbackMailer
--------------

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

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

В качестве дополнительных параметров в конструкторе можно указать количество повторов и время ожидания в миллисекундах.


DKIM
====

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

Подписание писем можно настроить для мейлера прямо в [конфигурации|#Konfigurace]. Если вы не используете dependency injection, это делается следующим образом:

```php
$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. Если вы не используете весь фреймворк, а только эту библиотеку, прочитайте, [как загрузить конфигурацию|bootstrap:].

Для отправки электронных писем по умолчанию используется мейлер `Nette\Mail\SendmailMailer`, который далее не конфигурируется. Однако мы можем переключить его на `Nette\Mail\SmtpMailer`:

```neon
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-сертификатов. **Настоятельно не рекомендуем** это делать, так как приложение станет уязвимым. Вместо этого "добавьте сертификаты в хранилище":https://www.php.net/manual/en/openssl.configuration.php.

Для повышения доверия мы можем подписывать электронные письма с помощью [технологии DKIM |https://blog.nette.org/cs/podepisujte-emaily-pomoci-dkim]:

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


Сервисы DI
==========

Эти сервисы добавляются в DI-контейнер:

| Имя             | Тип                        | Описание
|-----------------------------------------------------
| `mail.mailer`	  | [api:Nette\Mail\Mailer]   | [класс, отправляющий электронные письма |#Odeslání e-mailu]
| `mail.signer`	  | [api:Nette\Mail\Signer]   | [Подписание DKIM |#DKIM]


{{leftbar: nette:@menu-topics}}

Отправка электронной почты

Собираетесь отправлять электронные письма, например, рассылки или подтверждения заказов? Фреймворк 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