【Rails】人間が読める形式でメールの件名と本文をログに出力する方法 (Beta)

## 困っていること

ActionMailerからメールを送信すると、ログにメールの送信内容が出力されます。しかし、件名（Subject）や本文はエンコードされていて、内容が確認できません。

```
Devise::Mailer#reset_password_instructions: processed outbound mail in 11.8ms
Delivered mail 64b379aa26c5c_60f3440c-546@jit-m1.local.mail (3.4ms)
Date: Sun, 16 Jul 2023 14:01:30 +0900
From: please-change-me-at-config-initializers-devise@example.com
Reply-To: please-change-me-at-config-initializers-devise@example.com
To: foo@example.com
Message-ID: <64b379aa26c5c_60f3440c-546@jit-m1.local.mail>
Subject: =?UTF-8?Q?=E3=83=91=E3=82=B9=E3=83=AF=E3=83=BC=E3=83=89=E3=81=AE=E5=86=8D=E8=A8=AD=E5=AE=9A=E3=81=AB=E3=81=A4=E3=81=84=E3=81=A6?=
Mime-Version: 1.0
Content-Type: text/html;
 charset=UTF-8
Content-Transfer-Encoding: base64

PHA+Zm9vQGV4YW1wbGUuY29t5qeYPC9wPg0KDQo8cD7jg5Hjgrnjg6/jg7zj
g4nlho3oqK3lrprjga7kvp3poLzjgpLlj5fjgZHjgZ/jgZ/jgoHjgIHjg6Hj
g7zjg6vjgpLpgIHkv6HjgZfjgabjgYTjgb7jgZnjgILkuIvjga7jg6rjg7Pj
gq/jgYvjgonjg5Hjgrnjg6/jg7zjg4njga7lho3oqK3lrprjgYzjgafjgY3j
gb7jgZnjgII8L3A+DQoNCjxwPjxhIGhyZWY9Imh0dHA6Ly9leGFtcGxlLmNv
bS91c2Vycy9wYXNzd29yZC9lZGl0P3Jlc2V0X3Bhc3N3b3JkX3Rva2VuPWVp
c19YSmh4YXkzWW5kOVZ4aTFyIj7jg5Hjgrnjg6/jg7zjg4nlpInmm7Q8L2E+
PC9wPg0KDQo8cD7jg5Hjgrnjg6/jg7zjg4nlho3oqK3lrprjga7kvp3poLzj
gpLjgZfjgabjgYTjgarjgYTloLTlkIjjgIHjgZPjga7jg6Hjg7zjg6vjgpLn
hKHoppbjgZfjgabjgY/jgaDjgZXjgYTjgII8L3A+DQo8cD7jg5Hjgrnjg6/j
g7zjg4njga7lho3oqK3lrprjga/jgIHkuIrjga7jg6rjg7Pjgq/jgYvjgonm
lrDjgZfjgYTjg5Hjgrnjg6/jg7zjg4njgpLnmbvpjLLjgZnjgovjgb7jgafl
rozkuobjgZfjgb7jgZvjgpPjgII8L3A+DQo=
```

## こうなると嬉しい
人間が読める形式で件名と本文をログに出力したい。

## 解決策（version 2）
`config/initializers/action_mailer.rb`に以下のコードを書いて保存します。

```ruby:config/initializers/action_mailer.rb
class EmailDeliveryObserver
  def self.delivered_email(message)
    Rails.logger.debug(<<~TEXT)
      ==== decoded subject ====
      #{message.subject}
      ==== decoded body ====
      #{message.body.encoded}
    TEXT
  end
end

Rails.application.configure do
  config.action_mailer.observers = %w[EmailDeliveryObserver]
end
```

上記のコードではメールのオブザーバーを利用しています。オブザーバーについては下記Railsガイドの説明を参照してください。

https://railsguides.jp/action_mailer_basics.html#%E3%83%A1%E3%83%BC%E3%83%AB%E3%81%AE%E3%82%AA%E3%83%96%E3%82%B6%E3%83%BC%E3%83%90%E3%83%BC

## ~~解決策（version 1）~~

~~`config/initializers/action_mailer.rb`に以下のコードを書いて保存します。~~

モンキーパッチを当てるより、オブザーバーを使った方がスマートなのでversion 2のコードを推奨します。


