letter_opener_web: a browser inbox for the mail your Rails app sends
A web interface for browsing Ruby on Rails sent emails
At a glance
- What is it?
- letter_opener_web gives the letter_opener gem a web interface, so the emails a Rails application sends during development can be read in a browser instead of in local files. It is a small development tool with a real configuration surface, and its staging mode comes with sharp edges that the README documents.
- Who is it for?
- Adopt letter_opener_web if your team develops a Rails application on a machine with no mail client and no local browser, such as a container, a VM or a remote development box, and you want sent mail in a browser. Do not adopt it as a staging mail system without reading the caveats, because the README limits it to single dyno deployments that do not send mail from background jobs, and the engine is mounted as a route with no authentication of its own.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Activity is slowing. The repository last received commits 6 months ago.
- What is it written in?
- Mainly HTML, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
An inbox for mail that never left the machine
letter_opener_web gives letter_opener an interface for browsing sent emails. That is the whole of it, and the reason it exists is a specific moment in Rails development: your application sends an email, and in development it is captured rather than delivered, and now you have to go and find it.
The letter_opener gem writes those captured messages to disk as files, one directory per message, and it tries to open each one locally with launchy. On a developer laptop that works and nobody thinks about it. On a Vagrant box, in a Docker container, or on a remote machine, there is no browser to open, so every email produces a failure message about not finding a browser command.
letter_opener_web solves the second half of that problem. It reads the same captured messages and serves them through a mounted Rails engine, so you read them over HTTP in any browser, including one on your own machine pointing at a forwarded port.
The audience is therefore Rails developers and teams, particularly those working in containerised or remote setups where the local mail file is awkward to reach. It is a development tool with a documented secondary use on staging environments, which is where the sharp edges are.
Adding the gem and mounting the engine
The installation is a Gemfile entry in the development group, followed by the bundle command:
group :development do
gem 'letter_opener_web', '~> 3.0'
endThen the engine is mounted in routes.rb, and the README shows the guard that keeps it out of production:
Your::Application.routes.draw do
mount LetterOpenerWeb::Engine, at: "/letter_opener" if Rails.env.development?
endTwo details are worth pausing on. The engine is mounted at a path inside your own application's routes, so it inherits your application's middleware, session handling and authentication, which means it is not automatically protected by anything on its own. And the environment check is what keeps the inbox off the public internet, so a misconfigured guard is the difference between a development tool and an open mailbox.
The README also asks you to make sure the :letter_opener delivery method is configured for your app, and then you visit http://localhost:3000/letter_opener after sending an email.
One inconsistency is visible in the documentation itself. The install snippet asks for the 3.0 series while the newest listed release tag for the project is v2.0.0, dated 2021-11-06, with v1.4.1 before it. Check which version you actually resolve before assuming the documented snippet is current.
Turning off launchy in containers and VMs
The Vagrant and Docker case is handled by choosing a different delivery method rather than by configuring the existing one.
When you use :letter_opener, each captured message is written to disk and then handed to launchy to be opened, and on a machine with no browser that produces a wall of noise like this:
12:33:42 web.1 | Failure in opening /vagrant/tmp/letter_opener/1358825621_ba83a22/rich.html
with options {}: Unable to find a browser command. If this is unexpected, Please rerun with
environment variable LAUNCHY_DEBUG=true or the '-d' commandline option and file a bug at
https://github.com/copiousfreetime/launchy/issues/newThe fix is to set the delivery method to :letter_opener_web in config/environments/development.rb:
config.action_mailer.delivery_method = :letter_opener_webThe README frames this as the option for people running the app from a Vagrant machine or a Docker container who want to skip the launchy calls, and also for anyone who simply prefers to browse mail in the web interface and does not care about opening emails automatically.
That single line is the interesting design decision in the project. Rather than adding a flag to suppress launchy, the tool takes over the delivery method entirely, so the behaviour changes at the point where Rails decides what to do with a message, not later when something tries to open it.
Two configuration settings and what they really do
There are two settings, and both are set through the same configure block.
letters_location changes where the letters are stored, which is only relevant when you are using the :letter_opener_web delivery method, since that method is the one that writes into the location the inbox reads from:
LetterOpenerWeb.configure do |config|
config.letters_location = Rails.root.join('your', 'new', 'path')
endThe README says this can go in an initializer or in development.rb.
auto_dark_mode controls whether the preview applies an automatic dark mode colour inversion strategy. It is disabled by default, and the reason given is to avoid conflicts with email templates that already implement their own prefers-color-scheme styling. When you turn it on, the tool applies a CSS based inversion strategy to approximate dark mode for templates that do not define their own styles, and the README compares the result to high contrast or browser level colour inversion.
That is an honest framing. A CSS inversion is not a real dark theme, it flips whatever colours the template set, so a brand coloured logo comes out inverted and an image with a white background becomes dark. The default of off is the right call for templates that handle it themselves, and the setting is most useful for the plain text and simple HTML mails that dominate development testing.
Staging environments and the Heroku limitation
Some people use the gem on staging or pre-production environments to avoid real emails being sent out, and the README gives the three steps for that. Move the gem out of the development group in your Gemfile, set config.action_mailer.delivery_method on the appropriate config/environments/<env>.rb, and enable the route for those environments in routes.rb.
The routes snippet shows two patterns:
Your::Application.routes.draw do
# If you have a dedicated config/environments/staging.rb
mount LetterOpenerWeb::Engine, at: "/letter_opener" if Rails.env.staging?
# If you use RAILS_ENV=production in staging environments, you'll need another
# way to disable it in "real production"
mount LetterOpenerWeb::Engine, at: "/letter_opener" unless ENV["PRODUCTION_FOR_REAL"]
endThe second pattern exists because some teams run their staging environment with RAILS_ENV set to production, so an environment check alone cannot distinguish staging from the real thing, and an environment variable has to carry that distinction instead.
The deployment limitation is stated as a notice. Using this gem on Heroku will only work if your app has just one dyno and does not send emails from background jobs, and the README points to issue GH-35 for updates on the matter. The reasoning is not spelled out, but the shape of it is clear from the architecture: the letters live on the filesystem of the process that wrote them, so a second dyno or a background worker on another host writes letters the web dyno cannot see.
The acknowledgements credit alexrothenberg for ideas in a letter_opener pull request and pseudomuto for keeping the project alive for a few years.
Where letter_opener_web is the wrong tool
Three cases point elsewhere.
The first is a team with a working local setup. If your laptop has a mail client and letter_opener opens messages for you, a web inbox is extra machinery. The gem earns its place in containers, virtual machines and remote development boxes, and it adds an engine, a route and a storage configuration to a setup that did not need them.
The second is a shared or multi-process deployment, which is exactly the Heroku case the README calls out. A single dyno with no background jobs is a narrow condition, and a system with more than one process has a shared filesystem problem that this design does not solve.
The third is anything where the mail is sensitive and the environment is reachable by someone other than the developer. The engine is mounted in routes.rb with whatever authentication your application already has, and in a development environment that authentication may be a stub or nothing at all. Using it on a staging box that is reachable from a network means putting a mailbox behind whatever your application happens to enforce, and the README does not describe any authentication of its own.
The upkeep picture deserves a mention too. The repository is not archived and the last push was on 2026-04-08 and the newest tagged release listed is v2.0.0 from 2021-11-06, with v1.4.1 and v1.4.0 before it. The install instruction asking for the 3.0 series and the release list disagreeing with each other is the kind of detail to resolve before you pin a version across a team.
Editorial conclusion
Adopt letter_opener_web if your team develops a Rails application on a machine with no mail client and no local browser, such as a container, a VM or a remote development box, and you want sent mail in a browser. Do not adopt it as a staging mail system without reading the caveats, because the README limits it to single dyno deployments that do not send mail from background jobs, and the engine is mounted as a route with no authentication of its own. Verify three things first: the version you install, since the README asks for the 3.0 series while the newest listed release tag is v2.0.0 dated 2021-11-06; that the route is mounted only in the environments you intend, whether that is development, staging or both; and that your delivery method is set so the browser inbox, rather than the file writer, is what fills it. The licence is MIT and the last push was on 2026-04-08.
Frequently asked questions
What does letter_opener_web do?
It gives the letter_opener gem an interface for browsing sent emails, so the messages a Rails application captures during development can be read in a browser rather than opened from local files. It is a web interface for browsing the mail your app sends.
How do I install and set up letter_opener_web?
Add the gem to the development group of your Gemfile and run bundle, mount LetterOpenerWeb::Engine in routes.rb under a path such as /letter_opener guarded by an environment check, and make sure the :letter_opener delivery method is configured. You then visit http://localhost:3000/letter_opener after sending an email.
How do I stop letter_opener from failing to open a browser in Docker or Vagrant?
Set config.action_mailer.delivery_method = :letter_opener_web in config/environments/development.rb. That makes the web interface the delivery method, so launchy is never called and you do not see the Unable to find a browser command messages.
Can I use letter_opener_web on a staging environment?
Yes, and the README lists the steps: move the gem out of the development group in your Gemfile, set config.action_mailer.delivery_method on the environment file, and mount the route for those environments in routes.rb. If you run staging with RAILS_ENV set to production, you need another way to disable it in real production, such as the environment variable check shown in the README.
What are the limitations of letter_opener_web on Heroku?
The README states that using the gem on Heroku will only work if the app has just one dyno and does not send emails from background jobs. It points to issue GH-35 for updates on the matter.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/fgrehm-letter-opener-web)Was this useful?