Nette Documentation Preview

syntax
Odesílání e-mailů
*****************

<div class=perex>

Chystáte se odesílat e-maily, například newslettery nebo potvrzení objednávek? Nette Framework poskytuje potřebné nástroje s velmi příjemným API. Ukážeme si:

- jak e-mail vytvořit včetně příloh
- jak ho odeslat
- jak spojit e-maily a šablony

</div>


Instalace
=========

Knihovnu stáhnete a nainstalujete pomocí nástroje [Composer|best-practices:composer]:

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


Vytvoření e-mailu
=================

E-mail je objektem třídy [api:Nette\Mail\Message]. Vytvoříme jej třeba takto:

```php
$mail = new Nette\Mail\Message;
$mail->setFrom('Franta <franta@example.com>')
	->addTo('petr@example.com')
	->addTo('jirka@example.com')
	->setSubject('Potvrzení objednávky')
	->setBody("Dobrý den,\nvaše objednávka byla přijata.");
```

Všechny zadávané parametry musí být v UTF-8.

Kromě uvedení příjemce metodou `addTo()` lze uvést i příjemce kopie `addCc()`, nebo příjemce skryté kopie `addBcc()`. Ve všech těchto metodách včetně `setFrom()` můžeme adresáta zapsat třemi způsoby:

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

Tělo e-mailu zapsaného v HTML se předává metodou `setHtmlBody()`:

```php
$mail->setHtmlBody('<p>Dobrý den,</p><p>vaše objednávka byla přijata.</p>');
```

Textovou alternativu nemusíte vytvářet, Nette ji vygeneruje automaticky za vás. A pokud e-mail nemá nastavený subjekt, pokusí se jej převzít z elementu `<title>`.

Do HTML těla lze také neobyčejně snadno vkládat obrázky. Stačí jako druhý parametr předat cestu, kde se obrázky fyzicky nacházejí, a Nette je automaticky zahrne do e-mailu:

```php
// automaticky přidá /path/to/images/background.gif do e-mailu
$mail->setHtmlBody(
	'<b>Hello</b> <img src="background.gif">',
	'/path/to/images',
);
```

Algoritmus vkládající obrázky vyhledává tyto vzory: `<img src=...>`, `<body background=...>`, `url(...)` uvnitř HTML atributu `style` a speciální syntaxi `[[...]]`.

Může být odesílání e-mailů ještě jednodušší?

E-mail je něco jako pohlednice. Nikdy e-mailem neposílejte hesla ani jiné přístupové údaje. .[tip]


Přílohy
-------

Do e-mailu lze samozřejmě vkládat přílohy. Slouží k tomu metoda `addAttachment(string $file, string $content = null, string $contentType = null)`.

```php
// vloží do e-mailu soubor /path/to/example.zip pod názvem example.zip
$mail->addAttachment('/path/to/example.zip');

// vloží do e-mailu soubor /path/to/example.zip pojmenovaný info.zip
$mail->addAttachment('info.zip', file_get_contents('/path/to/example.zip'));

// vloží do e-mailu soubor example.txt s obsahem "Hello John!"
$mail->addAttachment('example.txt', 'Hello John!');
```


Šablony
-------

Pokud posíláte HTML e-maily, přímo se nabízí je zapisovat v šablonovacím systému [Latte|latte:]. Jak na to?

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

Soubor `email.latte`:

```latte
<html>
<head>
	<meta charset="utf-8">
	<title>Potvrzení objednávky</title>
	<style>
	body {
		background: url("background.png")
	}
	</style>
</head>
<body>
	<p>Dobrý den,</p>

	<p>Vaše objednávka číslo {$orderId} byla přijata.</p>
</body>
</html>
```

Nette automaticky vloží všechny obrázky, nastaví subject podle elementu `<title>` a vygeneruje textovou alternativu k HTML.


Použití v Nette Application
---------------------------

