Rails 4 ActionMailer - 如何在使用 Deliver_later 时捕获连接和 SMTP 错误

Posted

技术标签:

【中文标题】Rails 4 ActionMailer - 如何在使用 Deliver_later 时捕获连接和 SMTP 错误【英文标题】:Rails 4 ActionMailer - How to capture connection and SMTP errors when using deliver_later 【发布时间】:2015-11-11 05:16:00 【问题描述】:

我正在使用 ActionMailer deliver_later w ActiveJobs / Sidekiq 使用:

config.active_job.queue_adapter = :sidekiq

当我在开发模式下使用 MailCatcher 进行测试时,我能捕捉到的唯一错误是 Errno::ECONNREFUSED,设置端口 1026 而不是 1025

当我测试 Deliver_now 时,我得到了 Errno::ECONNREFUSED 错误,这很好

begin
   MessageMailer.contact_me_email(@message).deliver_now
   rescue Errno::ECONNREFUSED, Net::SMTPAuthenticationError, Net::SMTPServerBusy, Net::SMTPSyntaxError, Net::SMTPFatalError, Net::SMTPUnknownError => e
     flash[:error] = "Problems sending mail. Please try again later"
     # delete message or resend it ?
     byebug
     @message.destroy
     format.html  render :new 
   end

但是,当我请求deliver_later时,请求在sidekiq邮件队列中很痛苦,并且错误没有被捕获......

       begin
   MessageMailer.contact_me_email(@message).deliver_later(wait: 1.minute ) # in mailers queue
   rescue Errno::ECONNREFUSED, Net::SMTPAuthenticationError, Net::SMTPServerBusy, Net::SMTPSyntaxError, Net::SMTPFatalError, Net::SMTPUnknownError => e
     flash[:error] = "Problems sending mail. Please try again later"
     # delete message or resend it ?
     byebug
     @message.destroy
     format.html  render :new 
   end

在这种情况下,我如何捕获和挽救 SMTP 错误?我想这是 Sidekiq 的责任来处理它......欢迎任何提示......

【问题讨论】:

【参考方案1】:

ActiveJobs 允许您挽救使用rescue_from 方法执行作业时发生的错误。见the api。您需要在 ActiveJob 子类中实现此方法。

由于 ActionMailer 使用 DeliveryJobs 将消息作为作业传递,因此您需要向此类添加一个 rescue_from 方法来处理异常。

例如,您可以输入config/initializers/action_mailer.rb

ActionMailer::DeliveryJob.rescue_from(StandardError) do |exception|
    Rails.logger.error "Original record not found: #@serialized_arguments.join(', ')"
end

这将彻底拯救任何标准错误,并简单地记录它们而不是引发异常。我自己实现了这个来让 Rollbar 安静。

由于这是一个极端情况,因此最好也对其进行测试:

spec/initializers/action_mailer_spec.rb:

RSpec.describe 'ActionMailer::DeliveryJob error recovery' do

   it 'should log the deserialization errors' do
     @user = create(:user)
     MyCustomMailer.send_something(@user).deliver_later
     @user.destroy

     expect(Rails.logger).to receive(:error).at_least(:once)
     Delayed::Worker.new.work_off
   end

end

【讨论】:

以上是关于Rails 4 ActionMailer - 如何在使用 Deliver_later 时捕获连接和 SMTP 错误的主要内容,如果未能解决你的问题,请参考以下文章

ActionMailer 在开发 Rails 4 中不发送邮件

Rails 4 ActionMailer 与 gmail Net::SMTPAuthenticationError: 534-5.7.14

Rails-如何测试ActionMailer发送了特定附件?

Rails - 你如何测试 ActionMailer 在测试中发送了特定的电子邮件

如何使用 Actionmailer/Ruby on Rails 发送具有多个动态 smtp 的电子邮件

Rails 中 ActionMailer Mandrill 的问题