Laravel(6.x)の会員登録メールのデザインをカスタマイズする

前回の記事でmailtrapサービスを使ったメールの送信テストを
書いたのですが見た目がLaravelデフォルトなので
もっと独自性のある見た目にしたいといった場合にどう対応すれば
いいのかを今回はご紹介したいと思います

前回の記事はこちら

この記事をすすめるとどうなる

Laravelデフォルト状態で送ったメールのデザインや文言が変更できます

日本語化の設定をする

前回はLaravelの設定がデフォルトそのままだったため
ログイン機能のメッセージや、メールの文言が英語になっていました
まず、画面にでてくるメッセージを日本語化するところから始めます
(すでに日本語化済みの人は読み飛ばしていただいてOKです)

config/app.phpを修正する

config/app.phpにタイムゾーン、ロケールなどが設定されているので変更します
それぞれキーの値を以下のように変更しましょう

    'timezone' => 'Asia/Tokyo',
    'locale' => 'ja',
    'fallback_locale' => 'ja',

resources/lang/jaを追加する

resources/langディレクトリを確認すると、デフォルトではenのみ配置されています
日本語化するためにenと同じ位置に ja という名前でディレクトリを
作成していくのですが日本語翻訳ファイルを提供してくれているので利用しましょう
https://readouble.com/laravel/6.x/ja/passwords-php.html

今回、会員登録メール関係の箇所のみ日本語化します
プロジェクトフォルダに移動し以下コマンドを実行します

cd project
php -r "copy('https://readouble.com/laravel/6.x/ja/install-ja-lang-files.php', 'install-ja-lang.php');"
php -f install-ja-lang.php
php -r "unlink('install-ja-lang.php');"

これで再度resources/langフォルダを確認してみるとjaフォルダが
追加されています

カスタムメールを作成する

日本語化設定だけでは、メールは日本語になりません
(画面に表示される「パスワードリセットメールを送信しました。」は日本語になっているはずです)

カスタムNotificationを作成する

題名やメールにあるメッセージ(今回はパスワードリセットを対象とします)
は以下のフレームワークのファイルでハードコードされています

vendor/laravel/framework/src/Illuminate/Auth/Notifications/ResetPassword.php
    /**
     * Build the mail representation of the notification.
     *
     * @param  mixed  $notifiable
     * @return \Illuminate\Notifications\Messages\MailMessage
     */
    public function toMail($notifiable)
    {
        if (static::$toMailCallback) {
            return call_user_func(static::$toMailCallback, $notifiable, $this->token);
        }

        return (new MailMessage)
            ->subject(Lang::get('Reset Password Notification'))
            ->line(Lang::get('You are receiving this email because we received a password reset request for your account.'))
            ->action(Lang::get('Reset Password'), url(route('password.reset', ['token' => $this->token, 'email' => $notifiable->getEmailForPasswordReset()], false)))
            ->line(Lang::get('This password reset link will expire in :count minutes.', ['count' => config('auth.passwords.'.config('auth.defaults.passwords').'.expire')]))
            ->line(Lang::get('If you did not request a password reset, no further action is required.'));
    }

Notificationsが通知用(メール含む)に使われるフォルダですが
これを別途用意します
php artisanコマンドでさくっと作成できます、以下コマンドを実行してください

php artisan make:notification ResetPassword

上記コマンドを実行するとファイルが以下の場所に作成されていると思います

ファイルの中身の、toMailメソッドを見てみましょう
このメソッドを日本語対応していきます

    public function toMail($notifiable)
    {
        return (new MailMessage)
                    ->line('The introduction to the notification.')
                    ->action('Notification Action', url('/'))
                    ->line('Thank you for using our application!');
    }

以下のようにしました

    public function toMail($notifiable)
    {
        return (new MailMessage)
                    ->subject('ぱすわーどりせっとです')
                    ->greeting('こんにちは')
                    ->line('これはパスワードリセットです')
                    ->action('パスワードをリセットする', url('/'))
                    ->line('このメールは60分以内にほげほげ');
    }

Userモデルを修正する

では次にモデル(App/User.php)を修正します
Notificationsを用意しただけでは適用されないので、作ったものを
使うように変更します

以下2箇所を修正します
useとsendPasswordResetNotificationメソッドの追加です

<?php

namespace App;

〜割愛〜
use App\Notifications\ResetPassword; // 作ったResetPasswordをuseする

class User extends Authenticatable
{
〜割愛〜

    /**
     * パスワードリセット通知の送信をオーバーライド
     *
     * @param  string  $token
     * @return void
     */
    public function sendPasswordResetNotification($token)
    {
        $this->notify(new ResetPassword($token));
    }
}

sendPasswordResetNotificationメソッドをオーバーライドすることで
用意したResetPasswordで送信されます

一度送信して確認する

ここまでで日本語化の対応ができたので一度送信して確認してみましょう

パスワードリセット画面でメールを入れて送信

送信しましたメッセージは日本語化になっていてOK、メールも確認してみます

メールの内容が(ある程度)日本語になりました
ただ、Fromの Laravel< no-reply…>となっていたり
本文のタイトルがLaravelだったり
lineの最後にRegards,Laravelがあったり、、とじゃあ使えるレベルか
というと不十分です
さらに対応していきます

APP_NAMEを変更する

まずLaravelと表示されている箇所をHello Projectに変えたいと思います

これはAPP_NAMEから取得して設定しています
.envファイルのAPP_NAME(一番上にあると思います)を
Laravel → ”Hello Project”に変更してみましょう

再度パスワードリセットメールを送信してみると

Fromと題名のところが Laravel → Hello Projectに変更されました!
ただ、まだ本文のRegardsのところはそのまま残っています

メール本文をカスタムする

