From 3995ef98a3f7feb75f1aeb652e6afe40a5c94def Mon Sep 17 00:00:00 2001 From: Steven Buccini Date: Sat, 3 Dec 2016 10:59:41 -0800 Subject: [PATCH 1/8] In Python 2.7, encode strings in add_header() as ASCII (#72) * In Python 2, encode other strings in add_header() calls into ASCII so getting this filename does not cause Unicode errors * Fix test compatibility in Python3 --- marrow/mailer/message.py | 13 ++++++++++--- test/test_message.py | 23 +++++++++++++++++++++++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/marrow/mailer/message.py b/marrow/mailer/message.py index 2f83f9d..16d36f8 100644 --- a/marrow/mailer/message.py +++ b/marrow/mailer/message.py @@ -322,11 +322,18 @@ def attach(self, name, data=None, maintype=None, subtype=None, filename=(filename_charset, filename_language, filename) if inline: - part.add_header('Content-Disposition', 'inline', filename=filename) - part.add_header('Content-ID', '<%s>' % filename) + if sys.version_info < (3, 0): + part.add_header('Content-Disposition'.encode('utf-8'), 'inline'.encode('utf-8'), filename=filename) + part.add_header('Content-ID'.encode('utf-8'), '<%s>'.encode('utf-8') % filename) + else: + part.add_header('Content-Disposition', 'inline', filename=filename) + part.add_header('Content-ID', '<%s>' % filename) self.embedded.append(part) else: - part.add_header('Content-Disposition', 'attachment', filename=filename) + if sys.version_info < (3, 0): + part.add_header('Content-Disposition'.encode('utf-8'), 'attachment'.encode('utf-8'), filename=filename) + else: + part.add_header('Content-Disposition', 'attachment', filename=filename) self.attachments.append(part) def embed(self, name, data=None): diff --git a/test/test_message.py b/test/test_message.py index f014155..3c97f04 100644 --- a/test/test_message.py +++ b/test/test_message.py @@ -281,6 +281,29 @@ def test_mime_embed_failures(self): with pytest.raises(TypeError): message.embed('test.gif', object()) + + def test_that_add_header_and_collapse_header_are_inverses_ascii_filename(self): + message = self.build_message() + message.plain = "Hello world." + message.rich = "Farewell cruel world." + message.attach("wat.txt", b"not a unicode snowman") # calls add_header() under the covers + attachment = message.attachments[0] + filename = attachment.get_filename() # calls email.utils.collapse_rfc2231_value() under the covers + assert filename == "wat.txt" + + def test_that_add_header_and_collapse_header_are_inverses_non_ascii_filename(self): + message = self.build_message() + message.plain = "Hello world." + message.rich = "Farewell cruel world." + message.attach("☃.txt", b"unicode snowman", filename_language='en-us') + attachment = message.attachments[0] + filename = attachment.get_param('filename', object(), 'content-disposition') # get_filename() calls this under the covers + assert isinstance(filename, tuple) # Since attachment encoded according to RFC2231, should be represented as a tuple + filename = attachment.get_filename() # Calls email.utils.collapse_rfc2231_value() under the covers, currently fails + if sys.version_info < (3, 0): + assert isinstance(filename, basestring) # Successfully converts tuple to a string + else: + assert isinstance(filename, str) def test_recipients_collection(self): message = self.build_message() From 71863ce557ca0d68bef462377d0c9dd18c276a25 Mon Sep 17 00:00:00 2001 From: Alice Bevan-McGregor Date: Wed, 4 Sep 2019 19:17:40 -0400 Subject: [PATCH 2/8] Automatically add Message-Id header, if missing, when building the MIME serialization. Work on #81. --- marrow/mailer/message.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/marrow/mailer/message.py b/marrow/mailer/message.py index 16d36f8..86b9573 100644 --- a/marrow/mailer/message.py +++ b/marrow/mailer/message.py @@ -191,6 +191,9 @@ def _build_header_list(self, author, sender): else: headers.extend(self.headers) + if 'message-id' not in (i[0].lower() for header in headers): + headers.append('Message-Id', self.id) + return headers def _add_headers_to_message(self, message, headers): From 9c6e49355120b7f19d2ce2f2ae25bb21fe3a06de Mon Sep 17 00:00:00 2001 From: Alice Bevan-McGregor Date: Wed, 4 Sep 2019 19:21:01 -0400 Subject: [PATCH 3/8] Well that was silly; additional work on #81. --- marrow/mailer/message.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/marrow/mailer/message.py b/marrow/mailer/message.py index 86b9573..97e699b 100644 --- a/marrow/mailer/message.py +++ b/marrow/mailer/message.py @@ -191,7 +191,7 @@ def _build_header_list(self, author, sender): else: headers.extend(self.headers) - if 'message-id' not in (i[0].lower() for header in headers): + if 'message-id' not in (header[0].lower() for header in headers): headers.append('Message-Id', self.id) return headers From 0dd77ca21564339a836af4dd274bb96a0fe159ea Mon Sep 17 00:00:00 2001 From: Alice Bevan-McGregor Date: Wed, 4 Sep 2019 19:26:57 -0400 Subject: [PATCH 4/8] Need sleep. Work on #81. --- marrow/mailer/message.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/marrow/mailer/message.py b/marrow/mailer/message.py index 97e699b..7e0cb77 100644 --- a/marrow/mailer/message.py +++ b/marrow/mailer/message.py @@ -192,7 +192,7 @@ def _build_header_list(self, author, sender): headers.extend(self.headers) if 'message-id' not in (header[0].lower() for header in headers): - headers.append('Message-Id', self.id) + headers.append(('Message-Id', self.id)) return headers From 3879c8ee064509e6422b64762a818fbfcafec516 Mon Sep 17 00:00:00 2001 From: Alice Bevan-McGregor Date: Wed, 4 Sep 2019 19:29:46 -0400 Subject: [PATCH 5/8] Version bumps. --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 50ea65a..f8cefa9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,9 +9,11 @@ branches: python: - "2.7" - "pypy" - - "3.3" + - "pypy3" - "3.4" - "3.5" + - "3.6" + - "3.7" install: - travis_retry pip install --upgrade setuptools pip codecov 'setuptools_scm>=1.9' From 97cfff7520d22c7379299a11752750b61bce07d7 Mon Sep 17 00:00:00 2001 From: Alice Bevan-McGregor Date: Wed, 4 Sep 2019 19:30:40 -0400 Subject: [PATCH 6/8] Correct Python 3 testing issue. --- test/test_message.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_message.py b/test/test_message.py index 3c97f04..3ce4dc6 100644 --- a/test/test_message.py +++ b/test/test_message.py @@ -18,7 +18,7 @@ from marrow.mailer import Message from marrow.mailer.address import AddressList -from marrow.util.compat import unicode +from marrow.util.compat import basestring, unicode class TestBasicMessage(TestCase): From 426e2b26d012a2ec050842c2ae9c6a689e32b6c6 Mon Sep 17 00:00:00 2001 From: Alice Bevan-McGregor Date: Sun, 15 Sep 2019 20:03:27 -0400 Subject: [PATCH 7/8] Copyright year bumps, mention Python 2 deprecation. --- LICENSE.txt | 2 +- README.textile | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/LICENSE.txt b/LICENSE.txt index b3c4dc3..a2a1027 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright © 2006-2016 Alice Bevan-McGregor and contributors. +Copyright © 2006-2019 Alice Bevan-McGregor and contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/README.textile b/README.textile index 389dba3..757be1f 100644 --- a/README.textile +++ b/README.textile @@ -2,7 +2,7 @@ h1(#title). Marrow Mailer bq(subtitle). A highly efficient and modular mail delivery framework for Python 2.6+ and 3.2+, formerly called TurboMail. -bq(byline). (C) 2006-2016, Alice Bevan-McGregor and contributors. +bq(byline). (C) 2006-2019, Alice Bevan-McGregor and contributors. bq(byline). "https://github.com/marrow/mailer":github-project @@ -43,6 +43,8 @@ Installing @marrow.mailer@ is easy, just execute the following in a terminal: [2 If you add @marrow.mailer@ to the @install_requires@ argument of the call to @setup()@ in your application's @setup.py@ file, @marrow.mailer@ will be automatically installed and made available when your own application is installed. We recommend using "less than" version numbers to ensure there are no unintentional side-effects when updating. Use @"marrow.mailer<4.1"@ to get all bugfixes for the current release, and @"marrow.mailer<5.0"@ to get bugfixes and feature updates, but ensure that large breaking changes are not installed. +*Warning:* The 4.0 series is the last to support Python 2. + h3(#install-dev). %2.1.% Development Version @@ -454,7 +456,7 @@ Marrow Mailer has been released under the MIT Open Source license. h3(#license-mit). %8.1.% The MIT License -Copyright (C) 2006-2016 Alice Bevan-McGregor and contributors. +Copyright (C) 2006-2019 Alice Bevan-McGregor and contributors. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: From 4208b07f5e1858bbbac57533332be53d49f8a1fd Mon Sep 17 00:00:00 2001 From: Alice Bevan-McGregor Date: Sun, 15 Sep 2019 20:03:47 -0400 Subject: [PATCH 8/8] Version bump. --- marrow/mailer/release.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/marrow/mailer/release.py b/marrow/mailer/release.py index 4c7ece0..99f5398 100644 --- a/marrow/mailer/release.py +++ b/marrow/mailer/release.py @@ -5,7 +5,7 @@ from collections import namedtuple -version_info = namedtuple('version_info', ('major', 'minor', 'micro', 'releaselevel', 'serial'))(4, 0, 2, 'final', 0) +version_info = namedtuple('version_info', ('major', 'minor', 'micro', 'releaselevel', 'serial'))(4, 0, 3, 'final', 0) version = ".".join([str(i) for i in version_info[:3]]) + ((version_info.releaselevel[0] + str(version_info.serial)) if version_info.releaselevel != 'final' else '') author = namedtuple('Author', ['name', 'email'])("Alice Bevan-McGregor", 'alice@gothcandy.com')