Using Letter Opener to View Sent Email on a Server (without actually sending anything)
When developing email functionality you don’t want to send real emails to real people before in production. At the same time you need to send them to ensure they are formatted correctly and contain the proper information. You can (and should) write integration tests to verify this but that helps developers gain confidence, what can we do to show non-technical stakeholders that it all works?
Let’s think about the different Rails environments and how we want them to behave with email.
- test should not send emails and allow us to write specs or features against them
- development should not send emails but provide a UI to view what would be sent
- staging should not send emails but provide a UI to view what would be sent
- production should send real emails to real people
Looking at this, Rails works really well for test with ActionMailer’s :test delivery method that stores the emails in the ActionMailer::Base.deliveries array so you can then use email_spec to write your specs. Production is also covered as long as you give it your mail server configuration. That leaves development and staging which look identical but we’ll see that they are slightly different. I’ll spend the rest of this article talking about how letter_opener lets us do what we want in these environments.
Let’s imagine we are working on a new startup in stealth mode. We want to generate buzz and prepare for a beta launch. We’re hiding the fact its all vaporware with a splashy homepage where people can request an invitation to the beta and it sends a “thanks for your interest” email. Lastly, we want to test it in development and staging.
Here’s a live demo at http://awesome-site-staging.heroku.com/ if you want to dive in and start clicking.
After you request an invitation it shows a page like this
Logfile testing (we can do better)
When you fill in your email and click the
Request Invitation button, our controller uses a mailer to create and deliver the email.
The only way to tell whether the email worked is to scroll through the development.log until you see something like this
Ok if you’re a developer and you enjoy reading log files but letter_opener lets us do better.
Using letter_opener in development
Letter_opener provides us with a UI so we can view the emails right in our browser. It’s super easy to add this gem and I’ll just copy the instructions from its README
Preview email in the browser instead of sending it. This means you do not need to set up email delivery in your development environment, and you no longer need to worry about accidentally sending a test email to someone else’s address
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.
Once we’ve done that what happens when we use the site to request an invitation? A new tab opens up with the email right there. Now as a user we can tell it’s correct and any non-technical people on the team can feel their confidence rise.
###How does letter_opener actually work?
Rails goes through the standard flow to create the mail object and when it’s ready to deliver the message it calls letter_opener’s
deliver! method because we
registered letter_opener as the action_mailer.delivery_method. Letter_opener saves the email to your file system as an html file
then uses launchy to open it in a browser using the file:// protocol.
There will be a couple of problems once we move onto a server which brings us to staging.
Using letter_opener on staging
If you’re like me you probably have a staging environment where you or your stakeholders can validate your app before releasing it to production and your end users. There are two aspects of this environment that wont work with letter_opener the way it did in development
- We need to use http:// not file:// to preview the emails because the browser is not on the same file system where the emails are written
- We may not be able to write to the file system. For example if we have deployed to heroku.
I had to make some changes to letter_opener to support this kind of server environment. The fork is available at https://github.com/alexrothenberg/letter_opener/tree/on_a_server and I’ll update the article if my pull requests are merged back in.
We need to make a few changes to our application.
1 - Update our
Gemfile to use the fork from github
2 - Add a debugging UI link so users can get to the “preview emails” page in something like
3 - If you cannot write to the filesystem let letter_opener know in your
Now we can see it all in action.
First, we request an invite.
Then, we click the link “view the Emails that users would have received” link at the bottom and see an “inbox” of everything the app sent.
Fincally clicking one message lets us preview it just as we did in devellopment
We are able to run on heroku without writing to the file system by using the FakeFS gem which simulates the filesystem in memory. FakeFS is designed to be used for testing and one caveat to be aware of is that your old emails will disappear if heroku recycles your dyno due to inactivity.
I hope you think letter_opener is useful and give it a try the next time you need to send email. Remember here’s a live demo at http://awesome-site-staging.heroku.com/ of the site we’ve been talking about here.