Pokud e-maily používáte společeně s Nette Application, tj. s presentery, můžete chtít v šablonách vytvářet odkazy pomocí atributu `n:href` nebo značky `{link}`. Ty Latte v základu nezná, ale je velmi snadné je doplnit. Vytvářet odkazy umí objekt `Nette\Application\LinkGenerator`, ke kterému se dostanete tak, že si jej necháte předat pomocí [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;
	}
}
```

V šabloně potom vytváříme odkazy tak, jak jsme zvyklí. Všechny odkazy vytvořene přes LinkGenerator budou absolutní.

```latte
<a n:href="Presenter:action">Odkaz</a>
```


Odeslání e-mailu
================

Mailer je třída zajišťující odesílání e-mailů. Implementuje rozhraní [api:Nette\Mail\Mailer] a k dispozici je několik předpřipravených mailerů, které si představíme.

Framework automaticky přidává do DI kontejneru službu typu `Nette\Mail\Mailer` sestavenou na základě [#konfigurace], a ke které se dostanete tak, že si ji necháte předat pomocí [dependency injection |dependency-injection:passing-dependencies].


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

Výchozí mailer je SendmailMailer, který používá PHP funkci [php:mail]. Příklad použití:

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

Pokud chcete nastavit `returnPath` a server vám ho pořád přepisuje, použijte `$mailer->commandArgs = '-fMuj@email.cz'`.


SmtpMailer
----------

K odeslání pošty přes SMTP server slouží `SmtpMailer`.

```php
$mailer = new Nette\Mail\SmtpMailer(
	host: 'smtp.gmail.com',
	username: 'franta@gmail.com',
	password: '*****',
	encryption: 'ssl',
);
$mailer->send($mail);
```

Konstruktoru lze předat tyto další parametry:

* `port` - pokud není nastaven, použije se výchozí 25 nebo 465 pro `ssl`
* `timeout` - timeout pro SMTP spojení
* `persistent` - použít persistent spojení
* `clientHost` - nastavení hlavičky Host klienta
* `streamOptions` - umožňuje nastavit "SSL context options":https://www.php.net/manual/en/context.ssl.php pro spojení


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

E-maily přímo neodesílá, ale odesílání zprostředkovává přes sadu mailerů. V případě, že jeden mailer selže, zopakuje pokus u dalšího. Pokud selže i poslední, začíná znovu od prvního.

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

Jako další parametry v konstruktoru můžeme uvést počet opakování a čekací dobu v milisekundách.


DKIM
====

DKIM (DomainKeys Identified Mail) je technologie pro zvýšení důvěryhodnosti e-mailů, která také napomáhá odhalení podvržených zpráv. Odeslaná zpráva je podepsána privátním klíčem domény odesílatele a tento podpis je uložen v hlavičce e-mailu.
Server příjemce porovná tento podpis s veřejným klíčem uloženým v DNS záznamech domény. Tím, že podpis odpovídá, je prokázáno, že e-mail skutečně pochází z odesílatelovy domény a že během přenosu zprávy nedošlo k její úpravě.

Podepisování e-mailů můžete maileru nastavit přímo v [konfiguraci|#Konfigurace]. Pokud nepoužíváte dependency injection, používá se tímto způsobem:

```php
$signer = new Nette\Mail\DkimSigner(
	domain: 'nette.org',
	selector: 'dkim',
	privateKey: file_get_contents('../dkim/dkim.key'),
	passPhrase: '****',
);

$mailer = new Nette\Mail\SendmailMailer; // nebo SmtpMailer
$mailer->setSigner($signer);
$mailer->send($mail);
```


Konfigurace
===========

Přehled konfiguračních voleb pro Nette Mail. Pokud nepoužívate celý framework, ale jen tuto knihovnu, přečtěte si, [jak konfiguraci načíst|bootstrap:].

Pro odesílání e-mailů se standardně používá mailer `Nette\Mail\SendmailMailer`, který se dále nekonfiguruje. Můžeme jej však přepnout na `Nette\Mail\SmtpMailer`:

```neon
mail:
	# použije SmtpMailer
	smtp: true       # (bool) výchozí je false

	host: ...        # (string)
	port: ...        # (int)
	username: ...    # (string)
	password: ...    # (string)
	timeout: ...     # (int)
	encryption: ...  # (ssl|tls|null) výchozí je null (má alias 'secure')
	clientHost: ...  # (string) výchozí je $_SERVER['HTTP_HOST']
	persistent: ...  # (bool) výchozí je false

	# kontext pro připojení k SMTP serveru, výchozí je stream_context_get_default()
	context:
		ssl:         # přehled voleb na https://www.php.net/manual/en/context.ssl.php
			allow_self_signed: ...
			...
		http:        # přehled voleb na https://www.php.net/manual/en/context.http.php
			header: ...
			...
