Nette Documentation Preview

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

<div class=perex>

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

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

</div>


Установка .[#toc-installation]
==============================

Загрузите и установите пакет с помощью [Composer|best-practices:composer]:

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


Создание электронных писем .[#toc-creating-emails]
==================================================

Email - это объект [api:Nette\Mail\Message]:

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

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

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

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

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

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

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

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

Можно ли сделать отправку электронных писем ещё проще?

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


Вложения .[#toc-attachments]
----------------------------

Разумеется, вы можете прикреплять вложения к электронным письмам. Используйте команду `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!');
```


Шаблоны .[#toc-templates]
-------------------------

Если вы отправляете электронные письма в формате HTML, отличная идея — писать их в системе шаблонов [Latte|latte:]. Как это сделать?

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

```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 .[#toc-using-in-nette-application]
-------------------------------------------------------------------

Если вы используете электронную почту вместе с Nette Application, т. е. презентерами, вы можете захотеть создать ссылки в шаблонах, используя атрибут `n:href` или тег `{link}`. Latte в принципе их не знает, но их очень легко добавить. Созданием ссылок может заниматься объект `Nette\Application\LinkGenerator`, который вы получите, передав его с помощью [внедрения зависимостей |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">Link</a>
```


Отправка электронных писем .[#toc-sending-emails]
=================================================

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

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


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

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

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

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


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` - назначение клиента
* `streamOptions` - позволяет установить "опции контекста SSL":https://www.php.net/manual/ru/context.ssl.php для соединения


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

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

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

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


DKIM
====

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

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

```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);
```


Конфигурация .[#toc-configuring]
================================

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

Чтобы повысить доверие, мы можем подписывать электронные письма с помощью [технологии DKIM |https://blog.nette.org/ru/podpisyvajte-elektronnye-pis-ma-s-pomos-yu-dkim]:

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


Услуги DI .[#toc-di-services]
=============================

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

| Имя | Тип | Описание
|-----------------------------------------------------
| `mail.mailer`| [api:Nette\Mail\Mailer] | [Класс отправки электронной почты |#Sending Emails]
| `mail.signer`| [api:Nette\Mail\Signer] | [DKIM-подписание |#DKIM]


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

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

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

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

Имя Тип Описание
mail.mailer Nette\Mail\Mailer Класс отправки электронной почты
mail.signer Nette\Mail\Signer DKIM-подписание