Laravel 5.4 より組み込まれた Markdown を用いたメール通知 を作成します。
Markdown Mail Notificationの作成はartisan make:notification
を利用するとViewテンプレートまで自動生成できるのでおすすめです。
今回は、Laravelのデフォルトのユーザー登録時にメールアドレス検証用のメールを送信するという体でサンプルを作成します。
もくじ
なぜ Markdown ?
Laravel 5.3 で Notification が実装されましたが、これで使用できたメール通知はあまり使い勝手のいいものではありませんでした。
たとえば……
- 本文レイアウトの自由度が低い
- デフォルトで改行(≠改段落) を本文に入れられない、工夫してもイマイチ
- 本文をコード内に書くので分離が出来ず汚れる。またPHPCS等の抑制が必要に
- コードを見て確認がしにくい
これらの問題が Markdown を使ったメール通知では解消されています。
もちろん、必要に応じて従来のも使用できます。簡単な管理者宛通知メールとかならそっちの方がいいですよね。
Notificationの作成
artisan
でNotification
のクラスを作成します。今回は NewUserNotification
という名前にしました。同時に notification.user.new
というviewテンプレートを作成します。
1 |
artisan make:notification NewUserNotification --markdown=notification.user.new |
\App\Notifications\CreateUser
と resources/views/notification/user/new.blade.php
以下のような内容で生成されました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
<?php namespace App\Notifications; use Illuminate\Bus\Queueable; use Illuminate\Notifications\Notification; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; class NewUserNotification extends Notification { use Queueable; /** * Create a new notification instance. * * @return void */ public function __construct() { // } /** * Get the notification's delivery channels. * * @param mixed $notifiable * @return array */ public function via($notifiable) { return ['mail']; } /** * Get the mail representation of the notification. * * @param mixed $notifiable * @return \Illuminate\Notifications\Messages\MailMessage */ public function toMail($notifiable) { return (new MailMessage)->markdown('notification.user.new'); } /** * Get the array representation of the notification. * * @param mixed $notifiable * @return array */ public function toArray($notifiable) { return [ // ]; } } |
1 2 3 4 5 6 7 8 9 10 11 12 |
@component('mail::message') # Introduction The body of your message. @component('mail::button', ['url' => '']) Button Text @endcomponent Thanks,<br> {{ config('app.name') }} @endcomponent |
Notification の編集
今回作るのは登録完了&認証要求メールなので通知に載せれるようにしましょう。
Notification Class
Notificationの方はこんな感じ。今回はコンストラクタで値を取っていますが、セッターメソッドでももちろん構いません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
<?php namespace App\Notifications; use App\User; use Illuminate\Bus\Queueable; use Illuminate\Notifications\Notification; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; class NewUserNotification extends Notification { use Queueable; private $user; private $token; /** * Create a new notification instance. * * @param User $user * @param string $token */ public function __construct(User $user, string $token) { $this->user = $user; $this->token = $token; } /** * Get the notification's delivery channels. * * @param mixed $notifiable * * @return array */ public function via($notifiable) { return ['mail']; } /** * Get the mail representation of the notification. * * @param mixed $notifiable * * @return \Illuminate\Notifications\Messages\MailMessage */ public function toMail($notifiable) { return (new MailMessage)->markdown('notification.user.new', [ 'user' => $this->user, 'token' => $this->token, ])->subject('Larapet へようこそ!'); } } |
Notification::markdown
は第一引数にView名、第二引数にViewに渡す配列を渡します。view()
とかと基本的には一緒ですね。1
View Template
Viewテンプレートはmail::message
コンポーネントのスロットとして記述します。2 スロット内に記述したテキスト(もちろんHTMLも可)は自動的に Markdown テキスト としてパースされ、見た目の整えられたHTMLとしてメールに渡されます。また、CSSも動的に HTML 内にインライン化されます。(後述)
テキストメールでは、 Markdown のパースは行われず、HTMLタグの除去が行われたものが挿入されます。
また、デフォルトで button
, table
, panel
, promotion
といったbladeコンポーネントが用意されています。
渡されたデータを使って、とりあえずこんな感じの Markdown View テンプレートを用意しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
@component('mail::message') # 登録が完了しました。 {{$user->name}}さん、Larapet への登録ありがとうございます。 サービスのすべての機能を利用するには、 以下のリンクよりご利用のメールアドレスの確認を承認してください。 @component('mail::button', ['url' => route('mail-verify', ['token' => $token])]) 確認 @endcomponent @component('mail::panel') ☆ このメールに心当たりがありませんか?<br> その場合、お手数おかけいたしますが、このメールへの返信でお知らせいただけると幸いです。 @endcomponent Thanks,<br> {{ config('app.name') }} @endcomponent |
自分で書いておいてなんですが、心当たりのない人に返信を求めるのはダメだと思います。w
コントローラーから呼び出し
別にコントローラーでなくてもイベントリスナーでもサービスでもどっからでもいいんですけど今回はとりあえずコントローラーから呼び出します。
Laravel 5.3+においてデフォルトのapp\User
モデルは Notifiable
トレイト を継承しているのでここから生える notifiable->notify($notification)
を利用します。
notificationに渡されるnotifiableはこれ(ここではUser)になりますが、notifiableを利用するクラスはなんでも構いません。
デフォルトのRegisterController
ではアカウント作成後に RegisterController@registered
が呼び出されるのでここに書く。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/** * @param Request $request * @param User $user */ protected function registered(Request $request, $user) { $token = str_random(); // ユーザーにリレーションかけたテーブルでテキトーにトークンを保存。 // $user->verifyToken()->create(['token' => $token]); // send Notify $user->notify(new NewUserNotification($user, $token)); } |
以上で設置完了。
送信してみる
実際にユーザー登録をして、メールの送信を確認します。
なお、今回は一つ前の記事にてMailCatcherを設定済み。
登録が完了すると同時に、メールが届きました。
デザインのカスタマイズ
メールに独自のテンプレートを使いたいですよね。(メールテンプレートの構築は大変ですが。)
まずはFW内に含まれているテンプレートをプロジェクトリソースディレクトリにpublishします。
1 |
artisan vendor:publish --tag=laravel-mail |
/resources/views/vendor/mail
以下に複製されますね。
みたら分かる通り、これらのテンプレートもまた mesage.blade.php
を中心とした component チェーンで構成されています。HTMLとmarkdown(テキストメール用)で。
また、メールテンプレートなのにインラインスタイルが書かれておらず、themes/default.css
が存在することに気付くでしょう。
上にも書いたとおり、Notification で Markdown メールを送信する際にはこのCSSが CssToInlineStyles により自動的にインライン化されるんです。賢い!
またこのテーマのCSSファイル名は設定で変えれる……らしいんだけど決め打ちでアプリ内で複数使えるというわけではないようなので悩みどころ。要求するなら継承して作れってことなのだろうか。
“Markdown メール通知を作成する” への2件の返信