Overriding Mail Configs in Rails 3

When I am developing a rails app, and I need to work with email portions, I don’t like having to depend on remote mailers to eventually deliver the mail to my inbox, and I don’t really like the idea of installing a mail server locally on my laptop, just to handle some mail testing.

I found an alternative to either of those, called MockSMTP.app. SMTP is the acronym for “Simple Mail Transport Protocol,” and is the language that email servers speak to each other to move messages across the Internet. MockSMTP is an OS X app (I’m sure similar products exist elsewhere) that pretends to be an smtp server for the sole purpose of catching outgoing mail and displaying the contents to you. This works great in practice, the app is easy to set up, and handles html email with no problems. There is only one drawback, that ends up causing some minor hassles.

The drawback is that on Un*x-y systems, any process that wants to run on a port less than 1024 (like 25, the smtp port) must be run by the administrative (or “root”) user. MockSMTP recommends against this, with good reason, and instead recommends that you run it on port 1025.

This is all well and good, but whether you run it on port 25 or 1025, you need to tell your rails app to use this new mail server, and not the one you use in production, or development 90% of the time. Manually changing settings in some kind of file, whether environment or initializer is tedious, and error prone when checking things into version control.

But we can use a trick, a sleight of hand if you will, to get rails to do what we want, when we want it to do it. This trick is made easier if you have one mailer config in an initializer under config/initializers (you can namespace it to an environment using Rails.env.development?, etc, if you need different configs). I work on an app with mailer settings in /config/initializers/mail.rb that looks like so:

mailer config
1
2
3
4
5
6
7
8
9
ActionMailer::Base.delivery_method = :smtp
ActionMailer::Base.smtp_settings = {
  :address => "smtp.smtp_super_host.com",
  :port => 25,
  :domain => "example.com",
  :authentication => :login,
  :user_name => "client_email@example.com",
  :password => "smtp_pass"
}

When I want to override those settings for great speed, I add another file in the config/initializers subdirectory, called mail_override.rb, like this:

mailer override config
1
2
3
4
5
6
7
8
if(Rails.env.development? && !$rails_rake_task)
  ActionMailer::Base.delivery_method = :smtp
  ActionMailer::Base.smtp_settings = {
    :address => "localhost",
    :port => 1025,
    :domain => "www.yourdomain.com"
  }
end

Pretty sweet, huh? I don’t really think I need to override the delivery_method here, but better safe… The initializers get loaded in alphabetical order (alpha numeric actually, probably some strange, Lovecraftian design), so mail.rb gets loaded, then mail_override.rb. the bit at the top of the initializer checks to ensure we’re in the rails development environment, and that we aren’t running a rake task before overriding the mail settings. This technique was shamelessly stolen from a great article by Pratik Naik on using the ruby debugger with pow.

A couple of notes here. I normally tell my SCM (git) to ignore this file, so it doesn’t get checked into source control. With the guards at the top of the initializer, it shouldn’t do any damage in a production environment, but I’d rather not take chances. Also, I don’t actually copy this file into the initializers dir every time, but rather symlink it from a common dir, so all of the apps I work on can have the same mailer override quick and easy.

Hope this saves someone some time, and maybe gives an alternative to waiting that extra five seconds to five minutes for your dev emails to come back to you.

/korishev

Comments