```ruby 
ActiveSupport.on_load(:action_mailer) do
  module ActionMailer
    class Base < AbstractController::Base
      class << self
        prepend(Module.new do
          private
          def set_payload_for_mail(payload, mail)
            super
            payload[:body] = mail.body.encoded
          end
        end)
      end
    end

    class LogSubscriber < ActiveSupport::LogSubscriber
      prepend(Module.new do
        def deliver(event)
          super

          debug do
            <<~TEXT
            ==== decoded subject ====
            #{event.payload[:subject]}

            ==== decoded body ====
            #{event.payload[:body]}
            TEXT
          end
        end
      end)
    end
  end
end
```

## 実行結果

こうすると、元々のログ出力に加えて、デコードされた件名と本文がログに出力されます。

```
Devise::Mailer#reset_password_instructions: processed outbound mail in 4.4ms
Delivered mail 64b37a9640100_61ac715c45954@jit-m1.local.mail (2.2ms)
Date: Sun, 16 Jul 2023 14:05:26 +0900
From: please-change-me-at-config-initializers-devise@example.com
Reply-To: please-change-me-at-config-initializers-devise@example.com
To: foo@example.com
Message-ID: <64b37a9640100_61ac715c45954@jit-m1.local.mail>
Subject: =?UTF-8?Q?=E3=83=91=E3=82=B9=E3=83=AF=E3=83=BC=E3=83=89=E3=81=AE=E5=86=8D=E8=A8=AD=E5=AE=9A=E3=81=AB=E3=81=A4=E3=81=84=E3=81=A6?=
Mime-Version: 1.0
Content-Type: text/html;
 charset=UTF-8
Content-Transfer-Encoding: base64

PHA+Zm9vQGV4YW1wbGUuY29t5qeYPC9wPg0KDQo8cD7jg5Hjgrnjg6/jg7zj
g4nlho3oqK3lrprjga7kvp3poLzjgpLlj5fjgZHjgZ/jgZ/jgoHjgIHjg6Hj
g7zjg6vjgpLpgIHkv6HjgZfjgabjgYTjgb7jgZnjgILkuIvjga7jg6rjg7Pj
gq/jgYvjgonjg5Hjgrnjg6/jg7zjg4njga7lho3oqK3lrprjgYzjgafjgY3j
gb7jgZnjgII8L3A+DQoNCjxwPjxhIGhyZWY9Imh0dHA6Ly9leGFtcGxlLmNv
bS91c2Vycy9wYXNzd29yZC9lZGl0P3Jlc2V0X3Bhc3N3b3JkX3Rva2VuPVlO
M05kVFBpYVdKOG5wMzZoTVd4Ij7jg5Hjgrnjg6/jg7zjg4nlpInmm7Q8L2E+
PC9wPg0KDQo8cD7jg5Hjgrnjg6/jg7zjg4nlho3oqK3lrprjga7kvp3poLzj
gpLjgZfjgabjgYTjgarjgYTloLTlkIjjgIHjgZPjga7jg6Hjg7zjg6vjgpLn
hKHoppbjgZfjgabjgY/jgaDjgZXjgYTjgII8L3A+DQo8cD7jg5Hjgrnjg6/j
g7zjg4njga7lho3oqK3lrprjga/jgIHkuIrjga7jg6rjg7Pjgq/jgYvjgonm
lrDjgZfjgYTjg5Hjgrnjg6/jg7zjg4njgpLnmbvpjLLjgZnjgovjgb7jgafl
rozkuobjgZfjgb7jgZvjgpPjgII8L3A+DQo=

==== decoded subject ====
パスワードの再設定について
==== decoded body ====
<p>foo@example.com様</p>

<p>パスワード再設定の依頼を受けたため、メールを送信しています。下のリンクからパスワードの再設定ができます。</p>

<p><a href="http://example.com/users/password/edit?reset_password_token=YN3NdTPiaWJ8np36hMWx">パスワード変更</a></p>

<p>パスワード再設定の依頼をしていない場合、このメールを無視してください。</p>
<p>パスワードの再設定は、上のリンクから新しいパスワードを登録するまで完了しません。</p>
```

## ⚠️免責事項
- Deviseのパスワード再設定メールで動作確認しただけなので、それ以外のメールでちゃんと動く保証はありません。
- このコードを適用して本番環境等で何か致命的な問題が発生しても、筆者は責任を負いかねます🙏

### 動作確認バージョン

- Rails 7.0.4.2
- Ruby 3.2.1