views:

748

answers:

2

I have a need to use two different smtp servers in a Rails application. It appears that the way ActionMailer is constructed, it is not possible to have different smtp_settings for a subclass. I could reload the smtp settings for each mailer class whenever a message is being sent, but that messes up the ExceptionNotifier plugin which is outside my control (unless I mess with it too). Does anyone have a solution/plugin for something like this?

Ideally I would like to have

class UserMailer < ActionMailer::Base; end

and then set in environment.rb

ActionMailer::Base.smtp_settings = standard_smtp_settings
UserMailer.smtp_settings = user_smtp_settings

Thus, most of my mailers including ExceptionNotifier would pickup the default settings, but the UserMailer would use a paid relay service.

A: 

I'm afraid it's not doable natively.
But you can trick it a bit by modifying the @@smtp_settings variable in the model.

There's an article on Oreilly which explains it pretty well even though they code is not clean at all. http://broadcast.oreilly.com/2009/03/using-multiple-smtp-accounts-w.html

Damien MATHIEU
Thanks for the reply. I saw that article, and that is what I meant by reload the smtp settings before each mail (which is what the article did in the load_settings method). This is close to a solution, but it messes up ExceptionNotifier because I cannot reload the settings for it without changing the plugin. I was hoping there for something more maintainable.
marcus
Unfortunately, because of the way it is implemented, it's not possible.
Damien MATHIEU
Anything's possible with enough monkey patches.
tadman
+3  A: 

Based on the Oreilly article, I came up with the solution I wrote about here: http://transfs.com/devblog/2009/12/03/custom-smtp-settings-for-a-specific-actionmailer-subclass

Here's the relevant code:

class MailerWithCustomSmtp < ActionMailer::Base
  SMTP_SETTINGS = {
    :address => "smtp.gmail.com",
    :port => 587,
    :authentication => :plain,
    :user_name => "[email protected]",
    :password => 'password',
  }

  def awesome_email(bidder, options={})
     with_custom_smtp_settings do
        subject       'Awesome Email D00D!'
        recipients    '[email protected]'
        from          '[email protected]'
        body          'Hope this works...'
     end
  end

  # Override the deliver! method so that we can reset our custom smtp server settings
  def deliver!(mail = @mail)
    out = super
    reset_smtp_settings if @_temp_smtp_settings
    out
  end

  private

  def with_custom_smtp_settings(&block)
    @_temp_smtp_settings = @@smtp_settings
    @@smtp_settings = SMTP_SETTINGS
    yield
  end

  def reset_smtp_settings
    @@smtp_settings = @_temp_smtp_settings
    @_temp_smtp_settings = nil
  end
end
jkrall
Thanks for the reply - this looks like a good solution (thought I don't have enough reputation to vote it up). I ended up switching from ExceptionNotifier to HopToad which made the O'Reilly solution again posible.
marcus
I had to add :domain => 'localhost:3000', :authentication => :plain, :enable_starttls_auto => true, to get it to work but this is the best solution I have found
Sam
and of course change localhost:3000 to the appropriate domain in production
Sam
good stuff! saved me!
Sam