HTMLでデザインされたメールは読みやすく、視覚的に訴求しやすいというメリットがあります。ですが、多様なメーラーに対応するため通常のwebページとは異なるコーディングが必要であり、レスポンシブも考慮すると1通のメールを作成するのも大変です。

そこで、簡単にレスポンシブなHTMLメールが作成できるMJMLというツールをLaravel10.xのプロジェクトで試してみました。

MJMLをプロジェクトにインストール

ベースとなるメールクラスは前回作成したものを使用し、MJMLを使えるよう修正を加えてゆきます。

Laravel用にパッケージが用意されていますので、まずはこちらをインストールします。

$ composer require asahasrabuddhe/laravel-mjml

次に、フロントエンド用のライブラリをインストールします。

npm install --save mjml

ここまででインストールは完了です。

ビューファイル作成

次に、メールの本文となるビューファイルを作成します。

MJMLではmj-bodymj-columnなどの独自タグを使って画面を組み立てます。テンプレートドキュメントにたくさん使用例が載っていますので、ご参照ください。オンラインエディタではリアルタイムに表示を確認できるので便利です。

今回はシンプルに、ナビゲーションとカラムだけのメールを作成しました。先にPCビューの完成形をお見せします。

このHTMLメールをMJMLで記述したものが、以下となります。

<mjml>
  <mj-head>
    <mj-attributes>
      <mj-all font-family="Ubuntu, Helvetica, Arial, sans-serif" />
      <mj-class name="nav-item" font-size="14px" color="#fff" />
      <mj-class name="column" font-size="16px" color="#333" align="center" padding="25px" font-weight="bold" />
    </mj-attributes>
  </mj-head>
  <mj-body background-color="#FFC3BA">
    <!-- header navigation -->
    <mj-section background-color="#ef6451">
      <mj-column>
        <mj-navbar base-url="https://example.com" hamburger="hamburger" ico-color="#ffffff">
          <mj-navbar-link mj-class="nav-item" href="/page1">メニュー1</mj-navbar-link>
          <mj-navbar-link mj-class="nav-item" href="/page2">メニュー2</mj-navbar-link>
          <mj-navbar-link mj-class="nav-item" href="/page3">メニュー3</mj-navbar-link>
          <mj-navbar-link mj-class="nav-item" href="/page4">メニュー4</mj-navbar-link>
        </mj-navbar>
      </mj-column>
    </mj-section>
    <!-- 3column section -->
    <mj-section background-color="#FAD74D" padding-bottom="15px">
      <mj-column>
        <mj-text mj-class="column">カラムA</mj-text>
      </mj-column>
      <mj-column>
        <mj-text mj-class="column">カラムB</mj-text>
      </mj-column>
      <mj-column>
        <mj-text mj-class="column">カラムC</mj-text>
      </mj-column>
    </mj-section>
  </mj-body>
</mjml>

大きく、mj-headmj-bodyで構成されています。

背景色や文字色など、個別に指定したいCSSはインラインでの記述が可能です。ですが、全てのCSSをインラインで書くとコードが読みにくくなったり修正が大変になりますので、繰り返しになるものは mj-head > mj-attributes 内でまとめて指定しました。

その際2つのタグを使用しています。mj-allは、全体のフォントと文字色の指定に。またmj-classでは、クラスとCSSの定義をしています。これはメニューリストのような複数あるアイテムに便利です。

mj-classの記述を上のコードから抜粋すると、mj-head内ではnav-itemクラスを以下のように定義しています。

      <mj-class name="nav-item" font-size="14px"/>

そしてこのnav-itemをbody内で使用するには、適用させたいタグにmj-classを指定すればOKです。以下のようになります。

      <mj-navbar-link mj-class="nav-item" href="/page1">メニュー1</mj-navbar-link>

また本文の要素は、セクションごとに mj-section(セクション) > mj-column(列) > 中身の要素 という形に配置してゆきます。mj-columnの中は、メニューボタンにはmj-navbar、テキストにはmj-text、のように要素に応じたタグが用意されているのでこれらを使って画面を構成します。

レスポンシブなメールを送信

最後に、Mailableの修正です。修正箇所は2つで、1つはuseするMailableを今回インストールしたパッケージのクラスへ変更。2つめは、contentの記述です。

以下は、修正前のコードです。

...
use Illuminate\Mail\Mailable;
...
    public function content(): Content
    {
        return new Content(
            view: 'view.name',
        );
     }
...

修正後は、以下のようになります。mjmlbuildMjmlViewといった新しいメソッドが使えるようになるのでそちらを使用します。

...
use Asahasrabuddhe\LaravelMJML\Mail\Mailable;
...
    public function content(): Content
    {
        return new Content(
            view: $this->mjml('emails.mjml')->buildMjmlView()['html'],
        );
     }
...

この記述だけで、先ほどのMJMLタグがHTMLに変換されます。早速Tinkerでメールを送信してみましょう。

$ php artisan tinker
Psy Shell v0.11.20 (PHP 8.1.17 — cli) by Justin Hileman
> use App\Mail\TestMail;
> Mail::to('mjml-test@example.com')->send(new TestMail);
= Illuminate\Mail\SentMessage {#6325}

PCビューは先ほどと同じなので省略です。モバイル表示では、どうでしょうか。

PCビューでは横並びだったナビゲーションはハンバーガーメニューに、3カラムは縦並びに変わりました。ちゃんと画面サイズに最適化された表示になっていますね。

ソースを見てみると、以下のようなHTMLに変換されています。全体はもっと長いので、MJMLを使うことでコードをだいぶ簡略化できることがわかります。

By hmatsu