Our customers like to have a staging environment so that they can always test the latest and greatest bleeding edge features. But what if an application is sending e-mails and you would not want someone@somecorp to be told to visit your awesome staging website?
Setting ActionMailer
's delivery method to :test
somewhat does the trick but there will be no real e-mail until the application goes live. That's sad.
Maybe you would want those mails to get delivered somewhere, like your customer's e-mail address or your own.
We ran into some difficulties using the sanitize_email gem on Rails 2.3.5 and were a bit unhappy with the way the gem was doing its work (configuring it application-wide felt somewhat weird). So we came up with a different solution.
For the magic to happen we put two lines into the designated environments files (like environments/staging.rb
). If we want e-mails to be delivered to admin@example.com and foo@bar.baz instead of their actual recipients it looks like this:
require 'override_mail_recipients'
ActionMailer::Base.override_recipients = %w[ admin@example.com foo@bar.baz ]
Of course, there is a bit more to it. Put the following code into a file like lib/override_mail_recipients.rb
and ActionMailer will know what to do.
ActionMailer::Base.class_eval do
@@override_recipients = nil
cattr_accessor :override_recipients
def deliver_with_override!(mail = @mail)
if override_recipients.present?
mail.override_recipients! override_recipients
end
deliver_without_override! mail
end
alias_method_chain :deliver!, :override
end
TMail::Mail.class_eval do
def override_recipients!(recipients)
recipients = Array(recipients)
original_addresses = {
:to => override(:to, recipients),
:cc => override(:cc, recipients),
:bcc => override(:bcc, recipients)
}
self.body = original_addresses.to_yaml + "\\n" + self.body
end
def override(method, recipients)
original_recipients = send("#{method}")
self.send "#{method}=", recipients if original_recipients
original_recipients
end
end
Obviously we "only" replace any existing e-mail recipients with ours and do not want to do anything fancy like secretly adding ourselves to BCC here. On staging every email is sent to the e-mail address(es) defined in the environment file and the original recipients are quoted at the beginning of each mail.
All other environments will behave like nothing ever happened.
Update: We extracted this trick into its own gem, Mail Magnet.