メモ LaravelPHPネットワーク

LaravelのMailableでHTMLメールとプレーンテキストメール両方を送信する方法

2022.03.07

こんにちはjunです。Laravelでメール機能が伴う内容を実装していたときに、HTMLメールだけでなくプレーンテキストメールでも送付してほしいとの用件がありました。Laravelではメールを送信する時は大抵、Mailableを使用しますがその時に両方送る方法が意外と日本語でなかったので忘備録として記事を作りました。プレーンテキストとはなんぞや?というとこから解説するので、対策法をさっさと知りたい方は「Mailabeでのプレーンテキストの設定」を見てください。

プレーンテキストメールとHTMLメールの違い

HTMLメールは名の通り、HTMLの記法で作成されたメールです。生のデータにはHTMLが書かれており、メールクライアント側でHTMLをレンダリングしてメール内容を表示します。リッチなメールを送付できるというメリットがあります。デメリットとして環境やデバイスによってはメールが全く見れなくなることです。

HTMLメールが見れない環境や昔はプレーンテキストメールといった、メモ帳で書いた様な本当に純粋な文字だけのメールを利用します。メリットはどの端末でも必ず表示はできるので、確実に届けたいメールなどにはプレーンテキストがおすすめです。例えばGithubの二段階認証メールはContent-Type: text/plain; charset=UTF-8とプレーンテキストで必ず送られ、毎週のお知らせメールはその両方が送られています。

どうやって確認できるの?

気になる方は届いたメールのソースを見てみましょう。Gmailであれば「画面右側の点々」をクリックして「メッセージのソースを表示」をクリックしますと、メールのヘッダやボディを確認できます。そのとき

Content-Type: text/plain; charset=UTF-8があれば、プレーンテキストメール形式で送付され、Content-Type: text/html; charset=UTF-8があればHTMLメールです。きちんとHTMLの記述があるのを確認してみてください。

なぜ両方ともつけることができるの?

ちなみにメールにはHTMLとプレーン両方ともつけることは可能です。その場合環境に合わせてHTML・プレーンのものが表示されます。その仕組みはソースの中に Content-Type: multipart/alternative; boundary=のような記述をしようすることです。これはメールの内容を複数の形式で送りますよというヘッダ要素です。HTMLの内容とプレーンテキストの内容がソースでどこで分けているかを示しています。

boundary="..." のboundaryの中身にある文字を境界として使用します。Laravelの場合はSwiftを使用しているので _=_swift_1646631221_d7511bd8d439c84878b3339aaec563e1_=_という文字(一部分はランダムです)が境界として使用され、

Content-Type: multipart/alternative; boundary="_=_swift_1646631221_d7511bd8d439c84878b3339aaec563e1_=_"

--_=_swift_1646631221_d7511bd8d439c84878b3339aaec563e1_=_
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable

(1)HTMLの記述’

--_=_swift_1646631221_d7511bd8d439c84878b3339aaec563e1_=_
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: quoted-printable

(2)プレーンテキストの記述

--_=_swift_1646631221_d7511bd8d439c84878b3339aaec563e1_=_

上記の様な記述があると思います。ここで境界の文字を用いて2つの形式の内容を記述し、メールを送付してクライアントは適宜そのソースを汲み取って表示しています。

Mailabeでのプレーンテキストの設定

前置きがながくなりましたが、LaravelのMailableでは以下の様に指定します。

/**
    * Build the message.
    *
    * @return $this
*/
public function build()
{
    return $this->view('mail.registration',[
        'applay_user_name'=>$name,
    ])->text('mail.registration_text',[ // これ!
        'applay_user_name'=>$name,
    ])
    ->subject('登録を受け付けました。');
}

text()メソッドを使用することで前述の解説の様にプレーンテキスト用のmultipartを入れ込んでくれます。なお、引数はview()メソッドと同じでテンプレートファイルとデータを渡すことができます。この記法はLaravel5.3から利用できます。

参考 Laravel9 Mail

テンプレートの記述とファイル構成のすすめ

私の場合は以下の様な構成とファイル名でメールテンプレートを管理しています。

views
│
├── mail
    ├── master.blade.php
    ├── master_text.blade.php
    ├── register.blade.php
    └── register_text.blade.php

まずviewsでmail用のテンプレートを格納するディレクトリ を作成し、そしてHプレーンテキスト用のテンプレートはTML用のものに_textをつけておきます。そしてmaster.blade.phpはレイアウトやHTMLのスタイルを定義しています。同じようにプレーン用のレイアウトファイルのmaster_text.blade.phpを用意しておくといいです。

register.blade.php
{{$name}}<p>いつもご利用いただきありがとうございます。</p>
...
register_text.blade.php
{{$name}}様
いつもご利用いただきありがとうございます。
...

notifiableの場合

これはLaravel8しか確認していませんが、Notifiableで使用されるMailMessageの場合はプレーンテキストが自動的に作成されていました。以下の様にtoMail()を作成しておけばHTMLもプレーンも送付されていました。

public function toMail($notifiable)
{
    return (new MailMessage)
                ->subject('メールアドレスが変更されました')
                ->line("いつもご利用いただきありがとうございます。")
                ->line('連絡用メールアドレスの変更を受け付けました。')
                ->line('※本メールは送信専用です。ご返信いただいても対応できませんのでご了承ください。')
                ->line('※本メールにお心当たりがない場合は、恐れ入りますが破棄していただきますようお願いいたします。');
}
Copyright © 2021 jun. All rights reserved.