九保すこひ@フリーランスエンジニア|累計300万PVのブログ運営中
さてさて、この間は コピペでOK!Laravelからwordpressに投稿する機能 などいくつかLaravel
のNotification
をつかった機能について記事を公開しました。
そして、Notification
としてよく使われるのがメールかと思いますが、最近は送信内容によって「あること」に気をつけないといけなくなっています。
それは・・・
特定電子メール法
です。
つまり、メルマガなどを送信する際は、事前に同意をとらないといけないというルールです。(=オプトイン)
また、一度同意を得たとしても、その後受け取りを拒否された場合はメール送信してはいけないことにもなっていたりもします。(=オプトアウト)
そこで!
今回は、Laravel
のNotification
を使って、このオプトイン/オプトアウト機能を実装してみます。
ぜひ皆さんのお役に立てると嬉しいです😊✨
開発環境: Laravel 6.x
目次
やりたいこと
今回開発する内容は次のとおりです。
- 事前に許可したユーザーだけにメール送信
- 送信されたメールには、クリックするだけで今後の受信を拒否できるオプトアウト・リンクを用意する
では実際にやってみましょう!
前提として
今回の記事は、Laravel
のログイン機能がすでにインストールされていることを前提としています。
そのため、もしインストールがまだの方は以下を参考にして準備しておいてください。
- Laravel 6.x 以上 ・・・ Laravel6.0でログイン機能を使う方法
- それ未満 ・・・ 【Laravel5.6】インストール直後にやること3点
usersテーブルにフィールドをつくる
まずはじめに、メール受信を同意しているかどうかがわかるようにemail_accepted
というフィールドをusers
テーブルに作成します。
つまり、この項目がtrue
ならメール送信OK、false
ならメール送信NGということになります。
では、以下のコマンドを実行してください。
php artisan make:migration add_email_accepted_to_users
すると、「database/migrations/****_**_**_******_add_email_accepted_to_users.php」というファイルが作成されるので、中身を以下のように変更してください。
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class AddEmailAcceptedToUsers extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::table('users', function (Blueprint $table) { $table->boolean('email_accepted') ->default(false) ->after('email'); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::table('users', function (Blueprint $table) { $table->dropColumn('email_accepted'); }); } }
変更が完了したら、マイグレーションを実行しましょう。
php artisan migrate
すると、テーブルは次のようになります。
テストデータをつくる
今回はメール受信に同意しているユーザーとそうでないユーザーが必要になりますので、Seeder
でサクッとテストデータをつくっておきましょう。
以下のコマンドを実行してください。
php artisan make:seed UsersTableSeeder
すると、「database/seeds/UsersTableSeeder.php」というファイルが作成されるので、中身を以下のように変更します。
<?php use Illuminate\Database\Seeder; class UsersTableSeeder extends Seeder { /** * Run the database seeds. * * @return void */ public function run() { $names = [ 'taro' => '太郎', 'jiro' => '次郎', 'saburo' => '三郎', 'shiro' => '四郎', 'goro' => '五郎', 'rokuro' => '六郎', 'shichiro' => '七郎', 'hachiro' => '八郎', 'kuro' => '九郎' ]; $email_accepted = true; foreach ($names as $name_en => $name_jp) { \App\User::create([ 'name' => $name_jp, 'email' => $name_en .'@example.com', 'password' => bcrypt('xxxxxxxx'), 'email_accepted' => $email_accepted ]); $email_accepted = !$email_accepted; } } }
変更が完了したら、このSeeder
を登録します。
「database/seeds/DatabaseSeeder.php」を以下のようにしてください。
<?php use Illuminate\Database\Seeder; class DatabaseSeeder extends Seeder { /** * Seed the application's database. * * @return void */ public function run() { $this->call(UsersTableSeeder::class); } }
では、以下のコマンドでSeeder
を実行しましょう。
php artisan db:seed
すると、users
テーブルは次のようになります。
※ email_accepted
が1
のものがメール送信しても大丈夫なユーザーで、0
だと拒否です。
オプトアウト機能をつくる
続いて「クリックしたら今後はメール受信を拒否する」ためのURLを先につくっていきましょう。
仕組み
例えば、以下のようなURLをつくってオプトアウトしてもいいのですが、これだとなりすましでメール拒否されることも想定されるので、今回はオプトアウトするための「ワンタイムパスワード」を個別で管理して実装することにします。
http://*****/opt-out/(ユーザーID)
モデルとテーブルをつくる
以下のコマンドを実行してください。
php artisan OptOutTicket -m
するとモデルとマイグレーションのファイルがそれぞれ作成されるので、「database/migrations/****_**_**_******_create_opt_out_tickets_table.php」の中身を次のように変更してください。
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreateOptOutTicketsTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('opt_out_tickets', function (Blueprint $table) { $table->bigIncrements('id'); $table->unsignedBigInteger('user_id'); $table->string('uuid'); $table->timestamps(); $table->foreign('user_id') ->references('id')->on('users') ->onDelete('cascade'); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('opt_out_tickets'); } }
ではマイグレーションを実行してテーブルを作成しましょう。
php artisan migrate
実行後、テーブルはこうなります。
ルートをつくる
続いて、オプトアウトするためのURLをつくります。
「routes/web.php」に以下のルートを追加してください。
Route::get('opt_out/{uuid}', 'OptOutController@update')->name('opt_out');
コントローラーをつくる
先ほどルートで設定したコントローラーをつくります。
以下のコマンドを実行してください。
php artisan make:controller OptOutController
すると、「app/Http/Controllers/OptOutController.php」というファイルが作成されるので、中身を以下のように変更します。
<?php namespace App\Http\Controllers; use App\Notifications\NewsLetter; use Illuminate\Http\Request; class OptOutController extends Controller { public function update($uuid) { $ticket = \App\OptOutTicket::where('uuid', $uuid)->first(); if(is_null($ticket)) { abort(404); } // ユーザーの受信設定を「拒否」へ変更 $user = \App\User::find($ticket->user_id); $user->email_accepted = false; $user->save(); // オプトアウトのデータを削除 $ticket->delete(); return 'メール受信設定を「拒否」に変更しました。'; } }
※ 今回はメインがオプトイン/オプトアウトなのでビューは使わず単にテキストをreturn
しています。
Notificationをつくる
ではやっと本題のNotification
でメール送信する部分をつくっていきます。
なお、今回はメールマガジンを送信することを想定して実装していきます。
まずは以下のコマンドでNewsLetter
という名前のNotification
ファイルを作成してください。
php artisan make:notification NewsLetter
すると、「app/Notifications/NewsLetter.php」というファイルが作成されるので、中身を次のように変更してください。
<?php namespace App\Notifications; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Notification; use Illuminate\Support\Str; class NewsLetter extends Notification { private $view = ''; use Queueable; /** * Create a new notification instance. * * @return void */ public function __construct($view) { $this->view = $view; } /** * Get the notification's delivery channels. * * @param mixed $notifiable * @return array */ public function via($notifiable) { if(!$notifiable->email_accepted) { // メール受信を拒否している場合 return []; } return ['mail']; } /** * Get the mail representation of the notification. * * @param mixed $notifiable * @return \Illuminate\Notifications\Messages\MailMessage */ public function toMail($notifiable) { // オプトアウトのデータを作成する $ticket = new \App\OptOutTicket(); $ticket->user_id = $notifiable->id; $ticket->uuid = Str::uuid(); $ticket->save(); return (new MailMessage) ->view($this->view, [ 'user' => $notifiable, 'ticket' => $ticket ]); } /** * Get the array representation of the notification. * * @param mixed $notifiable * @return array */ public function toArray($notifiable) { return [ // ]; } }
なお、この中で重要なのは次の3ヶ所です。
メール受信を拒否している場合はキャンセルする
まず、メール受信を拒否している(つまり、users
テーブルのemail_accepted
がfalse
の場合)はメール送信をキャンセルしなければいけませんが、やり方は以下のようにvia()
の返り値を空白の配列にすることで実装します。
public function via($notifiable) { if(!$notifiable->email_accepted) { return []; } return ['mail']; }
メールを送信する部分
toMail()
内でメール送信するコード自体は通常のNotification
と同じですが、重要なのは$notifiable
が、このケースの場合はusers
テーブルのデータになるという部分です。
そのため、$notifiable->id
は、ユーザーIDを取得できますし、$notifiable->name
はユーザーの名前を取得することができます。
ビューを指定する部分
今回はメールマガジンを想定しているため、内容が毎回変わるという前提でコードを書きました。そのため、NewsLetter
は以下のようにビューを指定する形で実行することになります。
new NewsLetter('emails.news_letter')
ビューをつくる
では、メールマガジンの内容をビューとしてつくりましょう。
「resources/views/emails/news_letter.blade.php」というファイルを作成してください。
{{ $user->name }} さん、こんにちは。<br><br> (メールマガジンの内容)<br> (メールマガジンの内容)<br> (メールマガジンの内容)<br><br> <a href="{{ url('/your/event/url') }}">詳しい情報はこちら</a><br><br> なお、今後同様のメールを受信しない場合は<a href="{{ route('opt_out', $ticket->uuid) }}">こちら</a>
テストしてみる
では、実際にメールを送信してみましょう!
うまくいっているかをチェックするために次のルートを「routes/web.php」に追加してください。
Route::get('opt_out_test', 'OptOutController@test');
そして、「app/Http/Controllers/OptOutController.php」にテスト用のメソッドtest()
を追加します。
<?php namespace App\Http\Controllers; use App\Notifications\NewsLetter; use Illuminate\Http\Request; class OptOutController extends Controller { // 省略 public function test() { $users = \App\User::all(); $view = 'emails.news_letter'; \Notification::send($users, new NewsLetter($view)); } }
これで、「http://******/opt_out_test」にアクセスすると全てのユーザーに対してNotification
が実行されることになります。
なお、チェックする項目は以下の2つです。
- メール受信に同意している人だけに送信できているか(拒否している人のメール送信をキャンセルできているか)
- メールにかかれている「拒否リンク」をクリックしたらメール受信を拒否する設定にできるか
では、まずはテーブル内を確認してみましょう。
赤枠の人たちがメール受信に同意しているユーザーです。
では実際に「http://******/opt_out_test」にアクセスしてメール送信してみましょう!
送信された全メールです。
To
のメールアドレスを見てみると、受信に同意したユーザーだけにメール送信できていることが分かります😊✨
では、次に「太郎さん」に送信されたメールの中にある「拒否リンク」をクリックして、うまく処理ができるかチェックしてみましょう。
クリックすると、以下のような表示になりました。
では、念のためテーブルも確認してみましょう。
はい!「太郎さん」のemail_accepted
がfalse
になっています。
全てうまくいきました😊✨
ダウンロードする
今回実際に開発したソースコード一式を以下からダウンロードすることができます。
※ ただし、ログイン機能のインストールなどはご自身で行ってください。
Laravel】オプトイン/オプトアウトのメール送信機能おわりに
ということで、今回はLaravel
を使って「オプトイン/オプトアウト」機能をつくってみました。
これを応用すれば、メールマガジンを送信する機能だけでなく、イベント情報のお知らせやバーゲンの通知などもできると思います。
ぜひみなさんのサイトでも活用してみてくださいね。
ではでは〜!