Skip to content

Commit

Permalink
Merge 7643231 into cff9a7d
Browse files Browse the repository at this point in the history
  • Loading branch information
viktordick committed Jul 21, 2020
2 parents cff9a7d + 7643231 commit e82e842
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 47 deletions.
27 changes: 21 additions & 6 deletions src/zope/sendmail/delivery.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,16 +103,31 @@ def newMessageId(self):
return "%s@%s" % (left_part, gethostname())

def send(self, fromaddr, toaddrs, message):
parser = email.parser.Parser()
msg = parser.parsestr(message)
messageid = msg.get('Message-Id')
# Switch the message to be bytes immediately, any encoding
# peculiarities should be handled before.
if message is None:
header = b''
else:
if not isinstance(message, bytes):
message = message.encode('utf-8')
# determine line separator type (assumes consistency)
nli = message.find(b'\n')
line_sep = b'\n' if nli < 1 or message[nli - 1] != b'\r' \
else b'\r\n'
header = message.split(line_sep * 2, 1)[0]

if bytes is str:
parse = email.parser.Parser().parsestr # pragma: PY2
else:
parse = email.parser.BytesParser().parsebytes # pragma: PY3
messageid = parse(header).get('Message-Id')
if messageid:
if not messageid.startswith('<') or not messageid.endswith('>'):
raise ValueError('Malformed Message-Id header')
messageid = messageid[1:-1]
else:
messageid = self.newMessageId()
message = 'Message-Id: <%s>\n%s' % (messageid, message)
message = b'Message-Id: <%s>\n%s' % (messageid.encode(), message)
transaction.get().join(
self.createDataManager(fromaddr, toaddrs, message))
return messageid
Expand Down Expand Up @@ -157,8 +172,8 @@ def __init__(self, queuePath):
def createDataManager(self, fromaddr, toaddrs, message):
maildir = Maildir(self.queuePath, True)
msg = maildir.newMessage()
msg.write('X-Zope-From: %s\n' % fromaddr)
msg.write('X-Zope-To: %s\n' % ", ".join(toaddrs))
msg.write(b'X-Zope-From: %s\n' % fromaddr.encode())
msg.write(b'X-Zope-To: %s\n' % ", ".join(toaddrs).encode())
msg.write(message)
msg.close()
return MailDataManager(msg.commit, onAbort=msg.abort)
16 changes: 8 additions & 8 deletions src/zope/sendmail/queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,17 +150,17 @@ def _parseMessage(self, message):
rest = ""

try:
first, second, rest = message.split('\n', 2)
first, second, rest = message.split(b'\n', 2)
except ValueError:
return fromaddr, toaddrs, message

if first.startswith("X-Zope-From: "):
i = len("X-Zope-From: ")
fromaddr = first[i:]
if first.startswith(b"X-Zope-From: "):
i = len(b"X-Zope-From: ")
fromaddr = first[i:].decode()

if second.startswith("X-Zope-To: "):
i = len("X-Zope-To: ")
toaddrs = tuple(second[i:].split(", "))
if second.startswith(b"X-Zope-To: "):
i = len(b"X-Zope-To: ")
toaddrs = tuple(addr.decode() for addr in second[i:].split(b", "))

return fromaddr, toaddrs, rest

Expand Down Expand Up @@ -275,7 +275,7 @@ def _process_one_file(self, filename):
# XXX: Silently ignoring all other causes here.

# read message file and send contents
with open(filename) as f:
with open(filename, 'rb') as f:
message = f.read()

fromaddr, toaddrs, message = self._parseMessage(message)
Expand Down
68 changes: 41 additions & 27 deletions src/zope/sendmail/tests/test_delivery.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ class TestAbstractMailDelivery(unittest.TestCase):

def test_bad_message_id(self):
class Parser(object):
def parsestr(self, s):
def parsestr(self, s, headersonly=False):
return {'Message-Id': 'bad id'}

import email.parser
Expand All @@ -131,26 +131,36 @@ def testInterface(self):
verifyObject(IDirectMailDelivery, delivery)
self.assertEqual(delivery.mailer, mailer)

def testSend(self):
def testSend(self, send_unicode=False):
mailer = MailerStub()
delivery = DirectMailDelivery(mailer)
fromaddr = 'Jim <jim@example.com'
toaddrs = ('Guido <guido@example.com>',
'Steve <steve@examplecom>')
opt_headers = ('From: Jim <jim@example.org>\n'
'To: some-zope-coders:;\n'
'Date: Mon, 19 May 2003 10:17:36 -0400\n'
'Message-Id: <20030519.1234@example.org>\n')
message = ('Subject: example\n'
'\n'
'This is just an example\n')
opt_headers = (b'From: Jim <jim@example.org>\n'
b'To: some-zope-coders:;\n'
b'Date: Mon, 19 May 2003 10:17:36 -0400\n'
b'Message-Id: <20030519.1234@example.org>\n')
message = (b'Subject: example\n'
b'\n'
b'This is just an example\n')

if send_unicode:
opt_headers_bytes = opt_headers
opt_headers = opt_headers.decode('utf-8')
message_bytes = message + b'\xc3\xa4'
message = message_bytes.decode('utf-8')
else:
message_bytes = message
opt_headers_bytes = opt_headers

