Sending E-mails

Almost every web application needs to send e-mails, whether it's newsletter or order confirmation. That's why Nette Framework provides necessary tools. This tutorial will show you how to:

  • create e-mail
  • send it
  • add attachments
  • use templates in e-mails
  • create links

Never send passwords or any other login credentials by e-mail.

Example of creating an e-mail using Nette\Mail\Message class:

use Nette\Mail\Message;

$mail = new Message;
$mail->setFrom('John <john@example.com>')
    ->addTo('peter@example.com')
    ->addTo('jack@example.com')
    ->setSubject('Order Confirmation')
    ->setBody("Hello, Your order has been accepted.");

All parameters must be encoded in UTF-8.

And sending:

use Nette\Mail\SendmailMailer;

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

In presenters and services we don't create mailer manually, but we will require the service of type Nette\Mail\IMailer using DI.

In addition to specifying recipient with addTo(), it's possible to specify recipient of copy with addCc() and recipient of blind copy: addBcc(). In all these methods, including setFrom(), we can specify addressee in three ways:

$mail->setFrom('john.doe@example.com');
$mail->setFrom('john.doe@example.com', 'John Doe');
$mail->setFrom('John Doe <john.doe@example.com>');

HTML content can be defined using setHtmlBody() method:

$mail->setHtmlBody('<b>Sample HTML</b> <img src="background.gif">');

Embedded images can be inserted using $mail->addEmbeddedFile('background.gif'), but it is not necessary. Why? Because Nette Framework finds and inserts all files referenced in the HTML code automatically. This behavior can be supressed by adding false as a second parameter of the setHtmlBody() method.

If a HTML e-mail has no plain-text alternative, it will be automatically generated. And if it has no subject set, it will be taken from the <title> element.

Attachments

Adding attachments to the e-mail is simple. In order to attach a file, we use addAttachment method:

// attaches example.zip to the e-mail
$mail->addAttachment('path/to/example.zip');

// attaches new example.txt file with "Hello John!" in it
$mail->addAttachment('example.txt', 'Hello John!');

// attaches example.zip renamed to info.zip
$mail->addAttachment('info.zip', file_get_contents('path/to/example.zip'));

Templates

The real power comes in combination with Latte templating system:

$latte = new Latte\Engine;
$params = [
    'orderId' => 123,
];

$mail = new Message;
$mail->setFrom('John <john@example.com>')
    ->addTo('jack@example.com')
    ->setHtmlBody($latte->renderToString('email.latte', $params));

File email.latte:

<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Order Confirmation</title>
    <style>
    body {
        background: url("background.png")
    }
    </style>
</head>
<body>
    <p>Hello,</p>

    <p>Your order number {$orderId} has been accepted.</p>
</body>
</html>

The Latte Engine itself doesn't provide {link} macro. LinkGenerator provides {link} and n:href macros in templates.

class MailSender
{
    /** @var Nette\Application\LinkGenerator */
    private $linkGenerator;

    /** @var Nette\Application\UI\ITemplateFactory */
    private $templateFactory;

    public function sendEmail()
    {
        $template = $this->createTemplate();

        $template->name = $order->getName();
        $template->setFile(__DIR__ . '/email.latte');

        $mail = new Message;
        $mail->setHtmlBody($template);
    }

    protected function createTemplate()
    {
        $template = $this->templateFactory->createTemplate();
        $template->getLatte()->addProvider('uiControl', $this->linkGenerator);

        return $template;
    }
}

In the template, link is created like in a normal template. All links create over LinkGenerator are absolute:

Mailers

Default mailer, class responsible for e-mail sending, is SendmailMailer, whitch uses PHP function mail.

You can also create your own mailer – it's a class implementing Nette\Mail\IMailer interface.

SmtpMailer

To send mail via the SMTP server, use SmtpMailer.

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

FallbackMailer

It does not send email, but sends them through a set of mailers. In the event that one mailer fails, it repeats the attempt at the next one. If the last one fails, it starts again from the first one.

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

Other parameters in the constructor include the number of repeat and waiting time (in miliseconds).