📨

Laravel 新 Mailable を試してみる

2022/10/25に公開約4,600字

前書き

Laravel 9.35 から、新 Mailable が使えるようになりましたので、それを試してみました。

https://github.com/laravel/framework/pull/44462

気が早い事に、コマンド使って Mailable 作成すると、新 Mailable の雛形で出来上がりますので、早めに慣れておくと良さそうです。

日本語ドキュメントも既に新 Mailable に説明が変わっています。

本題

という事で、コマンドで新 Mailable を作ります。(以降、.env でメールの設定が適切に行われ、users テーブルには、データが入っている想定で行きます)

以下のコマンドを叩きます。

php artisan make:mail ContactMail

でも今回は、裏技で
php artisan make:mail ContactMail -m emails.contact

今回は裏技を使って作成していきます。-m は、markdown の略で、-m テンプレ名とすると、そのテンプレを作ってくれます。(中身は、マークダウンのサンプルが書かれている)

また、出来上がる Mailable ファイルにも「markdown: 'emails.contact',」と埋まっています↓

以下、上記コマンドで作成された ContactMail.php です。(紙面の都合上、DocBlock 略)

ContactMail.php
<?php

namespace App\Mail;

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

class ContactMail extends Mailable
{
    use Queueable, SerializesModels;

    public function __construct()
    {
        //
    }

    public function envelope()
    {
        return new Envelope(
            subject: 'Contact Mail',
        );
    }

    public function content()
    {
        return new Content(
            markdown: 'emails.contact', // ← ここ!
        );
    }

    public function attachments()
    {
        return [];
    }
}

さて、上記で必要な箇所を編集して行きます。

ContactMail.php
    /**
     * Get the message envelope.
     *
     * @return \Illuminate\Mail\Mailables\Envelope
     */
    public function envelope()
    {
        return new Envelope(
            subject: 'Contact Mail',
+           from: 'foo@example.net',
+           to: 'foo@example.net',
        );
    }

    /**
     * Get the message content definition.
     *
     * @return \Illuminate\Mail\Mailables\Content
     */
    public function content()
    {
        return new Content(
-           markdown: 'emails.contact',
+           text: 'emails.contact',
        );
    }

Envelope の所に、差出人などを適宜設定します。ここは、PHP8 からの新機能の名前付き引数(Named Arguments)の書き方になっていますね。

上記の書き方とは別に、インスタンス化した Envelope に ->from() などのメソッドを呼び出す事もできます↓

    public function envelope()
    {
        $envelope = new Envelope();

        return $envelope->subject('Contact Mail')
            ->from('foo@example.net')
            ->to('foo@example.net');
    }

また、メールは、実際はマークダウンではなく単なるテキストで送るため、text: と変更しています。(この作業を忘れないように。最初から --text というコマンドオプションがあったら良いのですが、残念ながらありません。)

せっかくですので、メール本文にユーザー名が記載されるようにします。
コンストラクタを以下のように変更します。

ContactMail.php
use App\Models\User;

    public function __construct(public User $user)
    {
        //
    }

コンストラクタで、user プロパティを初期化しています。
PHP8 からの Constructor property promotion を使うと上記で済むので楽ですね。

旧式の Mailable でもそうですが、public なプロパティは、テンプレート(ビュー)側に自動で渡るので、明示して渡す必要はありません。

テンプレートは、取りあえず以下で。

{!! $user->name !!} です。

web.php は、以下の感じ。

web.php
Route::get('/', function () {
    $user = User::first();

    Mail::send(new ContactMail($user));

    return view('welcome');
});

これで、トップページにアクセスすると、「Walter Bernhard です。」などと名前が書かれたメールが届きます。簡単ですね。

で、何が良くなったのか。

その辺は人それぞれかも知れませんが、私が感じたのは、旧式 Mailable の build() メソッド内で from とか to とか設定していると、下記のようなテストは通りませんでしたが、新 Mailable では通るので、そこは少し嬉しいですね。

    public function test_example()
    {
        \Mail::fake();

        $response = $this->get('/');

        Mail::assertSent(ContactMail::class, function ($mail) {
            return $mail->hasTo('foo@example.net') &&
                   $mail->hasFrom('foo@example.net');
        });
    }

ところで、名前付き引数(Named Arguments)って…。

話は少し逸れますが、上記でも見たように、新 Mailable では、名前付き引数(Named Arguments)機能が利用されたりします。(ドキュメントもそうなっている)

本来、Laravelでは、名前付き引数を使うのは、「サポートしませんよ。自己責任でよろしく。」的な感じになっていますが、この新 Mailable では、それがある意味サポートされている感じになっています。実際、ソースコード上にも、「@named-arguments-supported」とアノテーションが書かれていたり。

まぁ、「新 Mailable は、ちょっと例外なのね」、と理解していましたが、最近微妙にそうでない所でも、ドキュメント上で名前付き引数が書かれ始めているんですね…。

data_set($data, 'products.desk.price', 200, overwrite: false);

data_set

Benchmark::dd(fn () => User::count(), iterations: 10); // 0.5 ms

Benchmark

「おいおい、自己責任と言いつつ、ドキュメントにサラッと書くのか…💦」的な。(笑

実際、引数(パラメータ)の名前は「綴りミス」などによりサクッと変更されたりもしますので、その辺お気を付けて。

雑感

という事で、新 Mailable を軽く試してみました。
新機能や新しい書き方の情報を追うのも大変ですが、頑張って行きましょう。

ミスや間違い等ありましたら、コメント下さい🙇‍♂️

Discussion

ログインするとコメントできます