I am trying to send mail by a python script and facing some issues with adding the signature image of the company. I tried to base64 encode the image and then add it in the code like this:
Cheers!<br/>
<img src="data:image/jpg;base64,{}" alt="image"high="100" width="100" />
XXXX XXX<br/>
Head of XXXXX<br/>
XXXX | XXXX.com<br/>""".format(encoded_string)
but in the mail it is showing the broken image
Assuming you are using the Python EmailMessage Library this is how I was able to add both a signature in HTML accompanied by an image at the bottom. In my case, I was copying the signature I use in Outlook for automated smtp emails.
import codecs
import smtplib
from email.message import EmailMessage
from email.utils import make_msgid
msg = EmailMessage()
msg['Subject'] = 'This is the subject'
msg['From'] = 'email#email.com'
msg['To'] = 'receiver#email.com'
msg['Cc'] = 'cc#email.com'
body = "This is the normal text body of the email"
msg.set_content(body)
# Signature
img_path = r'filepath/sig_img.png' # Path to img you are appending to the end of the email
html_path = r'htmlpath/signature.htm' # Path to HTML file for signature (you can just write the HTML code in as well).
html_file = codecs.open(html_path, 'r', 'utf-8', errors='ignore') # Opens HTML file and converts to UTF-8, ignoring errors
html_code = html_file.read() # Writes contents of HTML signature file to a string
html_file.close()
image_id = make_msgid()
# Combines the text body, HTML signature, and image in Email HTML format
msg.add_alternative(body + '<br><br>' + html_code + '<img src="%s" />' % image_id.strip('<>'), subtype='html')
with open(img_path, 'rb') as img: # Open signature image used in email
msg.get_payload()[1].add_related(img.read(), 'image', 'png', cid=image_id)
with smtplib.SMTP('smtp.emailHost.com', 587) as smtp:
smtp.ehlo()
smtp.starttls()
smtp.login('email', 'pass')
smtp.send_message(msg)
The code used for attaching an image is shown in the asparagus example on the email lib documentation.
Related
I want to send a multi-part email (text and html) using the Python 3 EMailMessage class, which also has an embedded image. I have been able to get it working when using the MIME classes, but not with the EMailMessage class. The HTML mail shows up but there is no embedded image, with it being added as an attachment instead. Example code is shown below (there are also lines commented out from my various attempts):
# Send an HTML email with an embedded image and a plain text message for
# email clients that don't want to display the HTML.
#Import smtplib for the actual sending function
import smtplib, ssl, mimetypes, imghdr
# Import the email modules we'll need
from email.message import EmailMessage
from email.headerregistry import Address
from email.mime.image import MIMEImage
from email.utils import make_msgid
STR_FROM_DISPLAY_NAME = "From Display Name"
TEXTFILE = "example.txt"
HTMLFILE = "example.html"
IMGFILE = "logo.png"
STR_FROM = "from#example.com"
STR_TO = "to#example.com"
STR_SUBJECT = f"The contents of {TEXTFILE}"
msg = EmailMessage()
msg["Subject"] = STR_SUBJECT
# STR_FROM == the sender's email address
# STR_TO == the recipient's email address
msg["From"] = STR_FROM
msg["To"] = STR_TO
msg.preamble = 'You will not see this in a MIME-aware mail reader.\n'
# Open the plain text file whose name is in TEXTFILE for reading.
with open(TEXTFILE) as fp:
# Create a text/plain message
msg.set_content(fp.read())
# Add the html version. This converts the message into a multipart/alternative
# container, with the original text message as the first part and the new html
# message as the second part.
image_cid = make_msgid()[1:-1] # strip <>
with open(HTMLFILE) as fp:
msg.add_alternative(fp.read(), subtype="html")
#.format(cid=cid), subtype="html")
#maintype, subtype = mimetypes.guess_type(IMGFILE)[0].split('/', 1)
# Now add the related image to the html part.
#attachments={"image1": IMGFILE}
#for png_cid in attachments:
from email.mime.image import MIMEImage
with open(IMGFILE, "rb") as fp:
image_type = imghdr.what(fp.name)
print("image_type = ", image_type)
msgImage = MIMEImage(fp.read())
# Define the image's ID as referenced above
msgImage.add_header("Content-ID", "<image_cid>")
msgImage.add_header('X-Attachment-Id', IMGFILE)
msgImage.add_header("Content-Disposition", f"inline; filename={IMGFILE}")
# msg.attach(msgImage)
# Make the EmailMessage's payload `mixed`
#msg.get_payload()[1].make_mixed() # getting the second part because it is the HTML alternative
#msg.get_payload()[1].attach(msgImage)
msg.get_payload()[1].add_related(msgImage, "image", image_type, fp.name, cid=image_cid) #.format(cid=cid))
# logo = MIMEImage(img.read())
# logo.add_header("Content-ID", f"cid")
# logo.add_header('X-Attachment-Id', IMGFILE)
# logo['Content-Disposition'] = f"inline; filename=" IMGFILE
# msg.attach(logo)
# Make the EmailMessage's payload `mixed`
# msg.get_payload()[1].make_mixed() # getting the second part because it is the HTML alternative
# msg.get_payload()[1].attach(logo)
port = 465 # For starttls
smtp_server = "smtp.mail.server.com"
password = "Password"
# Create secure connection with server and send email
context = ssl.create_default_context()
# Send the message via our own SMTP server.
with smtplib.SMTP_SSL(smtp_server, port, context=context) as server:
server.login(STR_FROM, password)
server.send_message(msg)
Below is the line from the HTML file where I specify the image:
<img class="image_fix" src="cid:{image_cid}" alt="Logo" title="Logo" width="637" height="213" />
There are lots of examples where the HTML is specified in the python code, but I haven't been able to find any where the HTML is loaded from a file where an image is embedded.
I also want to attach a word .docx file to the email, and I have sort of managed this with MIME classes, but the attachment did not show the size when viewed in the e-mail client. I used the line:
MIMEBase("application", "octet-stream").
with it encoded as base64. I think that there is a "word"/"docx" MIME type, but again not sure how to do it.
Any ideas ?
How can I send a python e-mail with inline images for the signature? Currently, I use a link to display the images like this:
<img border="0" src="https://website.com/logo.png" role="presentation" alt="logo mail icon" style="max-width: 300px; width: 300px; display: block;">
But in Outlook the images are not loaded and the user needs to click on "display images" which ruins the e-mail, since I use it for business purposes (it is a confirmation link for a registration). Is there a way how to display the images inline and send them with the e-mail instead of a link?
My code so far:
from email.message import EmailMessage
import smtplib, ssl
import email.utils
import html2text
with open(html_template, 'r') as f:
html_string = f.read()
plain_text = html2text.html2text(html_string)
msg = EmailMessage()
msg['Subject'] = subject
msg['From'] = mail_address
msg['To'] = email_receiver
msg['Date'] = email.utils.formatdate()
msg.add_header('Content-Type','text/html')
msg.add_header('Content-Disposition', 'attachment', filename=file_attachment)
msg.set_content(plain_text)
msg.add_alternative(html_string.format(name=surname), subtype='html')
files = [file_attachment]
for file in files:
with open(file, 'rb') as f:
file_data = f.read()
file_name = f.name
msg.add_attachment(file_data, maintype='application', subtype='octet-stream', filename=file_name)
with smtplib.SMTP(smtp, port) as smtp:
smtp.ehlo()
smtp.starttls(context=ssl.create_default_context())
smtp.ehlo()
smtp.login(mail_address, mail_password)
try:
smtp.send_message(msg)
smtp.quit()
except Exception as e:
print('ERROR')
I couldn't find much approaches or solutions. I've read about encoding the images into base64 but I am a bit confused.
Thanks in advance!
To display images inline, you have to provide the image data in the email itself. You can do so by using a base64 encoded string of your image data. Here an example:
<img alt="Website" width="16" height="16" style="border:none;" src="data:image/png;filename=web.png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAABsAAAAbAFcG/0uAAABPElEQVQ4jaVT3U3DMBD+mgUSJqAbNEyQbkDYgL43Ejz7pUjkPZIHoBvUjNAJcDcoG7QTBH3mMzoikEC1dPL5/r+782wcR9jTdv09AFKD72cPYBu821rpV4C26+cAAoCF0Z91l0Z2oHnw7shHYZwjAN6PcnySLIo/S5ds5fMZQJlL0YNuOlaiONGV8sHsdv1MvC8AbhR9AHCNn8+7grD8NwCrQg17Dd7F4F1QRpZ8JbwH8ZRVtKEtfehbqNvB5EvlB+9OABKJP06aSZ+GEEZlOUnRmHctWe7HQuNEfhe/YP3zyQGG4N2SpPdGfBScpZoLYzfkMbKkdrI8ddv1eYSV+LlZLMhnPx0jMW/+M8a0ym3Xs9S8wjRigDsFS5AA7IwurXTwrs49YDksj0RsCUYeo3irIyXYF3+my74zgA9tApBUsNxB3wAAAABJRU5ErkJggg==" />
You can use online converters to get your base64 string or build it directly in your python script:
import base64
encoded_string = base64.b64encode(open("image.png", "rb").read())
Keep in mind, that inline images can also be blocked by the receivers mail client, so always provide proper alt descriptions.
The image has to be base64 encode and while implementing it to the html tag the b' prefix needs to be removed by using .decode()
import base64
encoded_string = base64.b64encode(open("image.png", "rb").read()).decode()
HTML code:
html = '''<img alt="Website" width="16" height="16" style="border:none;" src="data:image/png;filename=web.png;base64," />'''.format(logo=encoded_string)
I am tying to build an email that will embed an image base64 so that way it displays properly when my coworkers open it. I'm not really sure how to get there from a file and what I have now.
This runs great, but I've not been able to successfully embed an image. I need to imbed image1.jpg.
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
# me == my email address
# you == recipient's email address
me = "me#.com"
you = "you#.com"
# Create message container - the correct MIME type is multipart/alternative.
msg = MIMEMultipart('alternative')
msg['Subject'] = "Sent using Python :) "
msg['From'] = me
msg['To'] = you
# Create the body of the message (a plain-text and an HTML version).
text = "This is an HTML body. I would like to embed a base64 image."
html = """\
<html>
<body>
<p>This is an HTML body.<br>
I would like to embed a base64 image.
</p>
</body>
</html>
"""
# Record the MIME types of both parts - text/plain and text/html.
part1 = MIMEText(text, 'plain')
part2 = MIMEText(html, 'html')
# Attach parts into message container.
# According to RFC 2046, the last part of a multipart message, in this case
# the HTML message, is best and preferred.
msg.attach(part1)
msg.attach(part2)
# Send the message via local SMTP server.
s = smtplib.SMTP('localhost')
# sendmail function takes 3 arguments: sender's address, recipient's address
# and message to send - here it is sent as one string.
s.sendmail(me, you, msg.as_string())
s.quit()
I tested it only with base64 image embeded in HTML file but it should be the same.
You have to read image as bytes, encode to base64, convert it to string and then use in
'<img src="data:image/jpeg;base64,' + data_base64 + '">'
Working example to embed base64 image in HTML file:
import base64
data = open('image.jpg', 'rb').read() # read bytes from file
data_base64 = base64.b64encode(data) # encode to base64 (bytes)
data_base64 = data_base64.decode() # convert bytes to string
print(data_base64)
#html = '<html><body><img src="data:image/jpeg;base64,' + data_base64 + '"></body></html>' # embed in html
html = '<img src="data:image/jpeg;base64,' + data_base64 + '">' # embed in html
open('output.html', 'w').write(html)
Example encode and decode base64 image
Looking for a way to send the contents of a HTML file that is generated once a day using this script below. Running into road blocks getting it to work. I can sent HTML and see it, just not sure how to print out the contents of the file and send it.
File Format is export_MM-DD-YY.html
Id rather have it display the contents of the HTML in the email not the HTML file.
#!/usr/bin/env python3
import smtplib
import config
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
filename = 'name_of_file'
# Read a file and encode it into base64 format
fo = open(filename, "rb")
filecontent = fo.read()
encodedcontent = base64.b64encode(filecontent) # base64
filename = os.path.basename(filename)
# me == my email address
# you == recipient's email address
me = "From#example.com"
you = "TO#example.com"
subject = 'Test Subject v5'
# Create message container - the correct MIME type is multipart/alternative.
msg = MIMEMultipart('alternative')
msg['Subject'] = subject
msg['From'] = me
msg['To'] = you
# Create the body of the message (a plain-text and an HTML version).
text = "Hi!\nHow are you?\nHere is the link you wanted:\nhttps://www.python.org"
html = """\
**INSERT HTML FILE CONTENTS HERE...**
"""
# Record the MIME types of both parts - text/plain and text/html.
part1 = MIMEText(text, 'plain')
part2 = MIMEText(html, 'html')
# Attach parts into message container.
# According to RFC 2046, the last part of a multipart message, in this case
# the HTML message, is best and preferred.
msg.attach(part1)
msg.attach(part2)
# Send the message via local SMTP server.
server = smtplib.SMTP('smtp.gmail.com:587')
server.starttls()
server.login(config.EMAIL_ADDRESS, config.PASSWORD)
server.sendmail(me,you,msg.as_string())
server.quit()
So I think I got it working but im sure theres more code here than is needed (If anyone sees anything I can clean up?)
#!/usr/bin/env python3
import smtplib
import os
import config
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
raport_file = open('export.html','rb')
alert_msg = MIMEText(raport_file.read(),"html", "utf-8")
# me == my email address
# you == recipient's email address
me = "From#example.com"
you = "TO#example.com"
subject = 'Test Subject v5'
# Create message container - the correct MIME type is multipart/alternative.
msg = MIMEMultipart('alternative')
msg['Subject'] = subject
msg['From'] = me
msg['To'] = you
# Create the body of the message (a plain-text and an HTML version).
text = "Hi!\nHow are you?\nHere is the link you wanted:\nhttps://www.python.org"
html = """\
"""
# Record the MIME types of both parts - text/plain and text/html.
part1 = MIMEText(text, 'plain')
part2 = MIMEText(html, 'html')
# Attach parts into message container.
# According to RFC 2046, the last part of a multipart message, in this case
# the HTML message, is best and preferred.
msg.attach(part1)
msg.attach(part2)
# Send the message via local SMTP server.
server = smtplib.SMTP('smtp.gmail.com:587')
server.starttls()
server.login(config.EMAIL_ADDRESS, config.PASSWORD)
server.sendmail(me,you,alert_msg.as_string())
server.quit()
You're really close. Three changes:
Don't open the html file in binary mode. Read the file directly into the html string
report_file = open('export.html')
html = report_file.read()
remove the subsequent assignment to html var
html = """\
"""
send the msg object as constructed
server.sendmail(me, you, msg.as_string())
That worked for me. Also keep in mind that by default gmail settings may not allow your script to send mail. If so you'll need to update your settings to allow "insecure" (meaning non-Google) apps to send mail.
I am writing a script that creates multiple plotly interactive charts that are saved in HTML format. I want to write code that sends these HTML files out in an email as an attachment. I can't seem to find any documentation on this, only instructions on how to embed the HTML in an email which is not what I want. I just want to attach the file, just like I was attaching a JPG picture or PDF file.
Code I have so far, which just embeds the HTML:
import lxml.html
import smtplib
import sys
import os
page = 'report.html'
root = lxml.html.parse(page).getroot()
root.make_links_absolute()
content = lxml.html.tostring(root)
message = """From: <me#gmail.com>
To: <you#gmail.com>
MIME-Version: 1.0
Content-type: text/html
Subject: %s
%s""" %(page, content)
s = smtplib.SMTP('localhost')
s.sendmail('me#gmail.com', ['you#gmail.com'], message)
s.quit()
Appreciate the help. I'd hopefully like to find a dynamic way to send files that are in multiple formats, so that I don't have to worry about different functions to send different types of files.
In standard documentation see third example with module email
https://docs.python.org/3.6/library/email.examples.html#email-examples
# Import smtplib for the actual sending function
import smtplib
# And imghdr to find the types of our images
import imghdr
# Here are the email package modules we'll need
from email.message import EmailMessage
# Create the container email message.
msg = EmailMessage()
msg['Subject'] = 'Our family reunion'
# me == the sender's email address
# family = the list of all recipients' email addresses
msg['From'] = me
msg['To'] = ', '.join(family)
msg.preamble = 'Our family reunion'
# Open the files in binary mode. Use imghdr to figure out the
# MIME subtype for each specific image.
for file in pngfiles:
with open(file, 'rb') as fp:
img_data = fp.read()
msg.add_attachment(img_data, maintype='image',
subtype=imghdr.what(None, img_data))
# Send the email via our own SMTP server.
with smtplib.SMTP('localhost') as s:
s.send_message(msg)
EDIT: for other files you can get maintype, subtype
import mimetypes
filename = 'file.html'
ctype, encoding = mimetypes.guess_type(filename)
maintype, subtype = ctype.split("/", 1)
print(maintype, subtype)
# text html