I am trying to get images shown as part of the mail sent with Python. There is a example on Python docs which is not working.
from datetime import datetime
import sys
import smtplib
from email.message import EmailMessage
from email.headerregistry import Address
from email.utils import make_msgid
from email.mime.image import MIMEImage
attachment = '/user/file/test.png'
import email.policy
msg = EmailMessage()
msg['To'] = Address("Srujan", '[email protected]')
msg['From'] = Address("Srujan", '[email protected]')
msg['Subject'] = "Nice message goes with it "+str(datetime.now())
id = make_msgid()
msg.set_type('text/html')
msg.set_content(" This is the Data Message that we want to send")
html_msg = "<br> <b><u> This is the Text .... </u></b><br> <img src='cid:{image_id}' />".format(image_id=id[1:-1])
msg.add_alternative(html_msg, subtype="html")
image_data = open(attachment, "rb")
image_mime = MIMEImage(image_data.read())
image_data.close()
msg.add_attachment(image_mime, cid=id, filename = "myown.png" ,)
try:
with smtplib.SMTP('example.com') as s:
s.ehlo()
s.starttls()
s.ehlo()
s.send_message(msg)
s.close()
print("Email sent!")
except:
print("Unable to send the email. Error: ", sys.exc_info()[0])
raise
I noticed that the last part is a message/rfc822
, which then contains the image/png
.
To: Srujan <"[email protected]"> From: Srujan <"[email protected]"> Subject: Nice message goes with it 2016-01-21 17:39:23.642762 MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============3463325241650937591==" --===============3463325241650937591== Content-Type: multipart/alternative; boundary="===============0739224896516732414==" --===============0739224896516732414== Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit This is the Data Message that we want to send --===============0739224896516732414== Content-Type: text/html; charset="utf-8" Content-Transfer-Encoding: 7bit MIME-Version: 1.0 <br> <b><u> This is the Text .... </u></b><br> <img src='cid:20160122013923.64205.76661' /> --===============0739224896516732414==-- --===============3463325241650937591== Content-Type: message/rfc822 Content-Transfer-Encoding: 8bit Content-Disposition: attachment; filename="myown.png" Content-ID: <20160122013923.64205.76661> MIME-Version: 1.0 Content-Type: image/png MIME-Version: 1.0 Content-Transfer-Encoding: base64 iVBORw0KGgoAAAANSUhEUgAAAyAAAAJYCAIAAAAVFBUnAAAABmJLR0QA/wD/AP+gvaeTAAAgAElE QVR4nOzdd2BUVfYH8HNfmZJAChAEQ1FAqoKgCAsWLEgTG4gKP11FQNG1AauIgGBXVhRUsCK4i6gI
Now the attached message has two content-type values. Email comes with just text and with no image.
I have done it successfully with MultiPart
class, but looking to achieve that with EmailMessage
.
HTML Images SyntaxThe <img> tag creates a holding space for the referenced image. The <img> tag is empty, it contains attributes only, and does not have a closing tag. The <img> tag has two required attributes: src - Specifies the path to the image.
It is the base class for the email object model. EmailMessage provides the core functionality for setting and querying header fields, for accessing message bodies, and for creating or modifying structured messages. An email message consists of headers and a payload (which is also referred to as the content).
will produce an email with empty body and the image as an attachment. The trick is to define an image with a specific Content-ID and make that the only item in an HTML body: now you have an email with contains that specific image as the only content of the body, embedded in it.
Python provides smtplib module, which defines an SMTP client session object that can be used to send mails to any Internet machine with an SMTP or ESMTP listener daemon. host − This is the host running your SMTP server. You can specifiy IP address of the host or a domain name like tutorialspoint.com.
It is really a pity that Python docs on this subject are incomplete/wrong. I wanted to do the same thing and got the same problem (attachments got two content-types)
Solved the problem by using the attach()
method instead of add_attachment()
on EmailMessage
objects. The only caveat is that you have to transform the EmailMessage
to multipart/mixed
type before doing this. An example:
from smtplib import SMTP
from email.message import EmailMessage
from email.mime.text import MIMEText
from email.headerregistry import Address
from ssl import SSLContext, PROTOCOL_TLSv1_2
# Creating and populating email data:
msg = EmailMessage()
msg['From'] = Address(display_name='Recipient', addr_spec='[email protected]')
msg['To'] = Address(display_name='Sender', addr_spec='[email protected]')
msg['Subject'] = 'An email for you'
msg.set_content('This should be in the email body')
# It is possible to use msg.add_alternative() to add HTML content too
# Attaching content:
att = MIMEText('This should be in an attached file') # Or use MIMEImage, etc
# The following line is to control the filename of the attached file
att.add_header('Content-Disposition', 'attachment', filename='attachment.txt')
msg.make_mixed() # This converts the message to multipart/mixed
msg.attach(att) # Don't forget to convert the message to multipart first!
# Sending the email:
with SMTP(host='smtp.example.org', port=587) as smtp_server:
try:
# You can choose SSL/TLS encryption protocol to use as shown
# or just call starttls() without parameters
smtp_server.starttls(context=SSLContext(PROTOCOL_TLSv1_2))
smtp_server.login(user='[email protected]', password='password')
smtp_server.send_message(msg)
except Exception as e:
print('Error sending email. Details: {} - {}'.format(e.__class__, e))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With