Rails Mailer “Net::OpenTimeout: execution expired” 仅在生产服务器上出现异常

Posted

技术标签:

【中文标题】Rails Mailer “Net::OpenTimeout: execution expired” 仅在生产服务器上出现异常【英文标题】:Rails Mailer "Net::OpenTimeout: execution expired" Exception on production server only 【发布时间】:2013-04-09 01:00:14 【问题描述】:

我在 Ubuntu 12.04 TLS VPS 上使用 Ruby MRI 2.0.0 和 Rails 3.2.12 并尝试在我的应用程序中设置电子邮件通知。 几天前它运行良好,但现在不行了。我的虚拟主机是 OVH。

我的 SMTP 设置:

config.action_mailer.perform_deliveries = true
config.action_mailer.raise_delivery_errors = true

ActionMailer::Base.smtp_settings = 
  :address              => "smtp.gmail.com",
  :port                 => 587,
  :user_name            => 'sender@gmail.com',
  :password             => 'secret',
  :authentication       => 'plain',
  :enable_starttls_auto => true

使用RAILS_ENV=production rails console

class MyMailer < ActionMailer::Base
  def test_email
    sender     = "sender@gmail.com"
    receiver   = "receiver@example.com"
    mail from: sender, to: receiver, subject: "Hello!", body: "World!!"
  end
end
 => nil

MyMailer.test_email.deliver

输出:

Net::OpenTimeout: execution expired
    from ~/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/net/smtp.rb:540:in `initialize'
    from ~/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/net/smtp.rb:540:in `open'
    from ~/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/net/smtp.rb:540:in `tcp_socket'
    from ~/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/net/smtp.rb:550:in `block in do_start'
    from ~/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/net/smtp.rb:549:in `do_start'
    from ~/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/net/smtp.rb:519:in `start'
    from ~/.rvm/gems/ruby-2.0.0-p0@mygemset/gems/mail-2.4.4/lib/mail/network/delivery_methods/smtp.rb:144:in `deliver!'
    from ~/.rvm/gems/ruby-2.0.0-p0@mygemset/gems/mail-2.4.4/lib/mail/message.rb:2034:in `do_delivery'
    from ~/.rvm/gems/ruby-2.0.0-p0@mygemset/gems/mail-2.4.4/lib/mail/message.rb:229:in `block in deliver'
    from ~/.rvm/gems/ruby-2.0.0-p0@mygemset/gems/actionmailer-3.2.12/lib/action_mailer/base.rb:415:in `block in deliver_mail'
    from ~/.rvm/gems/ruby-2.0.0-p0@mygemset/gems/activesupport-3.2.12/lib/active_support/notifications.rb:123:in `block in instrument'
    from ~/.rvm/gems/ruby-2.0.0-p0@mygemset/gems/activesupport-3.2.12/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
    from ~/.rvm/gems/ruby-2.0.0-p0@mygemset/gems/activesupport-3.2.12/lib/active_support/notifications.rb:123:in `instrument'
    from ~/.rvm/gems/ruby-2.0.0-p0@mygemset/gems/actionmailer-3.2.12/lib/action_mailer/base.rb:413:in `deliver_mail'
    from ~/.rvm/gems/ruby-2.0.0-p0@mygemset/gems/mail-2.4.4/lib/mail/message.rb:229:in `deliver'
    from (irb):28
    from ~/.rvm/gems/ruby-2.0.0-p0@mygemset/gems/railties-3.2.12/lib/rails/commands/console.rb:47:in `start'
    from ~/.rvm/gems/ruby-2.0.0-p0@mygemset/gems/railties-3.2.12/lib/rails/commands/console.rb:8:in `start'
    from ~/.rvm/gems/ruby-2.0.0-p0@mygemset/gems/railties-3.2.12/lib/rails/commands.rb:41:in `<top (required)>'
    from script/rails:6:in `require'
    from script/rails:6:in `<main>'2.0.0p0 :029 >

我尝试了以下方法:

exception_notification gem 几天前已添加到设置中。我试图在Gemfile 中注释它的行以及它的匹配配置,然后运行bundle install。重新启动服务器后,即使我删除并重新创建 gemset,问题仍然存在。 在虚拟机上进行测试(与 VPS 完全相同的设置,包括 iptables 规则):有效 禁用 iptables 规则:不起作用 使用 openssl 从 VPS 手动连接到 Gmail:有效(所以这不是防火墙问题 - 请参阅此处:Connecting to smtp.gmail.com via command line); 在 Gmail 帐户选项中启用 IMAP(已禁用):不起作用 使用其他 Gmail 帐户:不起作用 将 Ruby 2.0.0 替换为 Ruby 1.9.3 升级到 Rails 3.2.13

有人知道如何解决这个问题吗?

谢谢!

【问题讨论】:

这里还有一种表现:执行过期 /ree-187/lib/ruby/1.8/timeout.rb:64:in open' .../vendor/plugins/action_mailer_optional_tls/lib/smtp_tls.rb:40:in do_tls_start' /.../vendor/plugins/action_mailer_optional_tls/lib/ smtp_tls.rb:40:in `do_tls_start'... 【参考方案1】:

