Deep in Rails: ActionMailer#deliver Part VI
So now we know how Rails sends emails. What can we do with that knowledge?
All kinds of stuff.
One of my clients needed the ability to send messages through 3 different SMTP servers. They wanted it to be easy to use for their developers and allow them to change out SMTP servers for each mailer method. Now that we know how AM does it’s thing, we can use that knowledge to create a quick patch and solve the above problem.
We’ll create a new file in out Rails app inside lib/ and call it action_mailer_hacks.rb. Inside of the file add the following (dont worry, we’ll go over each line)
module ActionMailerHacks
module InstanceMethods
def deliver_with_switchable_smtp!(mail = @mail)
unless logger.nil?
logger.info "Switching SMTP server to: #{new_smtp.inspect}"
end
ActionMailer::Base.smtp_settings = new_smtp unless new_smtp.nil?
deliver_without_switchable_smtp!(mail = @mail)
end
end
def self.included(receiver)
receiver.send :include, InstanceMethods
receiver.class_eval do
adv_attr_accessor :new_smtp
alias_method_chain :deliver!, :switchable_smtp
end
end
end
ActionMailer::Base.send :include, ActionMailerHacks
First, in module InstanceMethods, we create a new deliver method that will switch the SMTP server from AM. We do some quick logging and then set AM::Base.smtp_settings to the new smtp server. After we do that, we call deliver_without_switchable_smtp which gets created when we do our alias_method_chaining later down the page.
When this module is included we include the InstanceMethods module into the receiver and then run class_eval so that we can create a new adv_attr_accessor called new_smtp and then call alias_method_chain to create our without method. After that we include this whole module into AM::Base and we’re done with the hack. Add require "action_mailer_hacks.rb" to your environment.rb file and we’re ready for the mailer.
Now we move on to MessageMailer and actually use the hack.
class MessageMailer < ActionMailer::Base
def contact_form(msg_from, message)
subject 'Im contacting you'
recipients "someemail@somedomain.com"
new_smtp :address => 'mail.someplace.com', :port => 25, :domain => 'someplace.com', :authentication => :login, :user_name => 'xxxxdddd', :password => 'secret'
from msg_from
sent_on Time.now
body :message => message
end
end
All we do is call new_smtp with our new server address and then this method gets delivered through that SMTP server. That’s it. Simple and clean, exactly how I like it.
Well, that was fun. Next time, we’ll look through something a little shorter, maybe migrations. Until then, have fun and keep codin’