Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ActionMailer settings incorrectly differing between development and production

The Error

I've got my ActionMailer setup and working perfectly in development. I can call UserMailer.welcome(user).deliver, and the email reaches its destination. However, when I push my code into production and call the same deliver method, suddenly I get an error:

Errno::ECONNREFUSED: Connection refused - connect(2)
    from /usr/local/rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/net/smtp.rb:546:in `initialize'
    from /usr/local/rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/net/smtp.rb:546:in `open'
    from /usr/local/rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/net/smtp.rb:546:in `tcp_socket'
    from /usr/local/rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/net/smtp.rb:555:in `block in do_start'
    from /usr/local/rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/timeout.rb:58:in `timeout'
    from /usr/local/rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/timeout.rb:89:in `timeout'
    from /usr/local/rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/net/smtp.rb:555:in `do_start'
    from /usr/local/rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/net/smtp.rb:525:in `start'
    from /webapps/myapp/production/shared/bundle/ruby/1.9.1/gems/mail-2.3.0/lib/mail/network/delivery_methods/smtp.rb:128:in `deliver!'
    from /webapps/myapp/production/shared/bundle/ruby/1.9.1/gems/mail-2.3.0/lib/mail/message.rb:1989:in `do_delivery'
    from /webapps/myapp/production/shared/bundle/ruby/1.9.1/gems/mail-2.3.0/lib/mail/message.rb:230:in `block in deliver'
    from /webapps/myapp/production/shared/bundle/ruby/1.9.1/bundler/gems/rails-5680a51dcbaf/actionmailer/lib/action_mailer/base.rb:414:in `block in deliver_mail'
    from /webapps/myapp/production/shared/bundle/ruby/1.9.1/bundler/gems/rails-5680a51dcbaf/activesupport/lib/active_support/notifications.rb:55:in `block in instrument'
    from /webapps/myapp/production/shared/bundle/ruby/1.9.1/bundler/gems/rails-5680a51dcbaf/activesupport/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
    from /webapps/myapp/production/shared/bundle/ruby/1.9.1/bundler/gems/rails-5680a51dcbaf/activesupport/lib/active_support/notifications.rb:55:in `instrument'
    from /webapps/myapp/production/shared/bundle/ruby/1.9.1/bundler/gems/rails-5680a51dcbaf/actionmailer/lib/action_mailer/base.rb:412:in `deliver_mail'
    from /webapps/myapp/production/shared/bundle/ruby/1.9.1/gems/mail-2.3.0/lib/mail/message.rb:230:in `deliver'
    from (irb):10
    from /webapps/myapp/production/shared/bundle/ruby/1.9.1/bundler/gems/rails-5680a51dcbaf/railties/lib/rails/commands/console.rb:45:in `start'
    from /webapps/myapp/production/shared/bundle/ruby/1.9.1/bundler/gems/rails-5680a51dcbaf/railties/lib/rails/commands/console.rb:8:in `start'
    from /webapps/myapp/production/shared/bundle/ruby/1.9.1/bundler/gems/rails-5680a51dcbaf/railties/lib/rails/commands.rb:40:in `<top (required)>'
    from script/rails:6:in `require'
    from script/rails:6:in `<main>'

The Problem Thus Far

Probably the most valuable info I can offer is that the actual delivery_method data on the Message object is incorrect in production. In development, when I call UserMailer.welcome(user).delivery_method, the (formatted) output is:

#<Mail::SMTP:0x000001042c4a20 @settings={
  :address=>"smtp.gmail.com",
  :port=>587,
  :domain=>"foobar.com",
  :user_name=>"[email protected]",
  :password=>"MY_PASSWORD",
  :authentication=>"plain",
  :enable_starttls_auto=>true,
  :openssl_verify_mode=>nil}>

This clearly matches the settings I've defined in mailers.yml. In production, when I make the same call, the output is:

#<Mail::SMTP:0xbfb2c18 @settings={
  :address=>"localhost",
  :port=>25,
  :domain=>"localhost.localdomain",
  :user_name=>nil,
  :password=>nil,
  :authentication=>nil,
  :enable_starttls_auto=>true,
  :openssl_verify_mode=>nil}>

This just appears to be the defaults as defined on line 22 of ActionMailer::DeliveryMethods instead of my own settings from mailers.yml.

Relevant Code

As far as I can tell, my environments should have ActionMailer setup the same.

config/environment.rb:

Myapp::Application.config.action_mailer.delivery_method = :smtp
Myapp::Application.config.action_mailer.smtp_settings = YAML.load_file(
    Rails.root.join('config', 'mailers.yml'))[Rails.env].to_options

config/mailers.yml:

default: &default
  address:              smtp.gmail.com
  port:                 587
  domain:               foobar.com
  user_name:            [email protected]
  password:             MY_PASSWORD
  authentication:       plain
  enable_starttls_auto: true

development:
  <<: *default

production:
  <<: *default

config/environments/development.rb:

Myapp::Application.configure do
  # ...
  config.action_mailer.raise_delivery_errors = false
  config.action_mailer.default_url_options = { :host => 'localhost:3000' }
  config.action_mailer.interceptors = ['MailInterceptor']
  # ...
end

config/environments/production.rb:

Myapp::Application.configure do
  # ...
  config.action_mailer.default_url_options = { :host => 'foobar.com' }
  # ...
end

Note that I've also tried commenting out the two extra lines in development.rb (and tried adding them into production.rb) with no change -- I still get the same error in production, but not development.

Also, although I don't think it's relevant, I'll include MailIntercepter that I reference in development.rb (it's just to redirect all mail to my email address instead of test users' email addresses):

class MailInterceptor
  def self.delivering_email(message)
    message.subject = "[#{message.to}] #{message.subject}"
    message.to = "[email protected]"
  end
end
like image 408
Matt Huggins Avatar asked Aug 09 '11 03:08

Matt Huggins


2 Answers

Figured it out, though it seems to go against what I thought was supposed to be the standard approach to Rails 3.1 config.

Changed this line:

Myapp::Application.config.action_mailer.smtp_settings = YAML.load_file(
    Rails.root.join('config', 'mailers.yml'))[Rails.env].try(:to_options)

To this:

ActionMailer::Base.smtp_settings = YAML.load_file(
    Rails.root.join('config', 'mailers.yml'))[Rails.env].try(:to_options)

Still not sure why the former works in development but not production, but the latter now works for me in production, so it's what I'm going with for now.

like image 170
Matt Huggins Avatar answered Dec 18 '22 09:12

Matt Huggins


By any chance do you have your environment.rb set up like:

Myapp::Application.initialize!
Myapp::Application.configure do { }

If so, swap these two lines. I had nearly the same issue (mailer config worked in dev, not in other environments) and that was the problem.

like image 44
George Armhold Avatar answered Dec 18 '22 07:12

George Armhold