You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by di...@apache.org on 2021/12/16 17:30:39 UTC

[allura] branch dw/smtp_line_length created (now ac7e02c)

This is an automated email from the ASF dual-hosted git repository.

dill0wn pushed a change to branch dw/smtp_line_length
in repository https://gitbox.apache.org/repos/asf/allura.git.


      at ac7e02c  fix email headers being longer than SMTP limit

This branch includes the following new commits:

     new ac7e02c  fix email headers being longer than SMTP limit

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


[allura] 01/01: fix email headers being longer than SMTP limit

Posted by di...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

dill0wn pushed a commit to branch dw/smtp_line_length
in repository https://gitbox.apache.org/repos/asf/allura.git

commit ac7e02c01b7a643157f8fb62aa384b0d3cdd1aab
Author: Dillon Walls <di...@slashdotmedia.com>
AuthorDate: Thu Dec 16 17:30:33 2021 +0000

    fix email headers being longer than SMTP limit
---
 Allura/allura/lib/mail_util.py    | 27 +++++++++++++++++++++------
 Allura/allura/tests/test_tasks.py |  6 ++++--
 2 files changed, 25 insertions(+), 8 deletions(-)

diff --git a/Allura/allura/lib/mail_util.py b/Allura/allura/lib/mail_util.py
index 9b50e46..36a3b19 100644
--- a/Allura/allura/lib/mail_util.py
+++ b/Allura/allura/lib/mail_util.py
@@ -17,6 +17,7 @@
 
 from __future__ import unicode_literals
 from __future__ import absolute_import
+from __future__ import annotations
 import re
 import logging
 import smtplib
@@ -24,6 +25,7 @@ import email.parser
 from six.moves.email_mime_multipart import MIMEMultipart
 from six.moves.email_mime_text import MIMEText
 from email import header
+import typing
 
 import six
 import tg
@@ -37,6 +39,9 @@ from allura.lib import exceptions as exc
 from allura.lib import helpers as h
 from six.moves import map
 
+if typing.TYPE_CHECKING:
+    from email.message import EmailMessage
+
 log = logging.getLogger(__name__)
 
 RE_MESSAGE_ID = re.compile(r'<(?:[^>]*/)?([^>]*)>')
@@ -47,6 +52,9 @@ config = ConfigProxy(
 )
 EMAIL_VALIDATOR = fev.Email(not_empty=True)
 
+# http://www.jebriggs.com/blog/2010/07/smtp-maximum-line-lengths/
+MAX_MAIL_LINE_OCTETS = 998  # RFC 1000 - len(CRLF)
+
 
 def Header(text, *more_text):
     '''Helper to make sure we encode headers properly'''
@@ -190,10 +198,6 @@ def identify_sender(peer, email_address, headers, msg):
     return M.User.anonymous()
 
 
-# http://www.jebriggs.com/blog/2010/07/smtp-maximum-line-lengths/
-MAX_MAIL_LINE_OCTETS = 990
-
-
 def encode_email_part(content, content_type):
     try:
         # simplest email - plain ascii
@@ -264,7 +268,7 @@ class SMTPClient(object):
         self._client = None
 
     def sendmail(
-            self, addrs, fromaddr, reply_to, subject, message_id, in_reply_to, message,
+            self, addrs, fromaddr, reply_to, subject, message_id, in_reply_to, message: EmailMessage,
             sender=None, references=None, cc=None, to=None):
         if not addrs:
             return
@@ -291,7 +295,18 @@ class SMTPClient(object):
         if references:
             references = ['<%s>' % r for r in aslist(references)]
             message['References'] = Header(*references)
-        content = message.as_string()
+
+        # Kind of Hacky, but...
+        #   Certain headers, like 'References' can become very long when sent via reply
+        #   from deep inside a ticket thread. message.as_string allows you to pass a
+        #   maxheaderlen which splits long lines for you to fit inside your exim constraints.
+        #   HOWEVER, that flag doesn't take the header name length into account. So, this
+        #   somewhat hacky code approximates the longest 'Header-Name: ' prefix and makes sure
+        #   the line octet length takes that into account.
+        longest_header_len = max(len(h[0]) for h in message._headers)
+        max_header_len = MAX_MAIL_LINE_OCTETS - (2 + longest_header_len)
+
+        content = message.as_string(maxheaderlen=max_header_len)
         smtp_addrs = list(map(_parse_smtp_addr, addrs))
         smtp_addrs = [a for a in smtp_addrs if isvalid(a)]
         if not smtp_addrs:
diff --git a/Allura/allura/tests/test_tasks.py b/Allura/allura/tests/test_tasks.py
index 7c73399..6ac5691 100644
--- a/Allura/allura/tests/test_tasks.py
+++ b/Allura/allura/tests/test_tasks.py
@@ -34,7 +34,7 @@ import mock
 from tg import tmpl_context as c, app_globals as g
 
 from datadiff.tools import assert_equal
-from nose.tools import assert_in, assert_less
+from nose.tools import assert_in, assert_less, assert_less_equal
 from ming.orm import FieldProperty, Mapper
 from ming.orm import ThreadLocalORMSession
 from testfixtures import LogCapture
@@ -46,6 +46,7 @@ from allura.command.taskd import TaskdCommand
 from allura.lib import helpers as h
 from allura.lib import search
 from allura.lib.exceptions import CompoundError
+from allura.lib.mail_util import MAX_MAIL_LINE_OCTETS
 from allura.tasks import event_tasks
 from allura.tasks import index_tasks
 from allura.tasks import mail_tasks
@@ -475,12 +476,13 @@ class TestMailTasks(unittest.TestCase):
                 text=('0123456789' * 100) + '\n\n' + ('Громады стро ' * 100),
                 reply_to=g.noreply,
                 subject='По оживлённым берегам',
+                references=['foo@example.com'] * 100,  # needs to handle really long headers as well
                 message_id=h.gen_message_id())
             return_path, rcpts, body = _client.sendmail.call_args[0]
             body = body.split('\n')
 
             for line in body:
-                assert_less(len(line), 991)
+                assert_less_equal(len(line), MAX_MAIL_LINE_OCTETS)
 
             # plain text
             assert_in('012345678901234567890123456789012345678901234567890123456789012345678901234=', body)