I am getting an “error: ValueError: Cannot convert mixed to alternative.”
I get this error when I insert the open image and msg.add_attachment block (highlighted in btw #### ####). Without it, the code runs fine. I need to send the email as html and with the image attachment.
import os import imghdr from email.message import EmailMessage import smtplib EMAIL_ADDRESS = os.environ.get('EMAIL-USER') EMAIL_PASSWORD = os.environ.get('EMAIL-PASS') Message0 = "HelloWorld1" Message1 = "HelloWorld2" msg = EmailMessage() msg['Subject'] = 'Hello WORLD' msg['From'] = EMAIL_ADDRESS msg['To'] = EMAIL_ADDRESS msg.set_content('This is a plain text email, see HTML format') ######################################################################## with open('screenshot.png', 'rb') as f: file_data = f.read() file_type = imghdr.what(f.name) file_name = f.name msg.add_attachment(file_data, maintype='image', subtype=file_type, filename=file_name) ######################################################################### msg.add_alternative(""" <!DOCTYPE html> <html> <body> <h1 style="color:Blue;">Hello World</h1> {Message0} {Message1} </body> </html> """.format(**locals()), subtype='html') with smtplib.SMTP_SSL('smtp.gmail.com', 465) as smtp: smtp.login(EMAIL_ADDRESS, EMAIL_PASSWORD) smtp.send_message(msg) print("email sent")
For the end result, I need to be able to send an email via Python and attach images.
Advertisement
Answer
An e-mail can consist of a single part, or it can be a multi-part message.
If it is a multi-part message, it will usually be either a multipart/alternative
, or a multipart/mixed
.
multipart/alternative
means there are 2 or more versions of the same content (e.g. plain text and html)multipart/mixed
is used when multiple different contents need to be packed together (e.g. an email and an attachment)
What actually happens when multipart
is used is that email consists of a “multipart” container which contains additional parts, e.g. for text+html it is something like this:
multipart/alternative
parttext/plain
parttext/html
part
In case of an email with attachment, you can have something like this:
multipart/mixed
parttext/plain
partimage/png
part
So, the container is either mixed
or alternative
, but cannot be both. So, how to have both? You can nest them, e.g.:
multipart/mixed
partmultipart/alternative
parttext/plain
parttext/html
part
image/png
part
So, now you have an email which consists of a message and an attachment, and the message has both plain text and html.
Now, in code, this is the basic idea:
msg = EmailMessage() msg['Subject'] = 'Subject' msg['From'] = 'from@email' msg['To'] = 'to@email' msg.set_content('This is a plain text') msg.add_attachment(b'xxxxxx', maintype='image', subtype='png', filename='image.png') # Now there are plain text and attachment. # HTML should be added as alternative to the plain text part: text_part, attachment_part = msg.iter_parts() text_part.add_alternative("<p>html contents</p>", subtype='html')
BTW, you can then see what is in each part this way:
>>> plain_text_part, html_text_part = text_part.iter_parts() >>> print(plain_text_part) Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit This is a plain text
>>> print(html_text_part) Content-Type: text/html; charset="utf-8" Content-Transfer-Encoding: 7bit MIME-Version: 1.0 <p>html contents</p>
>>> print(attachment_part) Content-Type: image/png Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="image.png" MIME-Version: 1.0 eHh4eHh4
>>> print(msg) Subject: Subject From: from@email To: to@email MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============2219697219721248811==" --===============2219697219721248811== Content-Type: multipart/alternative; boundary="===============5680305804901241482==" --===============5680305804901241482== Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit This is a plain text --===============5680305804901241482== Content-Type: text/html; charset="utf-8" Content-Transfer-Encoding: 7bit MIME-Version: 1.0 <p>html contents</p> --===============5680305804901241482==-- --===============2219697219721248811== Content-Type: image/png Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="image.png" MIME-Version: 1.0 eHh4eHh4 --===============2219697219721248811==--