As far as I can see this happens when using python 3 (like we do) and
utf-8 as encoding.
* If you attach a text/csv file for example, django tries to instantiate a
SafeMIMEText object with the following parameters: (text: bytes(...),
subtype: 'csv', charset: 'utf-8') (django/core/mail/message.py:338)
* SafeMIMEText calls init of MIMEText and sets the charset to None
explicitly when charset was 'utf-8' before but does not convert text from
bytes to str which is expected by MIMEText
(django/core/mail/message.py:175)
* MIMEText then tries to encode the provided _text parameter as 'us-ascii'
and fails since a bytes object has no encode-method in python3
(email/mime/text.py:33)
'''Example'''
{{{
from django.core.mail import EmailMessage
email = EmailMessage('subject', 'body', 'fr...@example.com',
['t...@example.com'])
email.attach_file('/path/to/csv.file')
email.send()
}}}
Solutions I could think of:
* Convert text parameter of SafeMIMEText from bytes to str before calling
init of MIMEText. This would imply that one knows the encoding of the text
file or the file encoding is detected automatically.
* Convert the file content and call attach of EmailMessage.
'''Stack trace''':
{{{
Traceback (most recent call last):
File "./manage.py", line 10, in <module>
execute_from_command_line(sys.argv)
File "/usr/local/lib/python3.4/dist-
packages/django/core/management/__init__.py", line 385, in
execute_from_command_line
utility.execute()
File "/usr/local/lib/python3.4/dist-
packages/django/core/management/__init__.py", line 377, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/usr/local/lib/python3.4/dist-
packages/django/core/management/base.py", line 288, in run_from_argv
self.execute(*args, **options.__dict__)
File "/usr/local/lib/python3.4/dist-
packages/django/core/management/base.py", line 338, in execute
output = self.handle(*args, **options)
File
"/mnt/storage/django/code/trouble_ticket/management/commands/send2ntt.py",
line 41, in handle
raise(e)
File
"/mnt/storage/django/code/trouble_ticket/management/commands/send2ntt.py",
line 39, in handle
email.send()
File "/usr/local/lib/python3.4/dist-
packages/django/core/mail/message.py", line 286, in send
return self.get_connection(fail_silently).send_messages([self])
File "/usr/local/lib/python3.4/dist-
packages/django/core/mail/backends/smtp.py", line 99, in send_messages
sent = self._send(message)
File "/usr/local/lib/python3.4/dist-
packages/django/core/mail/backends/smtp.py", line 113, in _send
message = email_message.message()
File "/usr/local/lib/python3.4/dist-
packages/django/core/mail/message.py", line 253, in message
msg = self._create_message(msg)
File "/usr/local/lib/python3.4/dist-
packages/django/core/mail/message.py", line 312, in _create_message
return self._create_attachments(msg)
File "/usr/local/lib/python3.4/dist-
packages/django/core/mail/message.py", line 325, in _create_attachments
msg.attach(self._create_attachment(*attachment))
File "/usr/local/lib/python3.4/dist-
packages/django/core/mail/message.py", line 367, in _create_attachment
attachment = self._create_mime_attachment(content, mimetype)
File "/usr/local/lib/python3.4/dist-
packages/django/core/mail/message.py", line 338, in
_create_mime_attachment
attachment = SafeMIMEText(content, subtype, encoding)
File "/usr/local/lib/python3.4/dist-
packages/django/core/mail/message.py", line 175, in __init__
MIMEText.__init__(self, text, subtype, None)
File "/usr/lib/python3.4/email/mime/text.py", line 33, in __init__
_text.encode('us-ascii')
AttributeError: 'bytes' object has no attribute 'encode'
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/24623>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
* needs_better_patch: => 0
* needs_docs: => 0
* needs_tests: => 0
* stage: Unreviewed => Accepted
Comment:
Reproduced with the attached test (`EmailMessage.attach_file()` is
untested at the moment).
--
Ticket URL: <https://code.djangoproject.com/ticket/24623#comment:1>
* Attachment "24623-test.diff" added.
* owner: nobody => ChillarAnand
* status: new => assigned
--
Ticket URL: <https://code.djangoproject.com/ticket/24623#comment:2>
* owner: ChillarAnand =>
* status: assigned => new
--
Ticket URL: <https://code.djangoproject.com/ticket/24623#comment:3>
* Attachment "24623_workaround_1.diff" added.
* status: new => assigned
* owner: => kswiat
Comment:
https://docs.python.org/3/library/functions.html#open
Files opened in binary mode (including 'b' in the mode argument) return
contents as bytes objects without any decoding.
`EmailMessage.attach_file()` opens a attachment file with 'rb' mode. which
results in a `bytes` object content. In case of a `text` base mimetype,
content is beeing sent to python's `MimeText`, and then `encode()` fails
on `bytes` object.
I attached a simple workaround patch.
--
Ticket URL: <https://code.djangoproject.com/ticket/24623#comment:4>
Comment (by claudep):
Would you mind creating a pull request with your patch, including the test
from Tim?
--
Ticket URL: <https://code.djangoproject.com/ticket/24623#comment:5>
Comment (by kswiat):
Of course, I will create PR within a few hours.
--
Ticket URL: <https://code.djangoproject.com/ticket/24623#comment:6>
* has_patch: 0 => 1
--
Ticket URL: <https://code.djangoproject.com/ticket/24623#comment:7>
* stage: Accepted => Ready for checkin
--
Ticket URL: <https://code.djangoproject.com/ticket/24623#comment:8>
* needs_better_patch: 0 => 1
* stage: Ready for checkin => Accepted
--
Ticket URL: <https://code.djangoproject.com/ticket/24623#comment:9>
Comment (by kswiat):
PR updated.
--
Ticket URL: <https://code.djangoproject.com/ticket/24623#comment:10>
* needs_better_patch: 1 => 0
--
Ticket URL: <https://code.djangoproject.com/ticket/24623#comment:11>
Comment (by phalt):
@kswiat - you've got some tests in there already, are there any more
edgecases that you can think of? It doesn't hurt to have more.
--
Ticket URL: <https://code.djangoproject.com/ticket/24623#comment:12>
* status: assigned => closed
* resolution: => fixed
Comment:
In [changeset:"c6da621def9bc04a5feacd5652c7f9d84f48ad2c" c6da621]:
{{{
#!CommitTicketReference repository=""
revision="c6da621def9bc04a5feacd5652c7f9d84f48ad2c"
Fixed #24623 -- Fixed EmailMessage.attach_file() with text files on Python
3.
Thanks tkrapp for the report and Tim Graham for the review.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/24623#comment:13>