Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Sending mail

A site sends emails: a registration confirmation, a notice about a new comment, a message from the contact form. In Yii the Yii::$app->mailer component is responsible for this. In the standard project it works through the yiisoft/yii2-symfonymailer package, which is already installed.

Where mail is configured

The component is described in config/web.php:

// config/web.php
'components' => [
    'mailer' => [
        'class' => \yii\symfonymailer\Mailer::class,
        'viewPath' => '@app/mail',
        'useFileTransport' => true,
    ],
],

While useFileTransport is true, emails go nowhere and are saved as files in the runtime/mail folder. This is the development mode: you can check emails without the risk of sending them to real people.

The first email

// controllers/PostController.php
public function actionNotify(): string
{
    $sent = Yii::$app->mailer->compose()
        ->setFrom('blog@example.com')
        ->setTo('anna@example.com')
        ->setSubject('A new post in the blog')
        ->setTextBody('A new post has appeared in the blog.')
        ->send();
 
    return $sent ? 'Email sent' : 'Sending failed';
}

Open /post/notify and a file with the .eml extension appears in the runtime/mail folder. A mail program or a text editor opens it. The send() method returns true on success.

An email from a view

Email views live in the mail folder. Create mail/new-post.php:

<?php
// mail/new-post.php
 
use yii\helpers\Html;
use yii\helpers\Url;
?>
 
<h1><?= Html::encode($post->title) ?></h1>
 
<p>A new post has appeared in the blog.</p>
 
<p><?= Html::a('Read', Url::to(['post/view', 'id' => $post->id], true)) ?></p>

The view name and the data are passed to compose():

Yii::$app->mailer->compose('new-post', ['post' => $post])
    ->setFrom('blog@example.com')
    ->setTo('anna@example.com')
    ->setSubject('New post: ' . $post->title)
    ->send();

The email gets the markup from the view, wrapped in the common email layout mail/layouts/html.php. The second argument of Url::to(), true, makes the URL absolute: a relative link /posts/5 does not work in an email.

Message methods

MethodWhat it sets
setFrom('blog@example.com')The sender
setTo(['anna@example.com', 'ivan@example.com'])One or several recipients
setSubject('Subject')The subject
setTextBody('Text')Plain text content
setHtmlBody('<b>Text</b>')Content with markup
attach('/path/to/file.pdf')An attachment

Real sending

On a server the file mode is switched off and a mail server is specified:

'mailer' => [
    'class' => \yii\symfonymailer\Mailer::class,
    'viewPath' => '@app/mail',
    'useFileTransport' => false,
    'transport' => [
        'dsn' => 'smtp://user:password@smtp.example.com:587',
    ],
],

The dsn string contains the user name, the password, the address and the port of the SMTP server; the mail service provides them.

Common mistake

Emails "do not arrive" although send() returns true: this means useFileTransport is still on, and they pile up in runtime/mail. Check this setting on the server. The opposite mistake is more dangerous: switch it off on a developer's computer with a copy of the real database, and test emails go to real users.

Thanks for reading!

Donate to the site — we work hard for you.