March 29th 2011

Testing inbound mail with the mail gem

The mail gem has become the underlying library of Action Mailer with Rails 3, replacing TMail, but it's also capable of receiving email from a POP3 or IMAP account. I couldn't find any documentation for testing the retrieval, so I figured it out from the source - here's how you can test your inbound mail processing.

Instead of the POP and IMAP retrievers, you need to use the TestRetriever. To set it up, you'll just have to configure the retriever_method to :test, like this:

Mail.defaults do
  retriever_method :test
end

The "inbound mail" you'll be fetching is coming from the class method Mail::TestRetriever.emails, which is a plain array and is supposed to be fed with Mail instances which you'll obviosuly need to create either manually or by reading in a previously dumped email in the eml Format:

manual_mail = Mail.new do
  from "someone@example.com"
  to "someother@example.com"
  subject "Fancy Test Mail"
  body "Oi!"
end

dumped_mail = Mail.read('/path/to/message.eml')

Then, just add the mail to your inbound email collection:

Mail::TestRetriever.emails << manual_mail
Mail::TestRetriever.emails << dumped_mail

Calling Mail.all should now yield the test mails, so your mail processing code should process them as expected. Of course you could also use ActionMailer to generate your test messages: MyMailer.some_mail returns a plain Mail message instance.

Putting it together

You'll probably also want to reset the test email collection in a teardown method, so a basic test/unit test for inbound mail processing might look somewhat like this:

class InboundMailTest < Test::Unit::TestCase
  def setup
    Mail.defaults { retriever_method :test }
  end
  
  def teardown
    Mail::TestRetriever.emails = []
  end
  
  def test_inbound_mail
    receive_mail('examplemail')
    # This class being your inbound mail processor.
    # Implementation left as an excercise to the reader ;)
    assert MyMailProcessor.process
    # more assertions that test the results of your mail processing...
  end
  
  private
  
    # Read in email from a prepared fixture file in eml format and push it to the 
    # inbound mail q
    def receive_mail(fixture_name)
      Mail::TestRetriever.emails << Mail.read("fixtures/mails/#{fixture_name}.eml")
    end
end
Written by Christoph Olszowka
blog comments powered by Disqus