首先,用 Telnet 直接连接:

telnet smtp-relay.sendinblue.com 587
Trying 94.143.17.4...

这是基本的连接故障排除,适用于任何提供商或端口。将 SendBlue 和 587 端口替换为您的实际主机名/端口。

如果您收到此错误:

telnet: Unable to connect to remote host: Connection timed out

那么,问题不在于 Rails。

在上面的例子中,问题出在端口号上。 sendinblue 或 mandrill 等服务(我也相信 gmail)不再支持 587 端口。 “2525”是新的“587”


如果您在 telnet 上遇到超时,请检查:

    主机名:人们通常使用“smtp.sendinblue.com”而不是“stmp-relay.sendinblue.com”,“smtp.mandrill.com”而不是“smtp.mandrillapp.com”,等等。 端口:587 已过时。主要供应商现在使用 2525。主要的像 DigitalOcean 这样的云服务也会阻止与 587 的传出连接。这就是为什么它可以在你的电脑上运行,但不能在你的服务器上运行。我什至不会提及“25”端口,它比 587 更过时。此外,一些提供商使用特定的非默认端口或 imap。 ipv6 vs ipv4:检查主机名是否被转换为 IPv4。如果没有,请尝试禁用 IPv6(请参阅其他答案)。 主机名解析:在您知道电子邮件发送正常的机器上运行相同的 telnet 命令。检查翻译后的 ip(“正在尝试 xxx...”的 xxx 部分)是否相同。如果没有,请返回您的服务器并将主机名替换为此 ip。如果可行,请更改您的 /etc/hosts 并强制主机名使用此 ip。

【讨论】:

在 Rails 上使用 ruby​​ 时,你如何做同样的连接?【参考方案2】:

我可能遇到了同样的问题,我的生产应用程序没有发送邮件,尽管开发中的一切工作正常。我也收到了“Net::OpenTimeout”错误。

我的问题是我在生产中使用的是 Google 服务器,and it blocks ports 25, 465 and 587 on outbound connections。

由于我使用 Mandrill 发送邮件,I was able to switch the connecting port from 587 to 2525 and everything is okay now.

【讨论】:

我也在使用谷歌云并将我的 smtp 端口从 587 更改为 2525 并且工作正常!谢谢! 我的 iptables 规则集不允许输出连接到端口 465(自管理服务器) @lucianosousa,谢谢,我必须使用 2587,此处描述为 docs.aws.amazon.com/ses/latest/DeveloperGuide/smtp-connect.html 还使用了 GCP,并且您在跟踪此问题时让我非常头疼。谢谢!【参考方案3】:

这里还有一个临时修复程序,在等待您的托管服务提供商解决问题时可能会派上用场:

