19

I'm using SendGrid's SMTP API in my Rails application to send out emails. However, I'm running into troubles testing the email header ("X-SMTPAPI") using RSpec.

Here's what the email looks like (retrieving from ActionMailer::Base.deliveries):

#<Mail::Message:2189335760, Multipart: false, Headers: 
<Date: Tue, 20 Dec 2011 16:14:25 +0800>, 
<From: "Acme Inc" <contact@acmeinc.com>>, 
<To: doesntmatter@nowhere.com>, 
<Message-ID: <4ef043e1b9490_4e4800eb1b095f1@Macbook.local.mail>>, 
<Subject: Your Acme order>, <Mime-Version: 1.0>, 
<Content-Type: text/plain>, <Content-Transfer-Encoding: 7bit>, 
<X-SMTPAPI: {"sub":{"|last_name|":[Foo],"|first_name|":[Bar]},"to":["foo@bar.com"]}>> 

Here's my spec code (which failed):

ActionMailer::Base.deliveries.last.to.should include("foo@bar.com")

I've also tried various method to retrieve the header("X-SMTPAPI") and didn't work either:

mail = ActionMailer::Base.deliveries.last
mail.headers("X-SMTPAPI") #NoMethodError: undefined method `each_pair' for "X-SMTPAPI":String

Help?

Update (answer)

Turns out, I can do this to retrieve the value of the email header:

mail.header['X-SMTPAPI'].value

However, the returned value is in JSON format. Then, all I need to do is to decode it:

sendgrid_header = ActiveSupport::JSON.decode(mail.header['X-SMTPAPI'].value)

which returns a hash, where I can do this:

sendgrid_header["to"] 

to retrieve the array of email addresses.

Lim Cheng Soon
  • 191
  • 1
  • 4

2 Answers2

12

The email_spec gem has a bunch of matchers that make this easier, you can do stuff like

mail.should have_header('X-SMTPAPI', some_value)
mail.should deliver_to('foo@bar.com')

And perusing the source to that gem should point you in the right direction if you don't want to use it e.g.

mail.to.addrs

returns you the email addresses (as opposed to stuff like 'Bob ')

and

mail.header['foo']

gets you the field for the foo header (depending on what you're checking you may want to call to_s on it to get the actual field value)

Frederick Cheung
  • 83,189
  • 8
  • 152
  • 174
  • Thanks. I've checked out email_spec gem. The "deliver_to" matcher is similar to the "to" matcher (which returns "doesntmatter@nowhere.com" instead of "foo@bar.com") and the "have_header" matcher simply returns the full header. Anyway, I've found out a solution to this and will post it up now. Thanks! – Lim Cheng Soon Dec 20 '11 at 10:37
0

Repeating some of the other advice here, in more modern rspec syntax:

RSpec.describe ImportFile::Mailer do
  describe '.file_error' do
    let(:mail) { described_class.file_error('daily.csv', 'missing header') }

    it { expect(mail.subject).to eq("Import error: missing header in daily.csv") }
    it { expect(mail.header['X-source-file'].to_s).to eq ('daily.csv') }
  end
end
David Hempy
  • 5,373
  • 2
  • 40
  • 68