Nette Documentation Preview

syntax
Nette Mail
**********

<div class=perex>

Ali nameravate pošiljati e-pošto, na primer novice ali potrditve naročil? Nette Framework ponuja potrebna orodja z zelo prijetnim API-jem. Pokazali bomo:

- kako ustvariti e-pošto, vključno s prilogami
- kako jo poslati
- kako povezati e-pošto in predloge

</div>


Namestitev
==========

Knjižnico prenesete in namestite z orodjem [Composer|best-practices:composer]:

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


Ustvarjanje e-pošte
===================

E-pošta je objekt razreda [api:Nette\Mail\Message]. Ustvarimo jo na primer tako:

```php
$mail = new Nette\Mail\Message;
$mail->setFrom('Franta <franta@example.com>')
	->addTo('petr@example.com')
	->addTo('jirka@example.com')
	->setSubject('Potrditev naročila')
	->setBody("Dober dan,\nvaše naročilo je bilo sprejeto.");
```

Vsi vneseni parametri morajo biti v UTF-8.

Poleg navedbe prejemnika z metodo `addTo()` lahko navedemo tudi prejemnika kopije `addCc()` ali prejemnika skrite kopije `addBcc()`. V vseh teh metodah, vključno z `setFrom()`, lahko naslovnika zapišemo na tri načine:

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

Telo e-pošte, zapisano v HTML, se preda z metodo `setHtmlBody()`:

```php
$mail->setHtmlBody('<p>Dober dan,</p><p>vaše naročilo je bilo sprejeto.</p>');
```

Besedilne alternative vam ni treba ustvarjati, Nette jo bo samodejno ustvaril za vas. In če e-pošta nima nastavljenega subjekta, ga bo poskusil prevzeti iz elementa `<title>`.

V telo HTML lahko tudi izjemno enostavno vstavljate slike. Dovolj je, da kot drugi parameter predate pot, kjer se slike fizično nahajajo, in Nette jih bo samodejno vključil v e-pošto:

```php
// samodejno doda /path/to/images/background.gif v e-pošto
$mail->setHtmlBody(
	'<b>Hello</b> <img src="background.gif">',
	'/path/to/images',
);
```

Algoritem za vstavljanje slik išče te vzorce: `<img src=...>`, `<body background=...>`, `url(...)` znotraj atributa HTML `style` in posebno sintakso `[[...]]`.

Ali je lahko pošiljanje e-pošte še enostavnejše?

.[tip]
E-pošta je kot razglednica. Nikoli ne pošiljajte gesel ali drugih poverilnic po e-pošti.


Priloge
-------

V e-pošto lahko seveda vstavljate priloge. Za to služi metoda `addAttachment(string $file, ?string $content = null, ?string $contentType = null)`.

```php
// vstavi datoteko /path/to/example.zip v e-pošto pod imenom example.zip
$mail->addAttachment('/path/to/example.zip');

// vstavi datoteko /path/to/example.zip v e-pošto z imenom info.zip
$mail->addAttachment('info.zip', file_get_contents('/path/to/example.zip'));

// vstavi datoteko example.txt z vsebino "Hello John!" v e-pošto
$mail->addAttachment('example.txt', 'Hello John!');
```


Predloge
--------

Če pošiljate HTML e-pošto, je naravno, da jo zapišete v sistemu predlog [Latte|latte:]. Kako to storiti?

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

Datoteka `email.latte`:

```latte
<html>
<head>
	<meta charset="utf-8">
	<title>Potrditev naročila</title>
	<style>
	body {
		background: url("background.png")
	}
	</style>
</head>
<body>
	<p>Dober dan,</p>

	<p>Vaše naročilo številka {$orderId} je bilo sprejeto.</p>
</body>
</html>
```

Nette samodejno vstavi vse slike, nastavi subjekt glede na element `<title>` in ustvari besedilno alternativo HTML.


Uporaba v Nette Application
---------------------------

