
九保すこひです(フリーランスのITコンサルタント、エンジニア)
さてさて、この間は コピペで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
を使って「オプトイン/オプトアウト」機能をつくってみました。
これを応用すれば、メールマガジンを送信する機能だけでなく、イベント情報のお知らせやバーゲンの通知などもできると思います。
ぜひみなさんのサイトでも活用してみてくださいね。
ではでは〜!