Ticket 18967: Fix non-standard message/rfc822 base64 encoding issue (django master) #1222

wants to merge 24 commits into


None yet
tax and others added some commits May 24, 2013
@tax tax Link to active fork for ODBC backend
It took me quite some time to find if and where the ODBC backend was maintained.
I found (on djangoproject.com):
http://code.google.com/p/django-pyodbc/ (last commit about 3 years ago)
https://github.com/avidal/django-pyodbc avidal fork.
https://github.com/aurorasoftware/django-pyodbc/ aurorasoftware version which has avidal improvements merged.

Avidals version now links to https://github.com/aurorasoftware/django-pyodbc/ which is also the version installed through PIP.
@brosner brosner Updated my bio f3ba649
@ptone ptone Merge pull request #1209 from tax/master
Updated link to active project for ODBC backend
@timgraham timgraham Merge pull request #1210 from alasdairnicol/jquery_cookie_plugin_link
Updated link to jQuery Cookie plugin site
@timgraham timgraham Fixed #20492 - Removed a broken link in GIS docs. fbab320
@claudep claudep Fixed a regression in router initialization
Regression was introduced in 6a6bb16. Thanks Bas Peschier for the
@andrewgodwin andrewgodwin Rotate CSRF token on login 1514f17
@ziima @claudep ziima Fixed #14825 -- LocaleMiddleware keeps language
 * LocaleMiddleware stores language into session if it is not present there.
@claudep claudep Fixed #20099 -- Eased subclassing of BrokenLinkEmailsMiddleware
Thanks Ram Rachum for the report and the initial patch, and Simon
Charette for the review.
@claudep claudep Removed obsolete attribute of DjangoTranslation c0439b6
@frog32 @claudep frog32 Fixed #20455 -- Do not use ngettext for undefined plurals
Using two separate translation strings instead of gettext plural when
there is no reference to the number in the translated string. This
prevents some translations like Russian and Latvian to use the singular
form for 11 or 21.
@claudep claudep Updated translation catalogs
Updated core/admin/admindocs/comments translation catalogs.
@claudep claudep Fixed some minor translation-related issues b7cf44d
@claudep claudep Fixed #11725 -- Made possible to create widget label tag without "for"
Thanks Denis Martinez for the report and initial patch, and
Sergey Kolosov for bringing the patch up to date.
@bmispelon @claudep bmispelon Fixed #20296 -- Allowed SafeData and EscapeData to be lazy 2ee447f
@andrewjesaitis @claudep andrewjesaitis Fixed #19938 -- Consumed iterator only once in paginator's Page
Thanks Joshua Fialkoff for the report.
@shaib shaib Fix get_or_create test failure under Oracle
Test expected that when given invalid utf-8, the backend should raise
a DatabaseError, but the Oracle backend raises a UnicodeDecodeError.
@shaib shaib Fixed get_or_create...test_savepoint_rollback test for Python3
The test was always skipped on Python3 because string literals are unicode
@ptone ptone Fixed #19866 -- Added security logger and return 400 for SuspiciousOp…

SuspiciousOperations have been differentiated into subclasses, and
are now logged to a 'django.security.*' logger. SuspiciousOperations
that reach django.core.handlers.base.BaseHandler will now return a 400
instead of a 500.

Thanks to tiwoc for the report, and Carl Meyer and Donald Stufft
for review.
@ramiro ramiro Replaced `and...or...` constructs with PEP 308 conditional expressions. 0fa8d43
@micolous micolous Fix for issue #18967: message/rfc822 attachments should not be base64…
… encoded
@micolous micolous Issue #18967: Added regression/feature tests for encoding exceptions,…
… made the rules only apply on message/rfc822 mime-types and not all message/* mimetypes.
@micolous micolous Issue #18967: Documentation of new attachment behaviour for attaching…
… emails to emails

for=id_for_label would have worked here.


He, he, try and you'll see :-)

@timgraham timgraham commented on an outdated diff May 29, 2013
@@ -119,6 +121,30 @@ def sanitize_address(addr, encoding):
return formataddr((nm, addr))
+class SafeMIMEMessage(MIMEMessage):
+ def __init__(self, text, subtype):
timgraham May 29, 2013 Owner

this method doesn't appear to be necessary

@timgraham timgraham commented on an outdated diff May 29, 2013
+ def __setitem__(self, name, val):
+ # message/rfc822 attachments must be ASCII
+ name, val = forbid_multi_line_headers(name, val, 'ascii')
+ MIMEMessage.__setitem__(self, name, val)
+ def as_string(self, unixfrom=False):
+ """Return the entire formatted message as a string.
+ Optional `unixfrom' when True, means include the Unix From_ envelope
+ header.
+ This overrides the default as_string() implementation to not mangle
+ lines that begin with 'From '. See bug #13433 for details.
+ """
+ fp = six.StringIO()
+ g = Generator(fp, mangle_from_ = False)
timgraham May 29, 2013 Owner

no spaces around = (mangle_from_ = False)

@timgraham timgraham commented on an outdated diff May 29, 2013
@@ -309,6 +309,19 @@ The class has the following methods:
For example::
message.attach('design.png', img_data, 'image/png')
+ .. versionchanged:: dev
timgraham May 29, 2013 Owner

dev -> 1.6

@timgraham timgraham commented on an outdated diff May 29, 2013
@@ -309,6 +309,19 @@ The class has the following methods:
For example::
message.attach('design.png', img_data, 'image/png')
+ .. versionchanged:: dev
+ If you specify a ``mimetype`` of ``message/rfc822``, it will also accept
+ :py:class:`django.core.mail.EmailMessage` and
timgraham May 29, 2013 Owner

no :py: prefix for Django classes

@ramiro ramiro commented on the diff Aug 17, 2013
basetype, subtype = mimetype.split('/', 1)
if basetype == 'text':
encoding = self.encoding or settings.DEFAULT_CHARSET
attachment = SafeMIMEText(content, subtype, encoding)
+ elif basetype == 'message' and subtype == 'rfc822':
+ # Bug #18967: per RFC2046 s5.2.1, message/rfc822 attachments
+ # must not be base64 encoded.
+ if not isinstance(content, Message):
ramiro Aug 17, 2013 Member

Giving a last review before committing. Thanks Michael for your efforts and your patience.

Don't you think this block would be more readable in this form?:

# We need an email.Message object
if isinstance(content, EmailMessage):
    # convert content into an email.Message
    content = content.message()
elif not isinstance(content, Message):
    # For compatibility with existing code
    content = message_from_string(content)
ramiro commented Aug 21, 2013

Applied (with tweaks) in f9d1d5d. Thanks Michael and Tim.

@ramiro ramiro closed this Aug 21, 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment