This is an automated email from the ASF dual-hosted git repository. dill0wn pushed a commit to branch dw/8404 in repository https://gitbox.apache.org/repos/asf/allura.git
commit 6184203235ac6f83c943fae7fd3fef54678f9ed7 Author: Dillon Walls <[email protected]> AuthorDate: Thu Dec 16 17:30:33 2021 +0000 [#8404] fix email headers being longer than SMTP limit --- Allura/allura/lib/mail_util.py | 23 +++++++++++++++++------ Allura/allura/tests/test_tasks.py | 6 ++++-- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/Allura/allura/lib/mail_util.py b/Allura/allura/lib/mail_util.py index 9b50e46..00a6e71 100644 --- a/Allura/allura/lib/mail_util.py +++ b/Allura/allura/lib/mail_util.py @@ -24,6 +24,7 @@ import email.parser from six.moves.email_mime_multipart import MIMEMultipart from six.moves.email_mime_text import MIMEText from email import header +from email.message import EmailMessage import six import tg @@ -47,6 +48,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 = 990 + def Header(text, *more_text): '''Helper to make sure we encode headers properly''' @@ -190,10 +194,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 +264,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 +291,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=['[email protected]'] * 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)
