Rails 3 Mail gem error creating mail

Posted by unixmonkey on September 15, 2011

I’m in the process of upgrading a Rails app from 2 to 3, and this proved to be a stumbling block.

Creating a message of any kind would result in a message like this:

NoMethodError: undefined method `new' for "smtp":String
from gems/mail-2.2.15/lib/mail/message.rb:252:in `delivery_method'
from gems/actionmailer-3.0.0/lib/action_mailer/delivery_methods.rb:74:in `wrap_delivery_behavior'
from gems/actionmailer-3.0.0/lib/action_mailer/delivery_methods.rb:83:in `wrap_delivery_behavior!'
from gems/actionmailer-3.0.0/lib/action_mailer/base.rb:641:in `mail'
from app/mailers/developer_mailer.rb:22:in `email_error_message'

This behavior comes from a method named lookup_delivery_method in the Mail gem.
The problem is that this method assumes the ActionMailer::Base.delivery_method to return a symbol like :smtp instead of a string like “smtp”. The old behavior worked fine in Rails 2.x apps.

I have different mailer settings per environment and load the settings in pretty much the same way Redmine does, by looping over a yml config file and using send to set actionmailer settings. The solution is to make sure it is created as a symbol like so:

# Loads ActionMailer settings from config/email.yml
# and turns deliveries on only if configuration block is found
config_file = Rails.root.join('config','email.yml')
 
if File.file?(config_file)
  mailconfig = YAML::load_file(config_file)
 
  if mailconfig.is_a?(Hash) && mailconfig.has_key?(Rails.env)
  # enable deliveries
  ActionMailer::Base.perform_deliveries = true
 
  mailconfig[Rails.env].each do |key, value|
    if value.respond_to?(:symbolize_keys!)
      value.symbolize_keys!
    elsif value.respond_to?(:to_sym)
      value = value.to_sym
    end
    ActionMailer::Base.send("#{key}=", value)
  end
else
  # disable deliveries
  ActionMailer::Base.perform_deliveries = false
end