Če e-pošto uporabljate skupaj z Nette Application, tj. s presenterji, boste morda želeli v predlogah ustvarjati povezave z atributom `n:href` ali oznako `{link}`. Teh Latte privzeto ne pozna, vendar jih je zelo enostavno dodati. Povezave zna ustvarjati objekt `Nette\Application\LinkGenerator`, do katerega pridete tako, da si ga pustite predati z [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 predlogi nato ustvarjamo povezave, kot smo navajeni. Vse povezave, ustvarjene prek LinkGeneratorja, bodo absolutne.

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


Pošiljanje e-pošte
==================

Mailer je razred, ki skrbi za pošiljanje e-pošte. Implementira vmesnik [api:Nette\Mail\Mailer] in na voljo je več predpripravljenih mailerjev, ki jih bomo predstavili.

Framework samodejno doda v DI vsebnik storitev tipa `Nette\Mail\Mailer`, sestavljeno na podlagi [Konfiguracije |#Konfiguracija], do katere pridete tako, da si jo pustite predati z [dependency injection |dependency-injection:passing-dependencies].


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

Privzeti mailer je SendmailMailer, ki uporablja PHP funkcijo [php:mail]. Primer uporabe:

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

Če želite nastaviti `returnPath` in ga strežnik še vedno prepiše, uporabite `$mailer->commandArgs = '-fMoj@email.si'`.


SmtpMailer
----------

Za pošiljanje pošte prek strežnika SMTP služi `SmtpMailer`.

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

Konstruktorju lahko predate te dodatne parametre:

* `port` - če ni nastavljen, se uporabi privzeti 25 ali 465 za `ssl`
* `timeout` - časovna omejitev za SMTP povezavo
* `persistent` - uporabi trajno povezavo
* `clientHost` - nastavitev glave Host odjemalca
* `streamOptions` - omogoča nastavitev "SSL context options":https://www.php.net/manual/en/context.ssl.php za povezavo


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

E-pošte ne pošilja neposredno, ampak pošiljanje posreduje prek niza mailerjev. V primeru, da en mailer odpove, ponovi poskus pri naslednjem. Če odpove tudi zadnji, začne znova od prvega.

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

Kot dodatne parametre v konstruktorju lahko navedemo število ponovitev in čakalni čas v milisekundah.


DKIM
====

DKIM (DomainKeys Identified Mail) je tehnologija za povečanje verodostojnosti e-pošte, ki prav tako pomaga pri odkrivanju ponarejenih sporočil. Poslano sporočilo je podpisano z zasebnim ključem domene pošiljatelja in ta podpis je shranjen v glavi e-pošte. Strežnik prejemnika primerja ta podpis z javnim ključem, shranjenim v DNS zapisih domene. S tem, ko se podpis ujema, je dokazano, da e-pošta dejansko izvira iz pošiljateljeve domene in da med prenosom sporočila ni prišlo do njegove spremembe.

Podpisovanje e-pošte lahko mailerju nastavite neposredno v [konfiguraciji |#Konfiguracija]. Če ne uporabljate dependency injection, se uporablja na ta način:

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

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


Konfiguracija
=============

Pregled konfiguracijskih možnosti za Nette Mail. Če ne uporabljate celotnega ogrodja, ampak samo to knjižnico, preberite, [kako naložiti konfiguracijo|bootstrap:].

Za pošiljanje e-pošte se standardno uporablja mailer `Nette\Mail\SendmailMailer`, ki se nadalje ne konfigurira. Lahko pa ga preklopimo na `Nette\Mail\SmtpMailer`:

```neon
mail:
	# uporabi SmtpMailer
	smtp: true       # (bool) privzeto je false

	host: ...        # (string)
	port: ...        # (int)
	username: ...    # (string)
	password: ...    # (string)
	timeout: ...     # (int)
	encryption: ...  # (ssl|tls|null) privzeto je null (ima alias 'secure')
	clientHost: ...  # (string) privzeto je $_SERVER['HTTP_HOST']
	persistent: ...  # (bool) privzeto je false

	# kontekst za povezavo s SMTP strežnikom, privzeto je stream_context_get_default()
	context:
		ssl:         # pregled možnosti na https://www.php.net/manual/en/context.ssl.php
			allow_self_signed: ...
			...
		http:        # pregled možnosti na https://www.php.net/manual/en/context.http.php
			header: ...
			...
```

Z možnostjo `context › ssl › verify_peer: false` lahko izklopite preverjanje SSL certifikatov. **Močno odsvetujemo**, da to storite, ker bo aplikacija postala ranljiva. Namesto tega "dodajte certifikate v shrambo":https://www.php.net/manual/en/openssl.configuration.php.

Za povečanje verodostojnosti lahko e-pošto podpisujemo s [tehnologijo DKIM |https://blog.nette.org/sl/sign-emails-with-dkim]:

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


Storitve DI
===========

Te storitve se dodajo v DI vsebnik:

| Ime             | Tip                        | Opis
|-----------------------------------------------------
| `mail.mailer`	  | [api:Nette\Mail\Mailer]   | [razred, ki pošilja e-pošto |#Pošiljanje e-pošte]
| `mail.signer`	  | [api:Nette\Mail\Signer]   | [DKIM podpisovanje |#DKIM]

Nette Mail

Ali nameravate pošiljati e-pošto, na primer novice ali potrditve naročil? Nette Framework ponuja potrebna orodja z zelo prijetnim API-jem. Pokazali bomo:

  • kako ustvariti e-pošto, vključno s prilogami
  • kako jo poslati
  • kako povezati e-pošto in predloge

Namestitev

Knjižnico prenesete in namestite z orodjem Composer:

composer require nette/mail

Ustvarjanje e-pošte

E-pošta je objekt razreda Nette\Mail\Message. Ustvarimo jo na primer tako:

$mail = new Nette\Mail\Message;
$mail->setFrom('Franta <franta@example.com>')
	->addTo('petr@example.com')
	->addTo('jirka@example.com')
	->setSubject('Potrditev naročila')
	->setBody("Dober dan,\nvaše naročilo je bilo sprejeto.");

Vsi vneseni parametri morajo biti v UTF-8.

Poleg navedbe prejemnika z metodo addTo() lahko navedemo tudi prejemnika kopije addCc() ali prejemnika skrite kopije addBcc(). V vseh teh metodah, vključno z setFrom(), lahko naslovnika zapišemo na tri načine:

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

Telo e-pošte, zapisano v HTML, se preda z metodo setHtmlBody():

$mail->setHtmlBody('<p>Dober dan,</p><p>vaše naročilo je bilo sprejeto.</p>');

Besedilne alternative vam ni treba ustvarjati, Nette jo bo samodejno ustvaril za vas. In če e-pošta nima nastavljenega subjekta, ga bo poskusil prevzeti iz elementa <title>.

V telo HTML lahko tudi izjemno enostavno vstavljate slike. Dovolj je, da kot drugi parameter predate pot, kjer se slike fizično nahajajo, in Nette jih bo samodejno vključil v e-pošto:

// samodejno doda /path/to/images/background.gif v e-pošto
$mail->setHtmlBody(
	'<b>Hello</b> <img src="background.gif">',
	'/path/to/images',
);

Algoritem za vstavljanje slik išče te vzorce: <img src=...>, <body background=...>, url(...) znotraj atributa HTML style in posebno sintakso [[...]].

Ali je lahko pošiljanje e-pošte še enostavnejše?

E-pošta je kot razglednica. Nikoli ne pošiljajte gesel ali drugih poverilnic po e-pošti.

Priloge

V e-pošto lahko seveda vstavljate priloge. Za to služi metoda addAttachment(string $file, ?string $content = null, ?string $contentType = null).

// vstavi datoteko /path/to/example.zip v e-pošto pod imenom example.zip
$mail->addAttachment('/path/to/example.zip');

// vstavi datoteko /path/to/example.zip v e-pošto z imenom info.zip
$mail->addAttachment('info.zip', file_get_contents('/path/to/example.zip'));

// vstavi datoteko example.txt z vsebino "Hello John!" v e-pošto
$mail->addAttachment('example.txt', 'Hello John!');

Predloge

Če pošiljate HTML e-pošto, je naravno, da jo zapišete v sistemu predlog Latte. Kako to storiti?

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

Datoteka email.latte:

<html>
<head>
	<meta charset="utf-8">
	<title>Potrditev naročila</title>
	<style>
	body {
		background: url("background.png")
	}
	</style>
</head>
<body>
	<p>Dober dan,</p>

	<p>Vaše naročilo številka {$orderId} je bilo sprejeto.</p>
</body>
</html>

Nette samodejno vstavi vse slike, nastavi subjekt glede na element <title> in ustvari besedilno alternativo HTML.

Uporaba v Nette Application

Če e-pošto uporabljate skupaj z Nette Application, tj. s presenterji, boste morda želeli v predlogah ustvarjati povezave z atributom n:href ali oznako {link}. Teh Latte privzeto ne pozna, vendar jih je zelo enostavno dodati. Povezave zna ustvarjati objekt Nette\Application\LinkGenerator, do katerega pridete tako, da si ga pustite predati z 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 predlogi nato ustvarjamo povezave, kot smo navajeni. Vse povezave, ustvarjene prek LinkGeneratorja, bodo absolutne.

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

Pošiljanje e-pošte

Mailer je razred, ki skrbi za pošiljanje e-pošte. Implementira vmesnik Nette\Mail\Mailer in na voljo je več predpripravljenih mailerjev, ki jih bomo predstavili.

Framework samodejno doda v DI vsebnik storitev tipa Nette\Mail\Mailer, sestavljeno na podlagi Konfiguracije, do katere pridete tako, da si jo pustite predati z dependency injection.

SendmailMailer

Privzeti mailer je SendmailMailer, ki uporablja PHP funkcijo mail. Primer uporabe:

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

Če želite nastaviti returnPath in ga strežnik še vedno prepiše, uporabite $mailer->commandArgs = '-fMoj@email.si'.

SmtpMailer

Za pošiljanje pošte prek strežnika SMTP služi SmtpMailer.

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

Konstruktorju lahko predate te dodatne parametre:

  • port – če ni nastavljen, se uporabi privzeti 25 ali 465 za ssl
  • timeout – časovna omejitev za SMTP povezavo
  • persistent – uporabi trajno povezavo
  • clientHost – nastavitev glave Host odjemalca
  • streamOptions – omogoča nastavitev SSL context options za povezavo

FallbackMailer

E-pošte ne pošilja neposredno, ampak pošiljanje posreduje prek niza mailerjev. V primeru, da en mailer odpove, ponovi poskus pri naslednjem. Če odpove tudi zadnji, začne znova od prvega.

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

Kot dodatne parametre v konstruktorju lahko navedemo število ponovitev in čakalni čas v milisekundah.

DKIM

DKIM (DomainKeys Identified Mail) je tehnologija za povečanje verodostojnosti e-pošte, ki prav tako pomaga pri odkrivanju ponarejenih sporočil. Poslano sporočilo je podpisano z zasebnim ključem domene pošiljatelja in ta podpis je shranjen v glavi e-pošte. Strežnik prejemnika primerja ta podpis z javnim ključem, shranjenim v DNS zapisih domene. S tem, ko se podpis ujema, je dokazano, da e-pošta dejansko izvira iz pošiljateljeve domene in da med prenosom sporočila ni prišlo do njegove spremembe.

Podpisovanje e-pošte lahko mailerju nastavite neposredno v konfiguraciji. Če ne uporabljate dependency injection, se uporablja na ta način:

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

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

Konfiguracija

Pregled konfiguracijskih možnosti za Nette Mail. Če ne uporabljate celotnega ogrodja, ampak samo to knjižnico, preberite, kako naložiti konfiguracijo.

Za pošiljanje e-pošte se standardno uporablja mailer Nette\Mail\SendmailMailer, ki se nadalje ne konfigurira. Lahko pa ga preklopimo na Nette\Mail\SmtpMailer:

mail:
	# uporabi SmtpMailer
	smtp: true       # (bool) privzeto je false

	host: ...        # (string)
	port: ...        # (int)
	username: ...    # (string)
	password: ...    # (string)
	timeout: ...     # (int)
	encryption: ...  # (ssl|tls|null) privzeto je null (ima alias 'secure')
	clientHost: ...  # (string) privzeto je $_SERVER['HTTP_HOST']
	persistent: ...  # (bool) privzeto je false

	# kontekst za povezavo s SMTP strežnikom, privzeto je stream_context_get_default()
	context:
		ssl:         # pregled možnosti na https://www.php.net/manual/en/context.ssl.php
			allow_self_signed: ...
			...
		http:        # pregled možnosti na https://www.php.net/manual/en/context.http.php
			header: ...
			...

Z možnostjo context › ssl › verify_peer: false lahko izklopite preverjanje SSL certifikatov. Močno odsvetujemo, da to storite, ker bo aplikacija postala ranljiva. Namesto tega dodajte certifikate v shrambo.

Za povečanje verodostojnosti lahko e-pošto podpisujemo s tehnologijo DKIM:

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

Storitve DI

Te storitve se dodajo v DI vsebnik:

Ime Tip Opis
mail.mailer Nette\Mail\Mailer razred, ki pošilja e-pošto
mail.signer Nette\Mail\Signer DKIM podpisovanje