From 001c8cd0ee6e70cc96727cc37eedf263b916d24b Mon Sep 17 00:00:00 2001
From: Stan Hu <stanhu@gmail.com>
Date: Fri, 14 Aug 2015 22:21:22 -0700
Subject: [PATCH] Gracefully handle SMTP user input errors (e.g. incorrect
 email addresses) to prevent Sidekiq retries

Closes https://github.com/gitlabhq/gitlabhq/issues/9560
---
 CHANGELOG                                  |  1 +
 app/workers/emails_on_push_worker.rb       | 33 ++++++++++++---------
 spec/workers/emails_on_push_worker_spec.rb | 34 ++++++++++++++++++++++
 3 files changed, 54 insertions(+), 14 deletions(-)
 create mode 100644 spec/workers/emails_on_push_worker_spec.rb

diff --git a/CHANGELOG b/CHANGELOG
index 8214e57aaa7..6872ec16aa5 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -6,6 +6,7 @@ v 8.0.0 (unreleased)
   - Faster merge
   - Ability to fetch merge requests from refs/merge-requests/:id
   - Allow displaying of archived projects in the admin interface (Artem Sidorenko)
+  - Gracefully handle SMTP user input errors (e.g. incorrect email addresses) to prevent Sidekiq retries (Stan Hu)
 
 v 7.14.0 (unreleased)
   - Update default robots.txt rules to disallow crawling of irrelevant pages (Ben Bodenmiller)
diff --git a/app/workers/emails_on_push_worker.rb b/app/workers/emails_on_push_worker.rb
index 1d21addece6..916a99bb273 100644
--- a/app/workers/emails_on_push_worker.rb
+++ b/app/workers/emails_on_push_worker.rb
@@ -4,7 +4,7 @@ class EmailsOnPushWorker
   def perform(project_id, recipients, push_data, options = {})
     options.symbolize_keys!
     options.reverse_merge!(
-      send_from_committer_email:  false, 
+      send_from_committer_email:  false,
       disable_diffs:              false
     )
     send_from_committer_email = options[:send_from_committer_email]
@@ -16,9 +16,9 @@ class EmailsOnPushWorker
     ref = push_data["ref"]
     author_id = push_data["user_id"]
 
-    action = 
+    action =
       if Gitlab::Git.blank_ref?(before_sha)
-        :create 
+        :create
       elsif Gitlab::Git.blank_ref?(after_sha)
         :delete
       else
@@ -42,17 +42,22 @@ class EmailsOnPushWorker
     end
 
     recipients.split(" ").each do |recipient|
-      Notify.repository_push_email(
-        project_id, 
-        recipient, 
-        author_id:                  author_id, 
-        ref:                        ref, 
-        action:                     action,
-        compare:                    compare, 
-        reverse_compare:            reverse_compare,
-        send_from_committer_email:  send_from_committer_email,
-        disable_diffs:              disable_diffs
-      ).deliver
+      begin
+        Notify.repository_push_email(
+          project_id,
+          recipient,
+          author_id:                  author_id,
+          ref:                        ref,
+          action:                     action,
+          compare:                    compare,
+          reverse_compare:            reverse_compare,
+          send_from_committer_email:  send_from_committer_email,
+          disable_diffs:              disable_diffs
+        ).deliver
+      # These are input errors and won't be corrected even if Sidekiq retries
+      rescue Net::SMTPFatalError, Net::SMTPSyntaxError => e
+        logger.info("Failed to send e-mail for project '#{project.name_with_namespace}' to #{recipient}: #{e}")
+      end
     end
   ensure
     compare = nil
diff --git a/spec/workers/emails_on_push_worker_spec.rb b/spec/workers/emails_on_push_worker_spec.rb
new file mode 100644
index 00000000000..3600c771075
--- /dev/null
+++ b/spec/workers/emails_on_push_worker_spec.rb
@@ -0,0 +1,34 @@
+require 'spec_helper'
+
+describe EmailsOnPushWorker do
+  include RepoHelpers
+
+  let(:project) { create(:project) }
+  let(:user) { create(:user) }
+  let(:data) { Gitlab::PushDataBuilder.build_sample(project, user) }
+
+  subject { EmailsOnPushWorker.new }
+
+  before do
+    allow(Project).to receive(:find).and_return(project)
+  end
+
+  describe "#perform" do
+    it "sends mail" do
+      subject.perform(project.id, user.email, data.stringify_keys)
+
+      email = ActionMailer::Base.deliveries.last
+      expect(email.subject).to include('Change some files')
+      expect(email.to).to eq([user.email])
+    end
+
+    it "gracefully handles an input SMTP error" do
+      ActionMailer::Base.deliveries.clear
+      allow(Notify).to receive(:repository_push_email).and_raise(Net::SMTPFatalError)
+
+      subject.perform(project.id, user.email, data.stringify_keys)
+
+      expect(ActionMailer::Base.deliveries.count).to eq(0)
+    end
+  end
+end
-- 
GitLab