メール本文は現状のままではデフォルトになっています
メール全体的なカスタムと一部のみを変更する方法がありますが
ここでは全体的なカスタムのみ紹介します

フレームワークからテンプレートをartisanコマンドで
コピーしてきてそれを修正するというのがLaravelのやり方です
以下コマンドで本文に使われているテンプレートをコピーします

php artisan vendor:publish --tag=laravel-notifications

上記コマンドを実行すると以下のようにメッセージが出て作成されます

$ php artisan vendor:publish --tag=laravel-notifications
Copied Directory [/vendor/laravel/framework/src/Illuminate/Notifications/resources/views] To [/resources/views/vendor/notifications]
Publishing complete.

/resources/views/vendorを見てみるとnotificationsディレクトリが作られ
中に、email.blade.phpが作成されています

中を見ると本文に使われていた部分が記載されています

@component('mail::message')
{{-- Greeting --}}
@if (! empty($greeting))
# {{ $greeting }}
@else
@if ($level === 'error')
# @lang('Whoops!')
@else
# @lang('Hello!')
@endif
@endif

{{-- Intro Lines --}}
@foreach ($introLines as $line)
{{ $line }}

@endforeach

{{-- Action Button --}}
@isset($actionText)
<?php
    switch ($level) {
        case 'success':
        case 'error':
            $color = $level;
            break;
        default:
            $color = 'primary';
    }
?>
@component('mail::button', ['url' => $actionUrl, 'color' => $color])
{{ $actionText }}
@endcomponent
@endisset

{{-- Outro Lines --}}
@foreach ($outroLines as $line)
{{ $line }}

@endforeach

{{-- Salutation --}}
@if (! empty($salutation))
{{ $salutation }}
@else
@lang('Regards'),<br>
{{ config('app.name') }}
@endif

{{-- Subcopy --}}
@isset($actionText)
@slot('subcopy')
@lang(
    "If you’re having trouble clicking the \":actionText\" button, copy and paste the URL below\n".
    'into your web browser:',
    [
        'actionText' => $actionText,
    ]
) <span class="break-all">[{{ $displayableActionUrl }}]({{ $actionUrl }})</span>
@endslot
@endisset
@endcomponent

PHPファイルなのにいつもと違う!と思うかもしれませんが、
これはLaravelのViewで使われるBladeの component(コンポーネント)
というものを使っていることとマークダウン(# で始まるものが見出し)や
マークアップ(<span>などのタグ)で記述されているだけです

ここから、本文で残っていた
Salutation(結びの挨拶)とSubcopy(ボタンが使えないときのメッセージ)
を修正していきます

Salutationは日本語に書き換えてもいいですし、ここでは取り除いて対応します
Subcopyも変更して以下のようにしました

〜割愛〜
{{-- Outro Lines --}}
@foreach ($outroLines as $line)
{{ $line }}

@endforeach

{{-- Subcopy --}}
@isset($actionText)
@slot('subcopy')
@lang(
    " \":actionText\" ボタンが使えない場合は以下のURLをコピーしてブラウザURLに貼ってアクセスしてください\n",
    [
        'actionText' => $actionText,
    ]
) <span class="break-all">[{{ $displayableActionUrl }}]({{ $actionUrl }})</span>
〜割愛〜

再度メールを送信してみます

Regardsは削除され、ボタンが使えないときのメッセージも変更できました!

メールデザインをカスタムする

最後にメールのデザインをカスタムしたいと思います
ここではHello Project(元Laravel)とタイトルがあった部分の
文字色と背景色を変更したいと思います
これもphp artisanでコマンドを実行します

php artisan vendor:publish --tag=laravel-mail

上記コマンドを実行すると以下のようにメッセージが出て作成(フレームワーク内からコピー)されます

$ php artisan vendor:publish --tag=laravel-mail
Copied Directory [/vendor/laravel/framework/src/Illuminate/Mail/resources/views] To [/resources/views/vendor/mail]
Publishing complete.

resources/viewsを見てみると、vendor/mailが追加されています
その下にはhtml、textのフォルダがはいっていると思います

これはそれぞれ、HTML形式のメール、TEXT形式のメールでカスタム
できるようになっているためです

HTML形式メールのデザインを変更するので、htmlフォルダに
ある部分を変更します

今回のタイトル部分はheader.blade.phpが対象ファイルですが
デザインは themesフォルダにあるdefault.cssが対象です

ちなみにメールのデザイン箇所を特定するときも、mailtrapを利用できます
HTML Sourceタブでみるとタグ、スタイルがどうなっているのか
確認できるのでおすすめです!

default.cssと HTML Sourceを見比べてあたりをつけましょう

文字色は.header a のcolorを変更します

〜割愛〜
/* Header */

.header {
    padding: 25px 0;
    text-align: center;
}

.header a {
    color: #f6b1ff; /* ピンク色に変更してみました */
    font-size: 19px;
    font-weight: bold;
    text-decoration: none;
    text-shadow: 0 1px 0 white;
}
〜割愛〜

背景色は wrapper を変更します

〜割愛〜
/* Layout */

.wrapper {
    background-color: #fbffc1; /* 薄い黄色に変更してみました */
    margin: 0;
    padding: 0;
    width: 100%;
    -premailer-cellpadding: 0;
    -premailer-cellspacing: 0;
    -premailer-width: 100%;
}
〜割愛〜

保存して再度送信してみましょう
デザインが変更できました!
(wrapperはフッターにも使われているデザインで上下がかわっています)

まとめ

長くなってしまいましたが、ここまで見てくださった方ありがとうございました
Laravelのメール機能は非常に導入しやすいですが、
日本語対応させたりデザインをかえたりとカスタムしたいといったときには
少し変更を加える必要がでてきます

それでも、比較的楽に変更できるのが良いところなんでしょうね