How to catch error exception in ActionMailer

20,152

Solution 1

I'm using something like this in the controller:

 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 "/"

Solution 2

This should work in any of your environment files. development.rb or production.rb

config.action_mailer.raise_delivery_errors = true

Solution 3

If you are sending a lot of emails, you can also keep your code more DRY and get notifications of exceptions to your email by doing something like this:

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

Utility Class:

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

Got my original inspiration from here: http://www.railsonmaui.com/blog/2013/05/08/strategies-for-rails-logging-and-error-handling/

Solution 4

class ApplicationMailer < ActionMailer::Base
  rescue_from [ExceptionThatShouldBeRescued] do |exception|
    #handle it here
  end
end

Works with rails 5 onwards. And it's the best practice.

Solution 5

This is inspired by the answer given by @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

The * is the splat operator. It expands an Array into a list of arguments.

More explanation about (*) splat operator

Share:
20,152
com
Author by

com

Updated on September 09, 2020

Comments

  • com
    com over 3 years

    The problem is how can I catch exception in delivering mail by ActionMailer. For me it sounds impossible, because in this case ActionMailer should sent mail to mailserver, and if mailserver returns error, ActionMailer should show me this error. I am interested only in counting undelivered mails.

    Do you have any ideas how to implement this? Thanks!