After years of being a developer, (.NET and Grails, now I’m 3 months into Ruby-land), I always run into productivity problems when developing email-related features. Here’s why:
- Write/Fix the code
- Send the email to an inbox
- Open the inbox
- Find something wrong
- Repeat 1-4 until satisfied
Sounds easy, but it’s really tedious. Your inbox fills up with test emails. Your ‘flow’ gets broken. So recently, I’ve marked a new milestone in my development career: that doesn’t happen anymore. Instead, this happens:
- Write a test, expecting what I want to appear in an email.
- Write the code
- Run the test, find something wrong
- (Optional) Run the mailer in the rails console, email pops up as an HTML file in my browser
- Repeat 1-4 until satisfied.
No more inbox related stuff, and I can cycle quickly through the usual development loop.
rspec, email_spec and letter_opener are the keys to how I became productive. Combining these gems are one of the many ways to get productive in churning out email-related code, but so far this is my most favorite.
rspec/email-spec
rspec needs no introduction – simply put, it’s a unit testing framework for ruby.
I don’t write unit tests for all of my code, since I know I’ll go crazy when I do and it’ll be counterproductive. I only write tests for my code when:
- It’s a piece of the system that’s really important and prone to errors.
- It’s a pain to replicate manually.
To cut it short, Unit tests helps me be confident that whatever I’m expecting to send in an email, is actually written there in that email.
email_spec are helpers for rspec to test emails. Taken right out of the README:
describe "Signup Email" do
include EmailSpec::Helpers
include EmailSpec::Matchers
# include ActionController::UrlWriter - old rails
include Rails.application.routes.url_helpers
before(:all) do
@email = UserMailer.create_signup("jojo@yahoo.com", "Jojo Binks")
end
it "should be set to be delivered to the email passed in" do
@email.should deliver_to("jojo@yahoo.com")
end
it "should contain the user's message in the mail body" do
@email.should have_body_text(/Jojo Binks/)
end
it "should contain a link to the confirmation link" do
@email.should have_body_text(/#{confirm_account_url}/)
end
it "should have the correct subject" do
@email.should have_subject(/Account confirmation/)
end
end
letter_opener
letter_opener sends the email in the browser as an HTML file instead of really sending it. This means you do not need to set up email delivery in your development environment. Helpful for styling emails, and for integration tests (Cukes)
Taken right out of the README
:
First add the gem to your development environment and run the bundle
command to install it.
gem "letter_opener", :group => :development
Then set the delivery method in config/environments/development.rb
config.action_mailer.delivery_method = :letter_opener
Now any email will pop up in your browser instead of being sent. The messages are stored in tmp/letter_opener
TL;DR
rspec + letter_opener = developing any email-related feature is no longer painful.