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=>"example@foobar.com",
: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: example@foobar.com
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 = "example+catcher@foobar.com"
end
end
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:
To this:
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.