tutorial-mailing.md 7.2 KB
Newer Older
Klimov Paul committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
Mailing
=======

> Note: This section is under development.

Yii supports composition and sending of the email messages. However, the framework core provides
only the content composition functionality and basic interface. Actual mail sending mechanism should
be provided by the extension, because different projects may require its different implementation and
it usually depends on the external services and libraries.

For the most common cases you can use [yii2-swiftmailer](https://github.com/yiisoft/yii2/tree/master/extensions/swiftmailer) official extension.


Configuration
-------------

Mail component configuration depends on the extension you have chosen.
In general your application configuration should look like:

```php
return [
    //....
    'components' => [
24
        'mailer' => [
Klimov Paul committed
25 26 27 28 29 30 31 32 33 34
            'class' => 'yii\swiftmailer\Mailer',
        ],
    ],
];
```


Basic usage
-----------

35
Once 'mailer' component is configured, you can use the following code to send an email message:
Klimov Paul committed
36 37

```php
38
Yii::$app->mailer->compose()
Klimov Paul committed
39 40 41 42 43 44 45 46 47 48 49 50
    ->setFrom('from@domain.com')
    ->setTo('to@domain.com')
    ->setSubject('Message subject')
    ->setTextBody('Plain text content')
    ->setHtmlBody('<b>HTML content</b>')
    ->send();
```

In above example method `compose()` creates an instance of the mail message, which then is populated and sent.
You may put more complex logic in this process if needed:

```php
51
$message = Yii::$app->mailer->compose();
Klimov Paul committed
52 53 54 55 56 57 58 59 60 61 62
if (Yii::$app->user->isGuest) {
    $message->setFrom('from@domain.com')
} else {
    $message->setFrom(Yii::$app->user->identity->email)
}
$message->setTo(Yii::$app->params['adminEmail'])
    ->setSubject('Message subject')
    ->setTextBody('Plain text content')
    ->send();
```

63
> Note: each 'mailer' extension comes in 2 major classes: 'Mailer' and 'Message'. 'Mailer' always knows
Klimov Paul committed
64 65 66 67 68 69 70 71
  the class name and specific of the 'Message'. Do not attempt ot instantiate 'Message' object directly -
  always use `compose()` method for it.

You may also send several messages at once:

```php
$messages = [];
foreach ($users as $user) {
72
    $messages[] = Yii::$app->mailer->compose()
Klimov Paul committed
73 74 75
        // ...
        ->setTo($user->email);
}
76
Yii::$app->mailer->sendMultiple($messages);
Klimov Paul committed
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
```

Some particular mail extensions may benefit from this approach, using single network message etc.


Composing mail content
----------------------

Yii allows composition of the actual mail messages content via special view files.
By default these files should be located at '@app/mail' path.

Example mail view file content:

```php
<?php
use yii\helpers\Html;
use yii\helpers\Url;

95 96 97 98

/* @var $this \yii\web\View view component instance */
/* @var $message \yii\mail\BaseMessage instance of newly created mail message */

Klimov Paul committed
99 100 101 102 103 104 105 106
?>
<h2>This message allows you to visit out site home page by one click</h2>
<?= Html::a('Go to home page', Url::home('http')) ?>
```

In order to compose message content via view file simply pass view name to the `compose()` method:

```php
107
Yii::$app->mailer->compose('home-link') // message body becomes a view rendering result here
Klimov Paul committed
108 109 110 111 112 113 114 115 116
    ->setFrom('from@domain.com')
    ->setTo('to@domain.com')
    ->setSubject('Message subject')
    ->send();
```

You may pass additional view parameters to `compose()` method, which will be available inside the view files:

```php
117
Yii::$app->mailer->compose('greetings', [
Klimov Paul committed
118 119 120 121 122
    'user' => Yii::$app->user->identity,
    'advertisement' => $adContent,
]);
```

Klimov Paul committed
123 124 125
You can specify different view files for HTML and plain text message contents:

```php
126
Yii::$app->mailer->compose([
Klimov Paul committed
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
    'html' => 'contact-html',
    'text' => 'contact-text',
]);
```

If you specify view name as a scalar string, its rendering result will be used as HTML body, while
plain text body will be composed by removing all HTML entities from HTML one.

View rendering result can be wrapped into the layout, which an be setup using [[yii\mail\BaseMailer::htmlLayout]]
and [[yii\mail\BaseMailer::textLayout]]. It will work the same way like layouts in regular web application.
Layout can be used to setup mail CSS styles or other shared content:

```php
<?php
use yii\helpers\Html;

143
/* @var $this \yii\web\View view component instance */
Carsten Brandt committed
144
/* @var $message \yii\mail\MessageInterface the message being composed */
145
/* @var $content string main view render result */
Klimov Paul committed
146 147 148 149 150
?>
<?php $this->beginPage() ?>
<!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>
151
    <meta http-equiv="Content-Type" content="text/html; charset=<?= Yii::$app->charset ?>" />
Klimov Paul committed
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
    <style type="text/css">
        .heading {...}
        .list {...}
        .footer {...}
    </style>
    <?php $this->head() ?>
</head>
<body>
    <?php $this->beginBody() ?>
    <?= $content ?>
    <div class="footer">With kind regards, <?= Yii::$app->name ?> team</div>
    <?php $this->endBody() ?>
</body>
</html>
<?php $this->endPage() ?>
```

Klimov Paul committed
169 170 171 172

File attachment
---------------

Klimov Paul committed
173 174 175
You can add attachments to message using methods `attach()` and `attachContent()`:

```php
176
$message = Yii::$app->mailer->compose();
Klimov Paul committed
177 178 179 180 181 182 183 184

// Attach file from local file system:
$message->attach('/path/to/source/file.pdf');

// Create attachment on-the-fly
$message->attachContent('Attachment content', ['fileName' => 'attach.txt', 'contentType' => 'text/plain']);
```

Klimov Paul committed
185 186 187 188

Embed images
------------

Klimov Paul committed
189 190 191 192 193
You can embed images into the message content using `embed()` method. This method returns the attachment id,
which should be then used at 'img' tag.
This method is easy to use when composing message content via view file:

```php
194
Yii::$app->mailer->compose('embed-email', ['imageFileName' => '/path/to/image.jpg'])
Klimov Paul committed
195 196 197 198 199 200 201 202 203 204 205
    // ...
    ->send();
```

Then inside view file you can use following code:

```php
<img src="<?= $message->embed($imageFileName); ?>">
```


206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
Testing and debugging
---------------------

Developer often a to check, what actual emails are sent by application, what was their content and so on.
Such ability is granted by Yii via `yii\mail\BaseMailer::useFileTransport`. If enabled, this option enforces
saving mail message data into the local files instead of regular sending. These files will be saved under
`yii\mail\BaseMailer::fileTransportPath`, which is '@runtime/mail' by default.

> Note: you can either save messages to the file or send them to actual recipients, but can not do both simultaneously.

Mail message file can be opened by regular text file editor, so you can browse actual message headers, content and so on.
This mechanism amy prove itself, while debugging application or running unit test.

> Note: mail message file content is composed via `\yii\mail\MessageInterface::toString()`, so it depends on actual
  mail extension you are using in your application.


Klimov Paul committed
223 224
Creating your own mail solution
-------------------------------
Klimov Paul committed
225

Klimov Paul committed
226 227 228 229 230
In order 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 `yii\mail\BaseMailer` and `yii\mail\BaseMessage` as a base classes for your solution. These classes
already contains basic logic, which is described in this guide. However, their usage is not mandatory, it is enough
to implement `yii\mail\MailerInterface` and `yii\mail\MessageInterface` interfaces.
Qiang Xue committed
231
Then you need to implement all abstract methods to build you solution.