How to test with RSpec if an email is delivered

Assuming your test environment is set up in the usual fashion (that is, you have config.action_mailer.delivery_method = :test), then delivered emails are inserted into the global array ActionMailer::Base.deliveries as Mail::Message instances. You can read that from your test case and ensure the email is as expected. See here.


Configure your test environment to accumulate sent mails in ActionMailer::Base.deliveries.

# config/environments/test.rb
config.action_mailer.delivery_method = :test

Then something like this should allow you to test that the mail was sent.

# Sample parameters you would expect for POST #create.
def reservation_params
  { "reservation" => "Drinks for two at 8pm" }
end

describe MyController do
  describe "#create" do
    context "when a reservation is saved" do
      it "sends a confirmation email" do
        expect { post :create, reservation_params }.to change { ActionMailer::Base.deliveries.count }.by(1)
      end
    end
  end
end

Note that my example uses RSpec 3 syntax.


I know I'm late to the party with this one, but for future Googlers...

I think a better solution to this problem is answered here

The previously accepted answer is testing the Mailer itself (inside the controller spec). All you should be testing for here is that the Mailer gets told to deliver something with the right parameters.

You can then test the Mailer elsewhere to make sure it responds to those parameters correctly.

ReservationMailer.should_receive(:confirm_email).with(an_instance_of(Reservation))


Anyone using rspec +3.4 and ActiveJob to send async emails, try with:

expect {
  post :create, params
}.to have_enqueued_job.on_queue('mailers')

This is way how to test that Mailer is called with right arguments. You can use this code in feature, controller or mailer spec:

delivery = double
expect(delivery).to receive(:deliver_now).with(no_args)

expect(ReservationMailer).to receive(:confirm_email)
  .with('reservation')
  .and_return(delivery)