事象

ActionMailer::Base を継承したクラスのメソッドをコール時に、メソッド内で mail が呼び出されていない場合は、 ActionMailer::Base::NullMail が返却される。(通常は Mail::Message) ちなみに、 deliver_now などのメソッドを実行しても、エラーとならずに nil が返却されるだけなので気づきにくい

経緯

mail を deliver_now した後に、 mail の subject を取得したかった。しかし、mail.subject で、 nil しか取得できない。

class TestMailer < ActionMailer::Base
  def test_mail
    # selfだとdeliver_now時にエラーになる
    if TestMailer.use_api?
      # using Send Grid API
    else
      mail(to: "to@example.com", subject: "test mail")
    end
  end

  def self.use_api?
    Rails.env.production?
  end
end
mail = TestMailer.test_mail
mail.deliver_now

mail.subject # <= nil

解決

mailメソッドは呼ぶが、apiを使用した場合は、送信しない。

class TestMailer < ActionMailer::Base
  def test_mail
    # selfだとdeliver_now時にエラーになる
    if TestMailer.use_api?
      # using Send Grid API
    else
      mail(to: "to@example.com", subject: "test mail")
    end
  end

  def self.deliverable?
    !self.use_api?
  end

  def self.use_api?
    Rails.env.production?
  end
end
mail = TestMailer.test_mail
mail.deliver_now if TestMailer.deliverable?

mail.subject # <= "test mail"

tips

deliver_now時にもう一度、処理を行われる?

if TestMailer.use_api?self を敢えて指定していません。 selfを指定すると TestMailer.test_mail 時はエラーにならないのですが、 deliver_now 実行時に、 NoMethodError: undefined method 'use_api?' とエラーが発生します。