Laravel 6 メールログの Quoted-printable エンコードされた件名と送信先をデコード

はじめに

Laravel にはメール送信する代わりにログファイルに残す機能があります。

しかし、ログファイル内の件名や送信元は Quoted-printable という方式でエンコードされており、一見してそれが正しいかを把握することはできません。

そこで今日は Laravel のメールログで Quoted-printable エンコードされた件名と送信元をデコードする方法を紹介します。今回使用したのは Laravel 6.18.3 です。

目次
  1. テスト用メール送信機能
  2. デコード機能
  3. おわりに

1. テスト用メール送信機能

まずは動作確認のためのメール送信機能を実装します。

/app/Http/Controllers/SampleController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Mail;

class SampleController extends Controller
{
  public function index()
  {
    Mail::send('sample.mailbody', [], function ($msg) {
      $msg->to('user@example.com', 'サンプルプログラム')
        ->subject('テストメール送信');
    });
  }
}
/resources/views/sample/mailbody.blade.php
これはテストメールです1。
これはテストメールです2。
これはテストメールです3。
/routes/web.php
// ▼これを追加
Route::get('/sample', 'SampleController@index');
.env
MAIL_DRIVER=log # ← log を指定

ブラウザで /sample にアクセスすると /storage/logs/laravel.log に下記のように出力されます。

/storage/logs/laravel.log
[2020-04-05 12:34:56] local.DEBUG: Message-ID: <1234567890@example.com>
Date: Sun, 05 Apr 2020 12:34:56 +0000
Subject: =?utf-8?Q?=E3=83=86=E3=82=B9=E3=83=88=E3=83=A1?=
 =?utf-8?Q?=E3=83=BC=E3=83=AB=E9=80=81=E4=BF=A1?=
From:
To: =?utf-8?Q?=E3=82=B5=E3=83=B3=E3=83=97=E3=83=AB?=
 =?utf-8?Q?=E3=83=97=E3=83=AD=E3=82=B0=E3=83=A9=E3=83=A0?=
 <user@example.com>
MIME-Version: 1.0
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: quoted-printable

これはテストメールです1。
これはテストメールです2。
これはテストメールです3。

2. デコード機能

本題のデコード機能です。今回はフォームとして実装しました。

/app/Http/Controllers/SampleController.php
class SampleController extends Controller
{
  // ▼ これを追加
  public function decode(Request $request)
  {
    $decStr = '';
    $rawStr = $request->input('raw_str') ?? '';
    if ($rawStr) {
      // 余分な文字列を除去
      $encStr = preg_replace("/Subject:|To:|(\s)?=\?utf-8\?Q\?|\?=|\r|\n/", '', $rawStr);
      // デコード
      $decStr = quoted_printable_decode($encStr);
    }

    return view('sample.decode', compact('decStr', 'rawStr'));
  }
  ...
}
/resources/views/sample/decode.blade.php
<form method="post">
  <div>
    <textarea name="raw_str" style="width:100%; max-width:640px; height: 150px">{{ $rawStr }}</textarea>
  </div>
  <div>
    <button type="submit">Decode</button>
    @csrf
  </div>
</form>

@if ($decStr)
  <div>{{ $decStr }}</div>
@endif
/routes/web.php
// ▼これを追加
Route::any('/sample/decode', 'SampleController@decode');

ブラウザで /sample/decode にアクセスし、laravel.log の Subject: ~To: ~ の部分をコピペして送信してみてください。その際「Subject:」や、送信元のメアド部分が含まれていてもOKです。

余談ですが、上記 routes/web.php では Route::any() を使ってますが、今回は get と post だけなので Route::match() の方が適切だったかなと思います。match() の使い方は、下記公式ドキュメントにあります。

3. おわりに

最初は js で実装しようかと思ったのですが、ちょっと調べたら手段がいくつかみつかり、検討に時間がかかりそうだったので、今回はデコード機能が標準関数で提供されている PHP を使いました。

動的に変換したい場合は上記サンプルコードをちょっと改造して Ajax でやればいいかなぁと思っています。