Nette Documentation Preview

syntax
Відправлення електронних листів
*******************************

<div class=perex>

Ви збираєтеся надсилати електронні листи, наприклад, інформаційні бюлетені або підтвердження замовлень? Nette Framework надає необхідні інструменти з дуже зручним 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>Привіт</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 з вмістом "Привіт, John!"
$mail->addAttachment('example.txt', 'Привіт, 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, тобто з presenter'ами, ви можете захотіти створювати посилання в шаблонах за допомогою атрибута `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], і доступно кілька готових мейлерів, які ми розглянемо.

Framework автоматично додає до 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 = '-fMy@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]   | [клас, що надсилає електронні листи |#Відправлення електронного листа]
| `mail.signer`	  | [api:Nette\Mail\Signer]   | [DKIM підписування |#DKIM]


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

Відправлення електронних листів

Ви збираєтеся надсилати електронні листи, наприклад, інформаційні бюлетені або підтвердження замовлень? Nette Framework надає необхідні інструменти з дуже зручним 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>Привіт</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 з вмістом "Привіт, John!"
$mail->addAttachment('example.txt', 'Привіт, 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, тобто з presenter'ами, ви можете захотіти створювати посилання в шаблонах за допомогою атрибута 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, і доступно кілька готових мейлерів, які ми розглянемо.

Framework автоматично додає до DI-контейнера сервіс типу Nette\Mail\Mailer, зібраний на основі конфігурації, до якого ви можете отримати доступ, передавши його за допомогою dependency injection.

SendmailMailer

Мейлер за замовчуванням — це SendmailMailer, який використовує PHP-функцію mail. Приклад використання:

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

Якщо ви хочете встановити returnPath, а сервер постійно його перезаписує, використовуйте $mailer->commandArgs = '-fMy@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 підписування