将以下行添加到/etc/sysctl.conf

#disable ipv6
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1

现在使用以下命令重新加载 sysctl 服务:

sudo sysctl -p

现在应用可以再次发送电子邮件了。

您可以随时知道是否启用了 IPv6 呼叫

cat /proc/sys/net/ipv6/conf/all/disable_ipv6

从终端。两个可能的答案: 0 => IPv6 已启用; 1 => 禁用 IPv6。

发件人:https://serverfault.com/questions/512744/timeout-error-in-all-my-apps-for-every-call-to-smtp-servers

【讨论】:

请注意 link-only answers 是不鼓励的,所以答案应该是寻找解决方案的终点(与另一个中途停留的参考相比,随着时间的推移往往会变得陈旧)。请考虑在此处添加独立的概要,并保留链接作为参考。 即使在重新启动 sysctl.conf 以重新加载后,这个对我也不起作用 我想在您的解决方案 @DuArme 中添加一些内容,我们需要在将这些行添加为 sudo sysctl -p 后重新加载 sysctl 配置。只有重新加载 sysctl 后,它才会工作【参考方案4】:

问题是由于生产服务器上的 IPv6 配置错误,现已修复。

【讨论】:

同样的问题,您知道如何发现错误配置吗?是否有一些日志文件要查找或其他什么? 我注意到的一点:当我尝试通过命令行连接到 smpt.gmail.co 时,它可以工作,但首先它会尝试使用 IPv6 地址并等待几秒钟,直到经过这么长时间它尝试使用简单的 IP 并连接!也许是在我的应用程序第一次超时...现在的问题是:这可能是发现这种错误配置的症状吗? 我不确定这是否是问题所在,但我遇到了同样的症状……你是怎么解决的? @darmen 这个问题有进展吗?我遇到了同样的问题 别等了,我记得我找到了一个临时修复程序,请在此处阅读:serverfault.com/questions/512744/… 祝你好运!【参考方案5】:

您可以将 Ubuntu 配置为首选 IPv4 而不是 IPv6。通过这种方式,您将能够发送电子邮件并访问仅限 IPv6 的站点。编辑 /etc/gai.conf 并取消注释以下行:

precedence ::ffff:0:0/96 100

【讨论】:

【参考方案6】:

试试这个,如果以上都失败了

我通过在 config 下的 application.rb 中添加它解决了这个问题

需要'net/http' 需要'openssl' 需要“解决替换”

【讨论】:

【参考方案7】:

如果您(或本例中的互联网,因为此问题是此问题的第一个结果)正在测试 Mailgun,如果您使用端口 25,则可能会收到此错误。将端口更改为 587 有效,即使他们的文档/快速链接显示 25 可以使用。

【讨论】:

很有趣,端口 587 对我不起作用,端口 25 修复了它。【参考方案8】:

我将这些添加到 CentOS7 中的 /etc/gai.conf 中,它起作用了。

label       ::1/128        0
label       ::/0           1
label       2002::/16      2
label       ::/96          3
label       ::ffff:0:0/96  4
precedence  ::1/128        50
precedence  ::/0           40
precedence  2002::/16      30
precedence  ::/96          20
precedence  ::ffff:0:0/96  100

http://blog.asiantuntijakaveri.fi/2014/12/prefer-ipv4-over-ipv6-on-centos-6.html:title

【讨论】:

以上是关于Rails Mailer “Net::OpenTimeout: execution expired” 仅在生产服务器上出现异常的主要内容,如果未能解决你的问题,请参考以下文章

在 Rails 3.1 中为 Mailer 和 View 提供自定义助手

Rails 4.1 Mailer预览和设计自定义电子邮件

Rails Mailer 引用可打印替换 = 由 =3D

用于 webmail 的 rails 4 action mailer 设置 (SMTP)

Rails Action Mailer Document

Rails 5 mailer Net::SMTPFatalError 发送电子邮件时