Ruby
Rails
ActionMailer
RubyOnRails

[ActionMailer]添付ファイルの有無にかかわらずメールの本文を取得する

概要

ActionMailerで送信したメールの本文を添付ファイルの有無にかかわらず取得します1

メール本文の内容をテストするときなどにお使いください。

コード

def get_mail_body(mail)
  parts = mail.body.parts

  # partsにさらにマルチパートメールが含まれる(=添付ファイルがある)場合はメール部分のみを取得
  if parts.map(&:multipart?).inject(:|)
    multipart_mails = parts.find(&:multipart?).parts 
  else
    multipart_mails = parts
  end

  # テキストメールの本文を取得して返す
  multipart_mails.find{|part| part.content_type.match 'text/plain'}.body.raw_source
end

mail = HogeMailer.send_mail.deliver
body = get_mail_body(mail)

解説

Mail::Messageのインスタンスはpartsという配列を持っています。ここに格納されるのは、

  • 添付ファイルがない場合
    • テキストとHTMLのメール
  • 添付ファイルがある場合
    • メールの配列2
    • 添付ファイル

になります。

ですから、メール本文を取得しようと思うと、添付ファイルの有無で調べなくてはならない配列の深さが変わります。

ところで、partsの成分はすべてMail::Partというラッパーのインスタンスになっており、Mail::Part#multipart?を叩くとメールの配列であるかどうかを真偽値で返してくれます。

これを利用してpartsの各要素に対してmultipart?を実行して論理和を取れば、partsにメールの配列があるかどうかわかるという寸法です。

ちなみに

if文の部分はワンライナーでも書けます。見づらいですけど。

multipart_mails = (parts.map(&:multipart?).inject(:|) ? parts.find(&:multipart?).parts : parts)

バージョン

  • Ruby 2.2.6
  • Rails, ActionMailer 3.2.22.5

古い環境で調べたので最新の環境で動くかはわかりません(変わったことはしてないので動くと思いますが……)。


  1. テキストとHTMLのマルチパートであることを想定しています。マルチパートでないメールが飛ぶ可能性があるともう少し考えることが増えます 

  2. 添付ファイルがない場合のpartsとほぼ同様のもの