如何在 ActionMailer 中捕获错误异常

Posted

技术标签:

【中文标题】如何在 ActionMailer 中捕获错误异常【英文标题】:How to catch error exception in ActionMailer 【发布时间】:2012-02-01 08:35:26 【问题描述】:

问题是如何在 ActionMailer 发送邮件时捕获异常。对我来说这听起来不可能,因为在这种情况下 ActionMailer 应该向邮件服务器发送邮件,如果邮件服务器返回错误,ActionMailer 应该向我显示这个错误。我只对计算未投递的邮件感兴趣。

您有任何想法如何实施吗? 谢谢!

【问题讨论】:

【参考方案1】:

这是受到@sukeerthi-adiga给出的答案的启发

class ApplicationMailer < ActionMailer::Base
  # Add other exceptions you want rescued in the array below
  ERRORS_TO_RESCUE = [
    Net::SMTPAuthenticationError,
    Net::SMTPServerBusy,
    Net::SMTPSyntaxError,
    Net::SMTPFatalError,
    Net::SMTPUnknownError,
    Errno::ECONNREFUSED
  ]

  rescue_from *ERRORS_TO_RESCUE do |exception|
    # Handle it here
    Rails.logger.error("failed to send email")
  end

end

* 是 splat 运算符。它将一个 Array 扩展为一个参数列表。

More explanation about (*) splat operator

【讨论】:

【参考方案2】:
class ApplicationMailer < ActionMailer::Base
  rescue_from [ExceptionThatShouldBeRescued] do |exception|
    #handle it here
  end
end

适用于 Rails 5 以后。这是最佳做法。

【讨论】:

并确保其他邮件程序类继承自 ApplicationMailer【参考方案3】:

这应该适用于您的任何环境文件。 development.rbproduction.rb

config.action_mailer.raise_delivery_errors = true

【讨论】:

我不想向用户显示异常,我只需要识别交付失败 只要你抢救处理,用户就不会看到异常!我还喜欢向 Airbrake 或一些异常通知服务报告事情,以便我们知道事情是否失败——即使他们得到了愉快的处理。【参考方案4】:

如果您要发送大量电子邮件,您还可以通过执行以下操作使您的代码更加干燥并获得电子邮件异常通知:

status = Utility.try_delivering_email do
  ClientMailer.signup_confirmation(@client).deliver
end

unless status
  flash.now[:error] = "Something went wrong when we tried sending you and email :("
end

实用类:

class Utility
  # Logs and emails exception
  # Optional args:
  # request: request Used for the ExceptionNotifier
  # info: "A descriptive messsage"
  def self.log_exception(e, args = )
    extra_info = args[:info]

    Rails.logger.error extra_info if extra_info
    Rails.logger.error e.message
    st = e.backtrace.join("\n")
    Rails.logger.error st

    extra_info ||= "<NO DETAILS>"
    request = args[:request]
    env = request ? request.env : 
    ExceptionNotifier::Notifier.exception_notification(env, e, :data => :message => "Exception: #extra_info").deliver
  end

  def self.try_delivering_email(options = , &block)
    begin
      yield
      return true
    rescue  EOFError,
            IOError,
            TimeoutError,
            Errno::ECONNRESET,
            Errno::ECONNABORTED,
            Errno::EPIPE,
            Errno::ETIMEDOUT,
            Net::SMTPAuthenticationError,
            Net::SMTPServerBusy,
            Net::SMTPSyntaxError,
            Net::SMTPUnknownError,
            OpenSSL::SSL::SSLError => e
      log_exception(e, options)
      return false
    end
  end
end

我最初的灵感来自这里:http://www.railsonmaui.com/blog/2013/05/08/strategies-for-rails-logging-and-error-handling/

【讨论】:

它不需要是一个类。只是一个模块,你可以用module_function定义方法【参考方案5】:

我在控制器中使用这样的东西:

 if @user.save
      begin
      UserMailer.welcome_email(@user).deliver
      flash[:success] = "#@user.name created"
      rescue Net::SMTPAuthenticationError, Net::SMTPServerBusy, Net::SMTPSyntaxError, Net::SMTPFatalError, Net::SMTPUnknownError => e
        flash[:success] = "Utente #@user.name creato. Problems sending mail"
      end
      redirect_to "/"

【讨论】:

以上是关于如何在 ActionMailer 中捕获错误异常的主要内容,如果未能解决你的问题,请参考以下文章

iOS异常信号的捕获和简单处理

异常的捕获和处理

捕获异常

php 异常处理 如何捕获异常??必须要抛出才可以吗?

前端JavaScript 常见的报错及异常捕获

错误与异常