Mail

Wysyłanie
E-maile

Wysyłanie e-maili

Czy zamierzasz wysyłać maile takie jak newslettery czy potwierdzenia zamówień? Nette Framework dostarcza niezbędnych narzędzi z bardzo ładnym API. Zobaczmy:

  • jak stworzyć wiadomość e-mail zawierającą załączniki
  • jak go wysłać
  • jak łączyć e-maile i szablony

Instalacja

Pobierz i zainstaluj bibliotekę za pomocą Composera:

composer require nette/mail

Tworzenie wiadomości e-mail

E-mail jest obiektem klasy Nette\Mail\Message. Możemy go utworzyć w taki sposób:

$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.");

Wszystkie parametry muszą być w języku UTF-8.

Oprócz określenia odbiorcy za pomocą metody addTo(), można również określić odbiorcę kopii addCc(), lub odbiorcę ukrytej kopii addBcc(). We wszystkich tych metodach, łącznie z setFrom(), można określić odbiorcę na trzy sposoby:

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

Ciało maila zapisane w HTML jest przekazywane za pomocą metody setHtmlBody():

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

Nie musisz tworzyć tekstu alternatywnego, Nette wygeneruje go automatycznie za Ciebie. A jeśli mail nie ma ustawionego tematu, to spróbuje go pobrać z elementu <title>.

Niezwykle łatwe jest również wstawianie obrazów do ciała HTML. Wystarczy przekazać ścieżkę, gdzie fizycznie znajdują się obrazki jako drugi parametr, a Nette automatycznie dołączy je do maila:

// automatycznie dodaje /path/to/images/background.gif do wiadomości e-mail
$mail->setHtmlBody(
	'<b>Witam</b> <img src="background.gif">',
	'/path/to/images',
);

Algorytm wstawiający obrazy szuka tych wzorców: <img src=...>, <body background=...>, url(...) wewnątrz atrybutu HTML style oraz specjalna składnia [[...]].

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

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

Załączniki

Do maila można oczywiście dodać załączniki. Odbywa się to za pomocą metody addAttachment(string $file, string $content = null, string $contentType = null).

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

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

// wstawia do maila plik example.txt o treści "Witaj John!".
$mail->addAttachment('example.txt', 'Hello John!');

Szablony

Jeśli wysyłasz e-maile w formacie HTML, warto napisać je 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>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 automatycznie osadza wszystkie zdjęcia, ustawia temat według elementu <title> i generuje tekstową alternatywę dla HTML.

Zastosowanie w aplikacji Nette

Jeśli używasz e-maili w połączeniu z Nette Application, tj. prezenterami, możesz chcieć tworzyć linki w szablonach za pomocą atrybutu n:href lub tagu {link}. Nie są one domyślnie znane przez Latte, ale są bardzo łatwe do dodania. Obiekt Nette\Application\LinkGenerator może tworzyć linki, do których możesz uzyskać dostęp, przekazując je za pomocą zastrzyku 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;
	}
}

Następnie tworzymy linki w szablonie tak jak jesteśmy do tego przyzwyczajeni. Wszystkie linki utworzone za pośrednictwem LinkGeneratora będą miały charakter bezwzględny.

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

Wysyłanie wiadomości e-mail

Mailer to klasa służąca do wysyłania wiadomości e-mail. Implementuje on interfejs Nette\Mail\Mailer, a także istnieje kilka gotowych mailerów, które przedstawimy.

Framework automatycznie dodaje usługę taką jak Nette\Mail\Mailer zbudowaną na podstawie konfiguracji do kontenera DI, i do której możesz uzyskać dostęp, mając ją przekazaną do ciebie za pomocą zastrzyku 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 = '-fMuj@email.cz'.

SmtpMailer

Aby wysłać pocztę przez serwer SMTP, należy użyć SmtpMailer.

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

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

  • port – jeśli nie jest ustawiony, to domyślnie 25 lub 465 jest używany dla ssl
  • timeout – timeout dla połączenia SMTP
  • persistent – użyj trwałego połączenia
  • clientHost – ustawienie nagłówka Host Client
  • streamOptions – pozwala na ustawienie opcji kontekstu SSL dla połączenia

FallbackMailer

Nie wysyła maili bezpośrednio, ale pośredniczy w wysyłce poprzez zestaw mailerów. Jeśli jeden mailer się nie powiedzie, ponawia próbę następnego. Jeśli ostatni się nie powiedzie, zaczyna się od pierwszego.

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

Jako dodatkowe parametry w konstruktorze możemy podać liczbę retries oraz czas oczekiwania w milisekundach.

DKIM

DKIM (DomainKeys Identified Mail) to technologia zwiększania wiarygodności e-maili, która pomaga również w wykrywaniu fałszywych wiadomości. Wysłana wiadomość jest podpisywana kluczem prywatnym domeny nadawcy, a podpis ten jest przechowywany w nagłówku wiadomości e-mail. Serwer odbiorcy dopasowuje ten podpis do klucza publicznego przechowywanego w rekordach DNS domeny. Dzięki dopasowaniu podpisu udowadnia się, że e-mail rzeczywiście pochodzi z domeny nadawcy i że wiadomość nie została zmodyfikowana podczas transmisji.

Możesz skonfigurować podpisywanie wiadomości e-mail bezpośrednio w konfiguracji mailera. Jeśli nie używasz wtrysku zależności, jest on używany 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; // nebo SmtpMailer
$mailer->setSigner($signer);
$mailer->send($mail);

Konfiguracja

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

Domyślnie do wysyłania e-maili używany jest mailer Nette\Mail\SendmailMailer, który nie jest dalej konfigurowany. Możemy jednak przełączyć ją na Nette\Mail\SmtpMailer:

mail:
	# use 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 jest $_SERVER['HTTP_HOST']
	persistent: ...  # (bool) domyślnie jest false

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

Za pomocą opcji context › ssl › verify_peer: false możemy wyłączyć uwierzytelnianie certyfikatu SSL. Silnie radzimy, aby tego nie robić, ponieważ spowoduje to, że aplikacja będzie podatna na uszkodzenia. Zamiast tego dodaj certyfikaty do repozytorium.

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

Usługi te są dodawane do kontenera DI:

Nazwa Typ Opis
mail.mailer Nette\Mail\Mailer klasa wysyłania wiadomości e-mail
mail.signer Nette\Mail\Signer Podpisywanie DKIM
wersja: 4.0