msgid = delivery.send(fromaddr, toaddrs, opt_headers + message)
self.assertEqual(msgid, '20030519.1234@example.org')
self.assertEqual(mailer.sent_messages, [])
transaction.commit()
self.assertEqual(mailer.sent_messages,
[(fromaddr, toaddrs, opt_headers + message)])
[(fromaddr, toaddrs,
opt_headers_bytes + message_bytes)])

mailer.sent_messages = []
msgid = delivery.send(fromaddr, toaddrs, message)
Expand All @@ -160,16 +170,19 @@ def testSend(self):
self.assertEqual(len(mailer.sent_messages), 1)
self.assertEqual(mailer.sent_messages[0][0], fromaddr)
self.assertEqual(mailer.sent_messages[0][1], toaddrs)
self.assertTrue(mailer.sent_messages[0][2].endswith(message))
new_headers = mailer.sent_messages[0][2][:-len(message)]
self.assertIn('Message-Id: <%s>' % msgid, new_headers)
self.assertTrue(mailer.sent_messages[0][2].endswith(message_bytes))
new_headers = mailer.sent_messages[0][2][:-len(message_bytes)]
self.assertIn(('Message-Id: <%s>' % msgid).encode(), new_headers)

mailer.sent_messages = []
msgid = delivery.send(fromaddr, toaddrs, opt_headers + message)
self.assertEqual(mailer.sent_messages, [])
transaction.abort()
self.assertEqual(mailer.sent_messages, [])

def testSendUnicode(self):
self.testSend(send_unicode=True)

def testBrokenMailerErrorsAreEaten(self):
from zope.testing.loggingsupport import InstalledHandler
mailer = BrokenMailerStub()
Expand Down Expand Up @@ -234,7 +247,7 @@ def send(self):

class MaildirWriterStub(object):

data = ''
data = b''
commited_messages = [] # this list is shared among all instances
aborted_messages = [] # this one too
_closed = False
Expand Down Expand Up @@ -296,7 +309,7 @@ class WritableMaildirStub(MaildirStub):
STUB_DEFAULT_MESSAGE_SENT = (
'foo@example.com',
('bar@example.com', 'baz@example.com'),
'Header: value\n\nBody\n')
b'Header: value\n\nBody\n')

STUB_DEFAULT_MESSAGE_RECPT = ('bar@example.com', 'baz@example.com')

Expand Down Expand Up @@ -431,15 +444,15 @@ def testSend(self):
fromaddr = 'jim@example.com'
toaddrs = ('guido@example.com',
'steve@examplecom')
zope_headers = ('X-Zope-From: jim@example.com\n'
'X-Zope-To: guido@example.com, steve@examplecom\n')
opt_headers = ('From: Jim <jim@example.org>\n'
'To: some-zope-coders:;\n'
'Date: Mon, 19 May 2003 10:17:36 -0400\n'
'Message-Id: <20030519.1234@example.org>\n')
message = ('Subject: example\n'
'\n'
'This is just an example\n')
zope_headers = (b'X-Zope-From: jim@example.com\n'
b'X-Zope-To: guido@example.com, steve@examplecom\n')
opt_headers = (b'From: Jim <jim@example.org>\n'
b'To: some-zope-coders:;\n'
b'Date: Mon, 19 May 2003 10:17:36 -0400\n'
b'Message-Id: <20030519.1234@example.org>\n')
message = (b'Subject: example\n'
b'\n'
b'This is just an example\n')

msgid = delivery.send(fromaddr, toaddrs, opt_headers + message)
self.assertEqual(msgid, '20030519.1234@example.org')
Expand All @@ -461,9 +474,10 @@ def testSend(self):
MaildirWriterStub.commited_messages[0].endswith(message)
)
new_headers = MaildirWriterStub.commited_messages[0][:-len(message)]
self.assertIn('Message-Id: <%s>' % msgid, new_headers)
self.assertIn('X-Zope-From: %s' % fromaddr, new_headers)
self.assertIn('X-Zope-To: %s' % ", ".join(toaddrs), new_headers)
self.assertIn(('Message-Id: <%s>' % msgid).encode(), new_headers)
self.assertIn(('X-Zope-From: %s' % fromaddr).encode(), new_headers)
self.assertIn(('X-Zope-To: %s' % ", ".join(toaddrs)).encode(),
new_headers)
self.assertEqual(MaildirWriterStub.aborted_messages, [])

MaildirWriterStub.commited_messages = []
Expand Down
12 changes: 6 additions & 6 deletions src/zope/sendmail/tests/test_queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,18 +143,18 @@ def test_threadName(self):
"zope.sendmail.queue.QueueProcessorThread")

def test_parseMessage(self):
hdr = ('X-Zope-From: foo@example.com\n'
'X-Zope-To: bar@example.com, baz@example.com\n')
msg = ('Header: value\n'
'\n'
'Body\n')
hdr = (b'X-Zope-From: foo@example.com\n'
b'X-Zope-To: bar@example.com, baz@example.com\n')
msg = (b'Header: value\n'
b'\n'
b'Body\n')
f, t, m = self.thread._parseMessage(hdr + msg)
self.assertEqual(f, 'foo@example.com')
self.assertEqual(t, ('bar@example.com', 'baz@example.com'))
self.assertEqual(m, msg)

def test_parseMessage_error(self):
msg = "bad message"
msg = b"bad message"
f, t, m = self.thread._parseMessage(msg)
self.assertEqual(f, "")
self.assertEqual(t, ())
Expand Down

0 comments on commit e82e842

Please sign in to comment.