5

Following the examples in the Python email examples it seems it should be pretty straight forward to add an attachment. However, the following does not work:

import smtplib
from email.message import EmailMessage
import json

# Initialize message.
msg = EmailMessage()
msg['Subject'] = 'Testing, testing 1-2-3'
msg['To'] = 'fake@example.com'
msg['From'] = 'extrafake@example.com'
msg.set_content('Trying to attach a .json file')

# Create json attachment.
attachment = json.dumps({'This': 'is json'})

# Attempt to attach. This raises an exception.
msg.add_attachment(attachment, maintype='application', subtype='json', filename='test.json')

Here's the exception:

Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "/usr/local/lib/python3.7/email/message.py", line 1147, in add_attachment
    self._add_multipart('mixed', *args, _disp='attachment', **kw)
  File "/usr/local/lib/python3.7/email/message.py", line 1135, in _add_multipart
    part.set_content(*args, **kw)
  File "/usr/local/lib/python3.7/email/message.py", line 1162, in set_content
    super().set_content(*args, **kw)
  File "/usr/local/lib/python3.7/email/message.py", line 1092, in set_content
    content_manager.set_content(self, *args, **kw)
  File "/usr/local/lib/python3.7/email/contentmanager.py", line 37, in set_content
    handler(msg, obj, *args, **kw)
TypeError: set_text_content() got an unexpected keyword argument 'maintype'

Note that this very closely follows the third example here, yet fails. Any idea how I can attach a json file?

Also note this answer proposes a similar workflow, but calls the same function with the same arguments, and thus doesn't address my issue.

blthayer
  • 513
  • 3
  • 13
  • As an aside, you should probably not touch the MIME preamble. The examples show how to do it if you really need to, but it's vaguely misleading because you should basically never need to do that. (The one case I can imagine is if your recipients can't be expected to be able to understand the default message because it's in English, but then who ever reads the MIME preamble these days anyhow?) – tripleee Jun 22 '19 at 09:24
  • @tripleee - thanks for the aside. I'll update my question to capture the intent, which was adding the actual body/content of the email (I was confused about preamble). – blthayer Jun 24 '19 at 19:28

1 Answers1

6

EmailMessage.set_content delegates to a ContentManager, either one passed as a parameter or the default raw_data_manager.

raw_data_manager.set_content accepts a maintype argument if the content is bytes, but not if the content is str.

So the solution is to pass a bytes instance to EmailMessage.set_content:

# Create json attachment.
attachment = json.dumps({'This': 'is json'})

# Encode to bytes
bs = attachment.encode('utf-8')

# Attach
msg.add_attachment(bs, maintype='application', subtype='json', filename='test.json')
snakecharmerb
  • 28,223
  • 10
  • 51
  • 86