summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
authorMichael Schwarz <michi@cloudscale.ch>2016-08-03 15:53:06 +0200
committerTim Graham <timograham@gmail.com>2016-08-12 16:35:09 -0400
commit72d541b61cd7b0a14f70242e2207fdb3f600c4d5 (patch)
treeaa90cd09c360ed41657ffca31507c8fef579c2ab /django
parent311a8e8d505049ff5644a94e16c00246c8a43a18 (diff)
Fixed #27007 -- Handled non-UTF-8 bytes objects for text/* attachments.
The fallback logic which allows non-UTF-8 encoded files to be passed to attach_file() even when a `text/*` mime type has been specified is moved to attach(). Both functions now fall back to a content type of `application/octet-stream`. A side effect is that a file's content is decoded in memory instead of opening it in text mode and reading it into a string. Some mimetype-related logic in _create_attachment() has become obsolete as the code moved from attach_file() to attach() already handles this.
Diffstat (limited to 'django')
-rw-r--r--django/core/mail/message.py57
1 files changed, 29 insertions, 28 deletions
diff --git a/django/core/mail/message.py b/django/core/mail/message.py
index 29012201ef..44178d2447 100644
--- a/django/core/mail/message.py
+++ b/django/core/mail/message.py
@@ -356,6 +356,11 @@ class EmailMessage(object):
If the first parameter is a MIMEBase subclass it is inserted directly
into the resulting message attachments.
+
+ For a text/* mimetype (guessed or specified), when a bytes object is
+ specified as content, it will be decoded as UTF-8. If that fails,
+ the mimetype will be set to DEFAULT_ATTACHMENT_MIME_TYPE and the
+ content is not decoded.
"""
if isinstance(filename, MIMEBase):
assert content is None
@@ -363,6 +368,22 @@ class EmailMessage(object):
self.attachments.append(filename)
else:
assert content is not None
+
+ if not mimetype:
+ mimetype, _ = mimetypes.guess_type(filename)
+ if not mimetype:
+ mimetype = DEFAULT_ATTACHMENT_MIME_TYPE
+ basetype, subtype = mimetype.split('/', 1)
+
+ if basetype == 'text':
+ if isinstance(content, six.binary_type):
+ try:
+ content = content.decode('utf-8')
+ except UnicodeDecodeError:
+ # If mimetype suggests the file is text but it's actually
+ # binary, read() will raise a UnicodeDecodeError on Python 3.
+ mimetype = DEFAULT_ATTACHMENT_MIME_TYPE
+
self.attachments.append((filename, content, mimetype))
def attach_file(self, path, mimetype=None):
@@ -370,33 +391,17 @@ class EmailMessage(object):
Attaches a file from the filesystem.
The mimetype will be set to the DEFAULT_ATTACHMENT_MIME_TYPE if it is
- not specified and cannot be guessed or (PY3 only) if it suggests
- text/* for a binary file.
+ not specified and cannot be guessed.
+
+ For a text/* mimetype (guessed or specified), the file's content
+ will be decoded as UTF-8. If that fails, the mimetype will be set to
+ DEFAULT_ATTACHMENT_MIME_TYPE and the content is not decoded.
"""
filename = os.path.basename(path)
- if not mimetype:
- mimetype, _ = mimetypes.guess_type(filename)
- if not mimetype:
- mimetype = DEFAULT_ATTACHMENT_MIME_TYPE
- basetype, subtype = mimetype.split('/', 1)
- read_mode = 'r' if basetype == 'text' else 'rb'
- content = None
-
- with open(path, read_mode) as f:
- try:
- content = f.read()
- except UnicodeDecodeError:
- # If mimetype suggests the file is text but it's actually
- # binary, read() will raise a UnicodeDecodeError on Python 3.
- pass
-
- # If the previous read in text mode failed, try binary mode.
- if content is None:
- with open(path, 'rb') as f:
- content = f.read()
- mimetype = DEFAULT_ATTACHMENT_MIME_TYPE
- self.attach(filename, content, mimetype)
+ with open(path, 'rb') as file:
+ content = file.read()
+ self.attach(filename, content, mimetype)
def _create_message(self, msg):
return self._create_attachments(msg)
@@ -450,10 +455,6 @@ class EmailMessage(object):
Converts the filename, content, mimetype triple into a MIME attachment
object.
"""
- if mimetype is None:
- mimetype, _ = mimetypes.guess_type(filename)
- if mimetype is None:
- mimetype = DEFAULT_ATTACHMENT_MIME_TYPE
attachment = self._create_mime_attachment(content, mimetype)
if filename:
try: