docs

Various Yii 3.0 related documentation

View the Project on GitHub yiisoft/docs

Mailing

Yii makes composition and sending email messages convenient with the help of yiisoft/mailer package. The package provides content composition functionality, and a basic interface for sending emails. Out of the box, the package provides a file mailer that, instead of actually sending an email, writes its contents into a file. Such a default is useful during initial application development.

To actually send emails, there is a Symfony Mailer implementation of mailer. It’s used in further examples.

Configuring mailer

The mailer service allows you to get a message instance and, after it’s filled with data, send it. An instance is usually obtained from DI container as Yiisoft\Mailer\MailerInterface.

Manually you could create an instance as follows:

use Yiisoft\Mailer\MessageBodyRenderer;
use Yiisoft\Mailer\MessageBodyTemplate;
use Yiisoft\Mailer\MessageFactory;
use Yiisoft\Mailer\Symfony\Mailer;
use Yiisoft\Mailer\Symfony\Message;

/**
 * @var \Psr\EventDispatcher\EventDispatcherInterface $dispatcher
 * @var \Symfony\Component\Mailer\Transport\TransportInterface $transport
 * @var \Yiisoft\View\View $view
 */

$template = new MessageBodyTemplate('/path/to/directory/of/view-files');

$mailer = new Mailer(
    new MessageFactory(Message::class),
    new MessageBodyRenderer($view, $template),
    $dispatcher,
    $transport,
);

The Yiisoft\Mailer\MailerInterface has 4 methods:

Creating a message

The compose() method of the mailer allows composition of the actual mail messages content via special template view files such as the following:

<?php

declare(strict_types=1);

use Yiisoft\Html\Html;

/* @var string $content */

echo Html::p(Html::encode($content));

To compose message content via view file, simply pass view name to the compose() method:

$message = $mailer->compose('view-name') // A view rendering result becomes the message body.
    ->withFrom('from@domain.com')
    ->withTo('to@domain.com')
    ->withSubject('Message subject')
;

You may pass extra view parameters to compose() method, which will be available inside the view file:

$message = $mailer->compose('greetings', [
    'user' => $user,
    'advertisement' => $advertContent,
]);

It’s also possible to pass parameters to the layouts:

$message = $mailer->compose(
    'view-name', 
    ['viewParameter' => $viewParameter],
    ['layoutParameter' => $layoutParameter],
);

You can specify different view files for HTML and plain text message contents:

$message = $mailer->compose([
    'html' => 'contact-html',
    'text' => 'contact-text',
]);

If you specify view name as a string, mailer will use the rendering result as HTML body, while it will compose plain text body by removing all HTML entities from it.

If you specify view name as null the message instance will be returned without body content.

You can wrap a view rendering result into the layout. It will work the same way as layouts in regular web application. You can use layout to set up mail CSS styles or other shared content:

<?php
/* @var $content string Mail contents as view render result */
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>

<?= $content ?>

<footer style="margin-top: 5em">
-- <br>
Mailed by Yii
</footer>

</body>
</html>

You can specify the layouts when creating an instance of the Yiisoft\Mailer\MessageBodyRenderer, which you pass to the mailer constructor.

use Yiisoft\Mailer\MessageBodyRenderer;
use Yiisoft\Mailer\MessageBodyTemplate;
use Yiisoft\Mailer\Symfony\Mailer;

/**
 * @var \Psr\EventDispatcher\EventDispatcherInterface $dispatcher
 * @var \Symfony\Component\Mailer\Transport\TransportInterface $transport
 * @var \Yiisoft\View\View $view
 * @var \Yiisoft\Mailer\MessageFactory $factory
 */
 
$template = new MessageBodyTemplate(
    '/path/to/directory/of/view-files',
    'HTML layout name', // Default to 'layouts/html'
    'Plain text layout name', // Default to 'layouts/text'
);

$renderer = new MessageBodyRenderer($view, $template);

$mailer = new Mailer($factory, $renderer, $dispatcher, $transport);

It’s also possible to change the layouts and the path of views in runtime.

$template = new \Yiisoft\Mailer\MessageBodyTemplate(
    '/path/to/directory/of/view-files',
    'HTML layout name', // Default to 'layouts/html'
    'Plain text layout name', // Default to 'layouts/text'
);

$mailer = $mailer->withTemplate($template);

Note that the withTemplate() method returns a new instance of the mailer with the specified message body template.

If you specify the layouts as empty strings, mailer won’t use the layouts.

Adding more data

After you create the message, you can add actual content to it. The message implements Yiisoft\Mailer\MessageInterface that has many useful methods for the purpose:

Note with prefix. It indicates that the method is immutable and returns a new instance of the class with the changed data. You can add data using a chain of methods:

$message = $mailer->compose(null)
    ->withFrom('from@domain.com')
    ->withTo('to@domain.com')
    ->withSubject('Message subject')
    ->withTextBody('Plain text content')
    ->withHtmlBody('<b>HTML content</b>')
;

A number of getters is also available:

Attaching files

You can add attachments to message using the withAttached() method:

use Yiisoft\Mailer\File;

// Attach a file from local file system.
$message = $message->withAttached(
    File::fromPath('/path/to/source/file.pdf'),
);

// Create an attachment content on-the-fly.
$message = $message->withAttached(
    File::fromContent('Attachment content', 'attach.txt', 'text/plain')),
);

Embedding images

You can embed images into the message content using withEmbedded() method. This method is easy to use when composing message content via view:

$imageFile = \Yiisoft\Mailer\File::fromPath('/path/to/image.jpg');

// passing the file to the view
$mailer->compose('embed-email', ['imageFile' => $imageFile])
    ->withEmbedded($imageFile)
    // ...
;

// passing the file to the layout
$mailer->compose('embed-email', [], ['imageFile' => $imageFile])
    ->withEmbedded($imageFile)
    // ...
;

Then inside the view template or layout template you can use the following code:

<img src="<?= $imageFile->cid(); ?>">

The cid() method returns the attachment ID, which should be used in img tag.

Sending a message

You can use the following code to send an email message:

$message = $mailer->compose()
   ->withFrom('from@domain.com')
   ->withTo('to@domain.com')
   ->withSubject('Message subject')
   ->withTextBody('Plain text content')
   ->withHtmlBody('<b>HTML content</b>')
;
$mailer->send($message);

You may also send several messages at once:

$messages = [];

foreach ($users as $user) {
    $messages[] = $mailer->compose()
        // ...
        ->withTo($user->email)
    ;
}

$result = $mailer->sendMultiple($messages);

This method returns an array of failed messages, or an empty array if the mailer sent all messages successfully. You can get an error using the $message->getError() method.

Implementing your own mail driver

To create your own custom mail solution, you need to create 2 classes: one for the Mailer and another one for the Message. You can use Yiisoft\Mailer\Mailer as the base class for your solution. This class already has the basic logic, which described in this guide. However, their usage isn’t mandatory, it’s enough to implement Yiisoft\Mailer\MailerInterface and Yiisoft\Mailer\MessageInterface interfaces. Then you need to implement all the abstract methods to build your solution.