diff --git a/CHANGELOG.rdoc b/CHANGELOG.rdoc index f8cbd326c..020301e3f 100644 --- a/CHANGELOG.rdoc +++ b/CHANGELOG.rdoc @@ -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 = '

' (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) diff --git a/lib/mail/mail.rb b/lib/mail/mail.rb index b715d281a..46515ec5e 100644 --- a/lib/mail/mail.rb +++ b/lib/mail/mail.rb @@ -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. @@ -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' diff --git a/lib/mail/message.rb b/lib/mail/message.rb index 285d28398..8bff53ab7 100644 --- a/lib/mail/message.rb +++ b/lib/mail/message.rb @@ -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: @@ -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 diff --git a/spec/mail/message_spec.rb b/spec/mail/message_spec.rb index 42b389b51..2218e328f 100644 --- a/spec/mail/message_spec.rb +++ b/spec/mail/message_spec.rb @@ -1799,6 +1799,59 @@ def self.delivering_email(mail) expect(mail.to).to eq ['fred@example.com'] 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