Laravel 5.3でMailはどのように変わったか


https://laravel.com/docs/5.3/mail

## これまでのMail

これまでのメール送信はこんな感じで実装していました。

````
Mail::send('emails.reminder', ['user' => $user], function ($m) use ($user) {
    $m->from('hello@app.com', 'Your Application');

    $m->to($user->email, $user->name)->subject('Your Reminder!');
});
````

多くのケースでは、この実装は非常に不便です。
通常システムからメールを送る場合、メッセージのテキストと、FROM/TOなどのヘッダのパターンはある程度紐付いているので、
自前で`Sendable`とかのインターフェイスをを実行して送信可能なメッセージオブジェクトを作成するケースが多かったかと思います。

## 5.3 からのMail

`Mailable`インターフェイスの搭載で送信処理はよりシンプルになった。

````
Mail::to($request->user())->send(new OrderShipped($order));
````

上記は`OrderShipped`という`Mailable`インターフェイスを備えるクラスを用いた実装の例。

toの他にもcc,bccの設定も行える。

````
Mail::to($request->user())
    ->cc($moreUsers)
    ->bcc($evenMoreUsers)
    ->send(new OrderShipped($order));
````

### Mailable

Mailableの雛形は make コマンドで用意することが可能。

````
$ php artisan make:mail OrderShipped
````

lumen などartisanが使えない環境向けに、雛形を掲載しておく。

````
<?php

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;

class OrderShipped extends Mailable
{
    use Queueable, SerializesModels;

    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
        return $this->view('view.name');
    }
}
````

build は送信前に実行される処理なので、ここでテキストの設定などを行っていけば良い。

`view` `text` は共にbladeのテンプレート名を入力してテンプレートを指定することが出来る。
HTML メールとテキストメールで別のテンプレートを使用する際にはこれらを利用すると便利。

第二引数にテンプレート変数を指定可能だが、代入形式なので`view`,`text`で二度値を指定した時、前のものは消える(マージされない。) 
対して変数登録専用の`with`を使うときれいにマージされるので、段階的に変数を登録したいときはそちらを使うと良い。
(ちなみにテンプレート変数領域はtext とviewで共用となっている。)

宛先指定用に`from` `to`があったり、添付ファイル用の`attach`があったりとなんでも出来る。

ちなみにbuildは送信直前まで実行されないため、Maile::to 周りの処理のほうが先に実行されるが、内容は一応マージされる模様。

## 内部の実装

`Mailer::send` の中身は、以下のような形になっています。

https://github.com/illuminate/mail/blob/5.3/Mailer.php#L170

````
public function send($view, array $data = [], $callback = null)
{
    if ($view instanceof MailableContract) {
        return $view->send($this);
    }
    ...
````

第一引数に`MailableContract`を渡してあげれば`$this`を渡しつつ,`MailableCon`
tract`の`send`を実行しようとします。

ちなみに`to`とかの実装はこんな感じ。

https://github.com/illuminate/mail/blob/5.3/Mailer.php#L121

````
public function to($users)
{
    return (new MailableMailer($this))->to($users);
}
````

`MailableMailer`は`Mailer`を保持しつつ、`to`や`from`情報を保持してくれるコンテナみたいな機能をもっている。

`Mailable::send`の実装は次のような形

https://github.com/illuminate/mail/blob/master/Mailable.php#L107

````
public function send(MailerContract $mailer)
{
    Container::getInstance()->call([$this, 'build']);
    $mailer->send($this->buildView(), $this->buildViewData(), function ($message) {
        $this->buildFrom($message)
             ->buildRecipients($message)
             ->buildSubject($message)
             ->buildAttachments($message)
             ->runCallbacks($message);
    });
}
````

`Mailable`にbuildを実行しつつ、5.2以前の形式でメールの送信処理を行う。

`buildView`や`buildViewData`は`view` `text` `with`メソドで指定したテンプレート、変数をよしなにしてくれる関数となっている。

`buildFrom`は などは宛先情報などをセットするための関数です。