Mail

Wysyłanie
E-maile

Wysyłanie e-maili

Chcesz wysyłać e-maile, na przykład newslettery lub potwierdzenia zamówień? Nette Framework dostarcza niezbędnych narzędzi z bardzo przyjaznym API. Pokażemy:

  • jak utworzyć e-mail wraz z załącznikami
  • jak go wysłać
  • jak połączyć e-maile i szablony

Instalacja

Bibliotekę pobierzesz i zainstalujesz za pomocą narzędzia Composer:

composer require nette/mail

Tworzenie e-maila

E-mail jest obiektem klasy Nette\Mail\Message. Utworzymy go na przykład tak:

$mail = new Nette\Mail\Message;
$mail->setFrom('Franta <franta@example.com>')
	->addTo('petr@example.com')
	->addTo('jirka@example.com')
	->setSubject('Potwierdzenie zamówienia')
	->setBody("Dzień dobry,\nTwoje zamówienie zostało przyjęte.");

Wszystkie podawane parametry muszą być w UTF-8.

Oprócz podania odbiorcy metodą addTo(), można również podać odbiorcę kopii addCc() lub odbiorcę ukrytej kopii addBcc(). We wszystkich tych metodach, włącznie z setFrom(), adresata możemy zapisać na trzy sposoby:

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

Treść e-maila zapisaną w HTML przekazuje się metodą setHtmlBody():

$mail->setHtmlBody('<p>Dzień dobry,</p><p>Twoje zamówienie zostało przyjęte.</p>');

Nie musisz tworzyć alternatywy tekstowej, Nette wygeneruje ją automatycznie za Ciebie. A jeśli e-mail nie ma ustawionego tematu, spróbuje go pobrać z elementu <title>.

W treści HTML można również niezwykle łatwo wstawiać obrazy. Wystarczy jako drugi parametr przekazać ścieżkę, gdzie obrazy fizycznie się znajdują, a Nette automatycznie dołączy je do e-maila:

// automatycznie doda /path/to/images/background.gif do e-maila
$mail->setHtmlBody(
	'<b>Hello</b> <img src="background.gif">',
	'/path/to/images',
);

Algorytm wstawiający obrazy wyszukuje następujące wzorce: <img src=...>, <body background=...>, url(...) wewnątrz atrybutu HTML style oraz specjalną składnię [[...]].

Czy wysyłanie e-maili może być jeszcze prostsze?

E-mail jest jak pocztówka. Nigdy nie wysyłaj e-mailem haseł ani innych danych dostępowych.

Załączniki

Do e-maila można oczywiście wstawiać załączniki. Służy do tego metoda addAttachment(string $file, ?string $content = null, ?string $contentType = null).

// wstawia plik /path/to/example.zip do e-maila pod nazwą example.zip
$mail->addAttachment('/path/to/example.zip');

// wstawia plik /path/to/example.zip do e-maila o nazwie info.zip
$mail->addAttachment('info.zip', file_get_contents('/path/to/example.zip'));

// wstawia plik example.txt do e-maila z zawartością "Hello John!"
$mail->addAttachment('example.txt', 'Hello John!');

Szablony

Jeśli wysyłasz e-maile HTML, naturalnym rozwiązaniem jest zapisywanie ich w systemie szablonów Latte. Jak to zrobić?

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

Plik email.latte:

<html>
<head>
	<meta charset="utf-8">
	<title>Potwierdzenie zamówienia</title>
	<style>
	body {
		background: url("background.png")
	}
	</style>
</head>
<body>
	<p>Dzień dobry,</p>

	<p>Twoje zamówienie numer {$orderId} zostało przyjęte.</p>
</body>
</html>

Nette automatycznie wstawi wszystkie obrazy, ustawi temat według elementu <title> i wygeneruje alternatywę tekstową dla HTML.

Użycie w Nette Application

Jeśli używasz e-maili razem z Nette Application, tj. z presenterami, możesz chcieć tworzyć linki w szablonach za pomocą atrybutu n:href lub znacznika {link}. Latte domyślnie ich nie zna, ale bardzo łatwo je dodać. Tworzyć linki potrafi obiekt Nette\Application\LinkGenerator, do którego można uzyskać dostęp, prosząc o jego przekazanie za pomocą wstrzykiwania zależności:

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;
	}
}

