Browse Source

Fixed issue #2423 - Unable to update already configured email channel, verify email will not arrive.

Martin Edenhofer 6 years ago
parent
commit
6faaee3a97
3 changed files with 77 additions and 10 deletions
  1. 54 6
      app/models/channel/driver/imap.rb
  2. 19 3
      app/models/channel/driver/pop3.rb
  3. 4 1
      lib/email_helper/probe.rb

+ 54 - 6
app/models/channel/driver/imap.rb

@@ -145,11 +145,12 @@ example
         end
 
         # check how many content messages we have, for notice used
-        header = message_meta['RFC822.HEADER']
-        if header && header !~ /x-zammad-ignore/i
-          content_messages += 1
-          break if content_max_check < content_messages
-        end
+        headers = parse_headers(message_meta['RFC822.HEADER'])
+        next if messages_is_verify_message?(headers)
+        next if messages_is_ignore_message?(headers)
+
+        content_messages += 1
+        break if content_max_check < content_messages
       end
       if content_messages >= content_max_check
         content_messages = message_ids.count
@@ -207,9 +208,12 @@ example
 
       message_meta = nil
       timeout(1.minute) do
-        message_meta = @imap.fetch(message_id, ['RFC822.SIZE', 'ENVELOPE', 'FLAGS', 'INTERNALDATE'])[0]
+        message_meta = @imap.fetch(message_id, ['RFC822.SIZE', 'ENVELOPE', 'FLAGS', 'INTERNALDATE', 'RFC822.HEADER'])[0]
       end
 
+      # ignore verify messages
+      next if !messages_is_too_old_verify?(message_meta, count, count_all)
+
       # ignore to big messages
       info = too_big?(message_meta, count, count_all)
       if info
@@ -283,6 +287,50 @@ returns
 
   private
 
+  def messages_is_too_old_verify?(message_meta, count, count_all)
+    headers = parse_headers(message_meta.attr['RFC822.HEADER'])
+    return true if !messages_is_verify_message?(headers)
+    return true if headers['X-Zammad-Verify-Time'].blank?
+
+    begin
+      verify_time = Time.zone.parse(headers['X-Zammad-Verify-Time'])
+    rescue => e
+      Rails.logger.error e
+      return true
+    end
+    return true if verify_time < Time.zone.now - 30.minutes
+
+    Rails.logger.info "  - ignore message #{count}/#{count_all} - because message has a verify message"
+
+    false
+  end
+
+  def messages_is_verify_message?(headers)
+    return true if headers['X-Zammad-Verify'] == 'true'
+
+    false
+  end
+
+  def messages_is_ignore_message?(headers)
+    return true if headers['X-Zammad-Ignore'] == 'true'
+
+    false
+  end
+
+  def parse_headers(string)
+    return {} if string.blank?
+
+    headers = {}
+    headers_pairs = string.split("\r\n")
+    headers_pairs.each do |pair|
+      key_value = pair.split(': ')
+      next if key_value[0].blank?
+
+      headers[key_value[0]] = key_value[1]
+    end
+    headers
+  end
+
   # rubocop:disable Metrics/ParameterLists
   def already_imported?(message_id, message_meta, count, count_all, keep_on_server, channel)
     # rubocop:enable Metrics/ParameterLists

+ 19 - 3
app/models/channel/driver/pop3.rb

@@ -91,7 +91,7 @@ returns
         next if !mail
 
         # check how many content messages we have, for notice used
-        if !mail.match?(/x-zammad-ignore/i)
+        if !mail.match?(/(X-Zammad-Ignore: true|X-Zammad-Verify: true)/)
           content_messages += 1
           break if content_max_check < content_messages
         end
@@ -112,7 +112,7 @@ returns
       mails.reverse!
 
       # check for verify message
-      mails.each do |m|
+      mails.first(2000).each do |m|
         mail = m.pop
         next if !mail
 
@@ -137,12 +137,28 @@ returns
     count         = 0
     count_fetched = 0
     notice        = ''
-    mails.each do |m|
+    mails.first(2000).each do |m|
       count += 1
       Rails.logger.info " - message #{count}/#{count_all}"
       mail = m.pop
       next if !mail
 
+      # ignore verify messages
+      if mail.match?(/(X-Zammad-Ignore: true|X-Zammad-Verify: true)/)
+        if mail =~ /X-Zammad-Verify-Time:\s(.+?)\s/
+          begin
+            verify_time = Time.zone.parse($1)
+            if verify_time > Time.zone.now - 30.minutes
+              info = "  - ignore message #{count}/#{count_all} - because it's a verify message"
+              Rails.logger.info info
+              next
+            end
+          rescue => e
+            Rails.logger.error e
+          end
+        end
+      end
+
       # ignore to big messages
       max_message_size = Setting.get('postmaster_max_size').to_f
       real_message_size = mail.size.to_f / 1024 / 1024

+ 4 - 1
lib/email_helper/probe.rb

@@ -308,10 +308,13 @@ returns on fail
                  body:    "This is a Test Email of Zammad to verify if Zammad can send emails to an external address.\n\nIf you see this email, you can ignore and delete it.",
                }
              end
-      if subject
+      if subject.present?
         mail['X-Zammad-Test-Message'] = subject
       end
       mail['X-Zammad-Ignore']          = 'true'
+      mail['X-Zammad-Fqdn']            = Setting.get('fqdn')
+      mail['X-Zammad-Verify']          = 'true'
+      mail['X-Zammad-Verify-Time']     = Time.zone.now.iso8601
       mail['X-Loop']                   = 'yes'
       mail['Precedence']               = 'bulk'
       mail['Auto-Submitted']           = 'auto-generated'