I'm working on producing a quick newletter based on templates, local files, and files on the web. I "almost" have it working. I've distilled the problem code to the following block. I'm just learning Python, and am using Python 3.6.
My newsletter consists of some text with a photo pulled off the web, one or more in-line photos, and a couple of attachments.
The code below produces a valid message that is displayed by Gmail with no issues, but when sent to a Yahoo address, the in-line files do not show (The web photo shows and the attachments show, preview, and download fine).
The two "email-sources" look the same but render incorrectly on Yahoo!
import smtplib
from email.message import EmailMessage
from email.message import MIMEPart
from email.mime.multipart import MIMEMultipart
from base64 import encodebytes
import mimetypes
mSubject = 'Another new family reunion'
mFrom = 'me@mgmail.com'
mTo = 'mom@yahoo.com'
mCC = 'sis@roadrunner.com'
sLogin = 'me@gmail.com'
sPass = 'mypass'
mServer = "smtp.gmail.com"
mPort = 465
filename1 = "file1.jpg"
filename2 = "file2.jpg"
filename3 = "file3.jpg"
image_cid1 = filename1 + "@xxxx1"
image_cid2 = filename2 + "@xxxx2"
def inline_part(filename, icid):
""" Creates a MIMEMultipart for embedded images """
part = MIMEMultipart('related')
fp = open(filename, 'rb')
part.set_payload(encodebytes(fp.read()).decode())
fp.close()
part.add_header('Content-ID', '<' + icid + '>')
part.add_header("Content-Transfer-Encoding", "base64")
return part
def attach_part(filename):
""" Creates a MIMEPart for attached images """
part = MIMEPart()
fp = open(filename, 'rb')
part.set_payload(encodebytes(fp.read()).decode())
fp.close()
part.add_header("Content-Type", mimetypes.guess_type(filename2)[0] + '; filename="%s"' % filename)
part.add_header("Content-Transfer-Encoding", "base64")
part.add_header('Content-Disposition', 'attachment; filename="%s"' % filename)
return part
#set up the mime types
mimetypes.init()
# Create the container email message.
msg = EmailMessage()
msg['Subject'] = mSubject
msg['From'] = mFrom
msg['To'] = mTo
msg['Bcc'] = mCC
body ="""<HTML>
<head></head>
<body>
This is a test email to send an attachment.
This is a linked image:
<div align="center"><p><img src="http://www.freedigitalphotos.net/images/previews/success-road-sign-10031660.jpg"><br></p><p> </p></div>
we will try to add two in-line images as well, named file1.jpg and file2.jpg
"""
# add each of the the in-line photo body info
body += ' <p>This is file 1</p>\n<p><img id="'+ filename1 + '" src="cid:' + image_cid1 + '" alt="file01.jpg"></p>\n'
body += ' <p>This is file 2</p>\n<p><img id="'+ filename2 + '" src="cid:' + image_cid2 + '" alt="file02.jpg"></p>\n'
#add the rest of the body
body +=""" <p>and we have attached one file "file3.jpg"
</body>
</HTML>
"""
# add the body to the message
msg.add_alternative(body, subtype='html')
msg.set_boundary("===myBoundry")
# attach the in-line files
msg.attach(inline_part(filename1, image_cid1))
msg.attach(inline_part(filename2, image_cid2))
# attach the attachment file
msg.attach(attach_part(filename3))
# Open a connection to the mail server, log-on, send the message and disconnect
try:
server = smtplib.SMTP_SSL(mServer, mPort)
server.set_debuglevel(0)
server.login(sLogin, sPass)
server.send_message(msg)
server.quit()
print ("Message sent Successfully")
except Exception as e:
print ("Error sending mail:\n\t" + str(e))
Notes
- I set my own "boundary" because Yahoo was splitting the Content-Type/Boundary on two lines, but the results are the same!
- The body is broken up because it is actually "put together" from different pieces, I just combined most of here to make it closer to what I am actually doing.
- The "send_message" sequence is done because I actually open the server and login before creating the message(s) Yes I may send multiple, then disconnect
Obviously I missed something obvious..... but right now I can't see the forest for the trees!