Skip to content

Add capability to register and unregister failure handlers #931

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.rdoc
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Features:
* #872 - Low-level option to include BCC field in the encoded message (grossadamm)
* #901 - Allow mail.text_part = '…' and mail.html_part = '<p>…</p>' (taavo)
* #924 - Matcher for having attachments (schepedw)
* #931 - Add capability to add and remove failure handlers (j-concepcion and ramontayag)

Performance:
* #956 - Use native String#encode for CR/LF conversion (carsonreinke)
Expand Down
19 changes: 19 additions & 0 deletions lib/mail/mail.rb
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ def Mail.connection(&block)
# Initialize the observers and interceptors arrays
@@delivery_notification_observers = []
@@delivery_interceptors = []
@@failure_handlers = []

# You can register an object to be informed of every email that is sent through
# this method.
Expand Down Expand Up @@ -243,6 +244,24 @@ def self.inform_interceptors(mail)
end
end

# Manage failure handlers that will be triggered whenever an email delivery
# raises an exception.
def self.register_failure_handler(handler)
unless @@failure_handlers.include?(handler)
@@failure_handlers << handler
end
end

def self.unregister_failure_handler(handler)
@@failure_handlers.delete(handler)
end

def self.inform_failure_handlers(mail, error)
@@failure_handlers.each do |handler|
handler.failed_mail(mail, error)
end
end

protected

RANDOM_TAG='%x%x_%x%x%d%x'
Expand Down
5 changes: 5 additions & 0 deletions lib/mail/message.rb
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,10 @@ def inform_interceptors
Mail.inform_interceptors(self)
end

def inform_failure_handlers(error)
Mail.inform_failure_handlers(self, error)
end

# Delivers an mail object.
#
# Examples:
Expand Down Expand Up @@ -2148,6 +2152,7 @@ def do_delivery
delivery_method.deliver!(self)
end
rescue => e # Net::SMTP errors or sendmail pipe errors
inform_failure_handlers e
raise e if raise_delivery_errors
end
end
Expand Down
53 changes: 53 additions & 0 deletions spec/mail/message_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1799,6 +1799,59 @@ def self.delivering_email(mail)
expect(mail.to).to eq ['[email protected]']
end

it "should trigger failure handlers when there's an exception" do
failed_handler_class = Class.new do
def self.failed_mail(mail, error)
end
end

Mail.register_failure_handler(failed_handler_class)
mail = Mail.new
mail.raise_delivery_errors = false

error = StandardError.new("something went wrong")
allow(mail.delivery_method).to receive(:deliver!).
and_raise(error)

expect(failed_handler_class).to receive(:failed_mail).
with(mail, error)

mail.deliver

Mail.unregister_failure_handler(failed_handler_class)
end

it "should allow failure handlers to be unregistered" do
failed_handler_class = Class.new do
def self.failed_mail(mail, error)
end
end

Mail.register_failure_handler(failed_handler_class)
Mail.unregister_failure_handler(failed_handler_class)
mail = Mail.new
mail.raise_delivery_errors = false

error = StandardError.new("something went wrong")
allow(mail.delivery_method).to receive(:deliver!).
and_raise(error)

expect(failed_handler_class).to_not receive(:failed_mail).
with(mail, error)

mail.deliver
end

it "does not blow up when there is a failure and no failure_handler is set" do
mail = Mail.new
mail.raise_delivery_errors = false

error = StandardError.new("something went wrong")
allow(mail.delivery_method).to receive(:deliver!).
and_raise(error)

expect { mail.deliver }.to_not raise_error
end
end

describe "error handling" do
Expand Down