```

Pomocí volby `context › ssl › verify_peer: false` lze vypnout ověřování SSL certifikátů. **Důrazně nedoporučujeme** tohle dělat, protože se aplikace stane zranitelnou. Místo toho "přidejte certifikáty do uložiště":https://www.php.net/manual/en/openssl.configuration.php.

Pro zvýšení důvěryhodnosti můžeme e-maily podpisovat pomocí [technologie DKIM |https://blog.nette.org/cs/podepisujte-emaily-pomoci-dkim]:

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


Služby DI
=========

Tyto služby se přidávají do DI kontejneru:

| Název           | Typ                        | Popis
|-----------------------------------------------------
| `mail.mailer`	  | [api:Nette\Mail\Mailer]   | [třída odesílající e-maily |#Odeslání e-mailu]
| `mail.signer`	  | [api:Nette\Mail\Signer]   | [DKIM podepisování |#DKIM]


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

Odesílání e-mailů

Chystáte se odesílat e-maily, například newslettery nebo potvrzení objednávek? Nette Framework poskytuje potřebné nástroje s velmi příjemným API. Ukážeme si:

  • jak e-mail vytvořit včetně příloh
  • jak ho odeslat
  • jak spojit e-maily a šablony

Instalace

Knihovnu stáhnete a nainstalujete pomocí nástroje Composer:

composer require nette/mail

Vytvoření e-mailu

E-mail je objektem třídy Nette\Mail\Message. Vytvoříme jej třeba takto:

$mail = new Nette\Mail\Message;
$mail->setFrom('Franta <franta@example.com>')
	->addTo('petr@example.com')
	->addTo('jirka@example.com')
	->setSubject('Potvrzení objednávky')
	->setBody("Dobrý den,\nvaše objednávka byla přijata.");

Všechny zadávané parametry musí být v UTF-8.

Kromě uvedení příjemce metodou addTo() lze uvést i příjemce kopie addCc(), nebo příjemce skryté kopie addBcc(). Ve všech těchto metodách včetně setFrom() můžeme adresáta zapsat třemi způsoby:

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

Tělo e-mailu zapsaného v HTML se předává metodou setHtmlBody():

$mail->setHtmlBody('<p>Dobrý den,</p><p>vaše objednávka byla přijata.</p>');

Textovou alternativu nemusíte vytvářet, Nette ji vygeneruje automaticky za vás. A pokud e-mail nemá nastavený subjekt, pokusí se jej převzít z elementu <title>.

Do HTML těla lze také neobyčejně snadno vkládat obrázky. Stačí jako druhý parametr předat cestu, kde se obrázky fyzicky nacházejí, a Nette je automaticky zahrne do e-mailu:

// automaticky přidá /path/to/images/background.gif do e-mailu
$mail->setHtmlBody(
	'<b>Hello</b> <img src="background.gif">',
	'/path/to/images',
);

Algoritmus vkládající obrázky vyhledává tyto vzory: <img src=...>, <body background=...>, url(...) uvnitř HTML atributu style a speciální syntaxi [[...]].

Může být odesílání e-mailů ještě jednodušší?

E-mail je něco jako pohlednice. Nikdy e-mailem neposílejte hesla ani jiné přístupové údaje.

Přílohy

Do e-mailu lze samozřejmě vkládat přílohy. Slouží k tomu metoda addAttachment(string $file, string $content = null, string $contentType = null).

// vloží do e-mailu soubor /path/to/example.zip pod názvem example.zip
$mail->addAttachment('/path/to/example.zip');

// vloží do e-mailu soubor /path/to/example.zip pojmenovaný info.zip
$mail->addAttachment('info.zip', file_get_contents('/path/to/example.zip'));

// vloží do e-mailu soubor example.txt s obsahem "Hello John!"
$mail->addAttachment('example.txt', 'Hello John!');

Šablony

Pokud posíláte HTML e-maily, přímo se nabízí je zapisovat v šablonovacím systému Latte. Jak na to?

$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',
	);

Soubor email.latte:

<html>
<head>
	<meta charset="utf-8">
	<title>Potvrzení objednávky</title>
	<style>
	body {
		background: url("background.png")
	}
	</style>
</head>
<body>
	<p>Dobrý den,</p>

	<p>Vaše objednávka číslo {$orderId} byla přijata.</p>
</body>
</html>

Nette automaticky vloží všechny obrázky, nastaví subject podle elementu <title> a vygeneruje textovou alternativu k HTML.

Použití v Nette Application

Pokud e-maily používáte společeně s Nette Application, tj. s presentery, můžete chtít v šablonách vytvářet odkazy pomocí atributu n:href nebo značky {link}. Ty Latte v základu nezná, ale je velmi snadné je doplnit. Vytvářet odkazy umí objekt Nette\Application\LinkGenerator, ke kterému se dostanete tak, že si jej necháte předat pomocí 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;
	}
}

V šabloně potom vytváříme odkazy tak, jak jsme zvyklí. Všechny odkazy vytvořene přes LinkGenerator budou absolutní.

<a n:href="Presenter:action">Odkaz</a>

Odeslání e-mailu

Mailer je třída zajišťující odesílání e-mailů. Implementuje rozhraní Nette\Mail\Mailer a k dispozici je několik předpřipravených mailerů, které si představíme.

Framework automaticky přidává do DI kontejneru službu typu Nette\Mail\Mailer sestavenou na základě konfigurace, a ke které se dostanete tak, že si ji necháte předat pomocí dependency injection.

SendmailMailer

Výchozí mailer je SendmailMailer, který používá PHP funkci mail. Příklad použití:

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

Pokud chcete nastavit returnPath a server vám ho pořád přepisuje, použijte $mailer->commandArgs = '-fMuj@email.cz'.

SmtpMailer

K odeslání pošty přes SMTP server slouží SmtpMailer.

$mailer = new Nette\Mail\SmtpMailer(
	host: 'smtp.gmail.com',
	username: 'franta@gmail.com',
	password: '*****',
	encryption: 'ssl',
);
$mailer->send($mail);

Konstruktoru lze předat tyto další parametry:

  • port – pokud není nastaven, použije se výchozí 25 nebo 465 pro ssl
  • timeout – timeout pro SMTP spojení
  • persistent – použít persistent spojení
  • clientHost – nastavení hlavičky Host klienta
  • streamOptions – umožňuje nastavit SSL context options pro spojení

FallbackMailer

E-maily přímo neodesílá, ale odesílání zprostředkovává přes sadu mailerů. V případě, že jeden mailer selže, zopakuje pokus u dalšího. Pokud selže i poslední, začíná znovu od prvního.

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

Jako další parametry v konstruktoru můžeme uvést počet opakování a čekací dobu v milisekundách.

DKIM

DKIM (DomainKeys Identified Mail) je technologie pro zvýšení důvěryhodnosti e-mailů, která také napomáhá odhalení podvržených zpráv. Odeslaná zpráva je podepsána privátním klíčem domény odesílatele a tento podpis je uložen v hlavičce e-mailu. Server příjemce porovná tento podpis s veřejným klíčem uloženým v DNS záznamech domény. Tím, že podpis odpovídá, je prokázáno, že e-mail skutečně pochází z odesílatelovy domény a že během přenosu zprávy nedošlo k její úpravě.

Podepisování e-mailů můžete maileru nastavit přímo v konfiguraci. Pokud nepoužíváte dependency injection, používá se tímto způsobem:

$signer = new Nette\Mail\DkimSigner(
	domain: 'nette.org',
	selector: 'dkim',
	privateKey: file_get_contents('../dkim/dkim.key'),
	passPhrase: '****',
);

$mailer = new Nette\Mail\SendmailMailer; // nebo SmtpMailer
$mailer->setSigner($signer);
$mailer->send($mail);

Konfigurace

Přehled konfiguračních voleb pro Nette Mail. Pokud nepoužívate celý framework, ale jen tuto knihovnu, přečtěte si, jak konfiguraci načíst.

Pro odesílání e-mailů se standardně používá mailer Nette\Mail\SendmailMailer, který se dále nekonfiguruje. Můžeme jej však přepnout na Nette\Mail\SmtpMailer:

mail:
	# použije SmtpMailer
	smtp: true       # (bool) výchozí je false

	host: ...        # (string)
	port: ...        # (int)
	username: ...    # (string)
	password: ...    # (string)
	timeout: ...     # (int)
	encryption: ...  # (ssl|tls|null) výchozí je null (má alias 'secure')
	clientHost: ...  # (string) výchozí je $_SERVER['HTTP_HOST']
	persistent: ...  # (bool) výchozí je false

	# kontext pro připojení k SMTP serveru, výchozí je stream_context_get_default()
	context:
		ssl:         # přehled voleb na https://www.php.net/manual/en/context.ssl.php
			allow_self_signed: ...
			...
		http:        # přehled voleb na https://www.php.net/manual/en/context.http.php
			header: ...
			...

Pomocí volby context › ssl › verify_peer: false lze vypnout ověřování SSL certifikátů. Důrazně nedoporučujeme tohle dělat, protože se aplikace stane zranitelnou. Místo toho přidejte certifikáty do uložiště.

Pro zvýšení důvěryhodnosti můžeme e-maily podpisovat pomocí technologie DKIM:

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

Služby DI

Tyto služby se přidávají do DI kontejneru:

Název Typ Popis
mail.mailer Nette\Mail\Mailer třída odesílající e-maily
mail.signer Nette\Mail\Signer DKIM podepisování