Redirect all outgoing emails to single address for testing
In Ruby on Rails, I'm in a situation where I'd like my application (in a particular testing environment) to intercept all outgoing emails generated by the application and instead send them to a different, testing address (ma开发者_运维知识库ybe also modifying the body to say "Initially sent to: ...").
I see ActionMailer has some hooks to observe or intercept mail, but I don't want to spin my own solution if there's an easier way to do this. Suggestions?
We're using the sanitize_email gem with much success. It sends all email to an address you specify and prepends the subject with the original recipient. It sounds like it does exactly what you want and has made QA-ing emails a breeze for us.
Rails 3.0.9+
This is now very simple to do with Action Mailer interceptors.
Interceptors make it easy to alter the receiving address, subject, and other details of outgoing mail. Just define your interceptor, then register it in an init
file.
lib/sandbox_mail_interceptor.rb
# Catches outgoing mail and redirects it to a safe email address.
module SandboxMailInterceptor
def self.delivering_email( message )
message.subject = "Initially sent to #{message.to}: #{message.subject}"
message.to = [ ENV[ 'SANDBOX_EMAIL' ] ]
end
end
config/init/mailers.rb
require Rails.root.join( 'lib', 'sandbox_mail_interceptor' )
if [ 'development', 'staging' ].include?( Rails.env )
ActionMailer::Base.register_interceptor( SandboxMailInterceptor )
end
You can also unregister the interceptor at any time if, for example, you need to test the original email without the interceptor's interference.
Mail.unregister_interceptor( SandboxMailInterceptor )
# Test the original, unmodified email.
ActionMailer::Base.register_interceptor( SandboxMailInterceptor )
Typically what you do in tests is inspect ActionMailer::Base.deliveries, which is an array of TMail objects for mails that have been sent through your application. In the test environment the default settings are that nothing gets delivered, just put into that array.
I'd also look into using email_spec in your tests. Much more convenient than rolling your own testing functionality. Between the use of email_spec, capybara's helper functions and web steps, and factory_girl, that's close to 80% of the surface area of an application for testing in most of my applications.
Old question, but first hit on Google...
I eventually solved this in a different manner by (ab)using delivery_method = :sendmail
, this effective just pipes an email to something executable; this is assumed to be sendmail
, but it can be anything, really.
In your config/environments/development.rb
you can do something like:
YourApp::Application.configure do
# [...]
config.action_mailer.delivery_method = :sendmail
config.action_mailer.sendmail_settings = {
location: "#{Rails.root}/script/fake-sendmail",
arguments: 'martin+rails@arp242.net',
}
end
And then make script/fake-sendmail
:
#!/bin/sh
sendmail -if fake_sendmail@example.com "$1" < /dev/stdin
(don't forget to make this executable!)
A related solution (that I prefer) is to just append it to a mbox file; this required very little setup.
The config/environments/development.rb
looks similar:
YourApp::Application.configure do
# [...]
config.action_mailer.delivery_method = :sendmail
config.action_mailer.sendmail_settings = {
location: "#{Rails.root}/script/fake-sendmail",
arguments: "'#{Rails.root}/tmp/mail.mbox'",
}
end
And script/fake-sendmail
now looks like:
#!/bin/sh
echo "From FAKE-SENDMAIL $(date)" >> "$1"
cat /dev/stdin >> "$1"
echo >> "$1"
Open the mbox file with $any
email client...
This is a very simple method, that seems to work quite well. Some more details can be found here (I am the author of this page).
精彩评论