はじめに

Laravel でメール送信イベントを検知してログ出力する方法

TL;DR

  • MessageSent イベントを監視
    • app/Providers/EventServiceProvider.phpprotected $listen に設定
  • リスナ(イベントハンドラ)内でログを出力
    • getTo, getSubject で送信先、件名を取得可能
  • 要件/環境 によってはボトルネックになりかねないので注意が必要
この記事が参考になった方
ここここからチャージや購入してくれると嬉しいです(ブログ主へのプレゼントではなく、ご自身へのチャージ)
欲しいもの / Wish list

目次

  1. はじめに
  2. TL;DR
  3. 環境・条件
  4. 詳細
    1. シンプルな方法
    2. イベント検知してロギング
    3. 注意事項
      1. オーバーヘッドの考慮
      2. キュー利用時
  5. まとめ
  6. 参考文献

環境・条件

1
2
3
4
5
6
7
8
9
10
11
12
$ cat /etc/os-release
PRETTY_NAME="Ubuntu 16.04.6 LTS"

$ php -v
PHP 7.3.16-1+ubuntu16.04.1+deb.sury.org+1 (cli) (built: Mar 20 2020 13:51:21) ( NTS )

$ composer -V
Composer version 1.9.1 2019-11-01 17:20:17

$ composer info laravel/framework
name : laravel/framework
versions : * v5.7.28

詳細

メール送信ということを最低限ログに残しておきたい場合の設定方法。

シンプルな方法

一番シンプルなのは、以下のようにメール送信箇所でログを出力すること。 

1
2
3
$email = new XxxxEmail();
Mail::to($address)->send($email);
\Log::info("Mail sent to {$address}");

メリットは「必要な箇所(例えば請求通知などの重要なもの)のみにログを制限できること」、デメリットは「必要な箇所すべてに処理を実装しないといけないこと」。
(とは言え、明示的に出力箇所を絞る、というのはセキュリティ的に見るとメリットになり得るとも思う)

イベント検知してロギング

参考:


Laravel には指定したイベントに対してリスナ(イベントハンドラ)を設定し、特定の処理をさせるということが可能。そして、メール送信処理時に発火する標準のイベントも存在する。

ということで、「メール送信時に逐一ログを出力させる」ということが簡潔に記述できる。


app/Providers/EventServiceProvider.php
MessageSent イベントを検知して、MailLogger クラスで処理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 <?php

namespace App\Providers;

+use App\Listeners\MailLogger;
use Illuminate\Support\Facades\Event;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
+use Illuminate\Mail\Events\MessageSent;

class EventServiceProvider extends ServiceProvider
{
protected $listen = [
// 略
+ MessageSent::class => [
+ MailLogger::class,
+ ],
// 略
];
// 略
}

app/Listeners/MailLogger.php
新規ファイル(php artisan make:listener で作成)。

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
<?php

namespace App\Listeners;

use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;

class MailLogger
{
public function __construct()
{
//
}

public function handle($event)
{
if (!$event->data || !isset($event->data['message'])) {
return;
}

$message = $event->data['message'];
$subject = $message->getSubject();
$toAddresses = collect($message->getTo())->keys();
\Log::info("Mail sent to {$toAddresses}, subject: {$subject}");
}
}

$event->data['message']->getTo() で送信先アドレス一覧、同じように getSubject() で件名が取得可能。

getTo() は以下のような Array になっているのでキーのみを取得。

1
['foo@example.com' => null, 'bar@example.com' => null, ...]

注意事項

オーバーヘッドの考慮

同時利用者数が多い、メール送信頻度が高いなどの場合、ログ出力による影響(CPU, Disk, etc)もバカにならないはずなので、利用時には注意すること。

キュー利用時

キューを使っての送信の場合、ログ出力が反映されないことがある。

その際は、環境をリセット(再起動)すると反映されるはず。(自分は Laradock 環境で発生した)

まとめ

  • MessageSent イベントを監視
    • app/Providers/EventServiceProvider.phpprotected $listen に設定
  • リスナ(イベントハンドラ)内でログを出力
    • getTo, getSubject で送信先、件名を取得可能
  • 要件/環境 によってはボトルネックになりかねないので注意が必要

参考文献

関連記事

この記事が参考になった方
ここここからチャージや購入してくれると嬉しいです(ブログ主へのプレゼントではなく、ご自身へのチャージ)
欲しいもの / Wish list