W szablonie tworzymy linki tak, jak jesteśmy przyzwyczajeni. Wszystkie linki utworzone przez LinkGenerator będą absolutne.

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

Wysyłanie e-maila

Mailer to klasa zapewniająca wysyłanie e-maili. Implementuje interfejs Nette\Mail\Mailer i dostępnych jest kilka gotowych mailerów, które przedstawimy.

Framework automatycznie dodaje do kontenera DI usługę typu Nette\Mail\Mailer skonfigurowaną na podstawie Konfiguracja, do której można uzyskać dostęp, prosząc o jej przekazanie za pomocą wstrzykiwania zależności.

SendmailMailer

Domyślnym mailerem jest SendmailMailer, który używa funkcji PHP mail. Przykład użycia:

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

Jeśli chcesz ustawić returnPath, a serwer ciągle go nadpisuje, użyj $mailer->commandArgs = '-fMoj@email.cz'.

SmtpMailer

Do wysyłania poczty przez serwer SMTP służy SmtpMailer.

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

Konstruktorowi można przekazać następujące dodatkowe parametry:

  • port – jeśli nie jest ustawiony, użyje się domyślnego 25 lub 465 dla ssl
  • timeout – timeout dla połączenia SMTP
  • persistent – użyj połączenia trwałego
  • clientHost – ustawienie nagłówka Host klienta
  • streamOptions – umożliwia ustawienie SSL context options dla połączenia

FallbackMailer

Nie wysyła e-maili bezpośrednio, ale pośredniczy w wysyłaniu przez zestaw mailerów. W przypadku, gdy jeden mailer zawiedzie, ponawia próbę u następnego. Jeśli zawiedzie i ostatni, zaczyna ponownie od pierwszego.

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

Jako dodatkowe parametry w konstruktorze możemy podać liczbę powtórzeń i czas oczekiwania w milisekundach.

DKIM

DKIM (DomainKeys Identified Mail) to technologia zwiększająca wiarygodność e-maili, która również pomaga w wykrywaniu sfałszowanych wiadomości. Wysłana wiadomość jest podpisywana prywatnym kluczem domeny nadawcy, a ten podpis jest przechowywany w nagłówku e-maila. Serwer odbiorcy porównuje ten podpis z publicznym kluczem przechowywanym w rekordach DNS domeny. Zgodność podpisu dowodzi, że e-mail rzeczywiście pochodzi z domeny nadawcy i że podczas przesyłania wiadomości nie doszło do jej modyfikacji.

Podpisywanie e-maili można ustawić w mailerze bezpośrednio w konfiguracji. Jeśli nie używasz wstrzykiwania zależności, używa się go w ten sposób:

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

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

Konfiguracja

Przegląd opcji konfiguracyjnych dla Nette Mail. Jeśli nie używasz całego frameworka, a tylko tej biblioteki, przeczytaj, jak wczytać konfigurację.

Do wysyłania e-maili standardowo używa się mailera Nette\Mail\SendmailMailer, który nie wymaga dalszej konfiguracji. Możemy go jednak przełączyć na Nette\Mail\SmtpMailer:

mail:
	# użyje SmtpMailer
	smtp: true       # (bool) domyślnie false

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

	# kontekst do połączenia z serwerem SMTP, domyślnie stream_context_get_default()
	context:
		ssl:         # przegląd opcji na https://www.php.net/manual/en/context.ssl.php
			allow_self_signed: ...
			...
		http:        # przegląd opcji na https://www.php.net/manual/en/context.http.php
			header: ...
			...

Za pomocą opcji context › ssl › verify_peer: false można wyłączyć weryfikację certyfikatów SSL. Zdecydowanie odradzamy tego robić, ponieważ aplikacja stanie się podatna na ataki. Zamiast tego dodaj certyfikaty do magazynu.

Aby zwiększyć wiarygodność, możemy podpisywać e-maile za pomocą technologii DKIM:

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

Usługi DI

Te usługi są dodawane do kontenera DI:

Nazwa Typ Opis
mail.mailer Nette\Mail\Mailer klasa wysyłająca e-maile
mail.signer Nette\Mail\Signer Podpisywanie DKIM
wersja: 4.0