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
Related
I have a list of text files and html files generated by two distinct functions. Each file is labeled signal1.txt, signal2, etc. and signal1.html, signal2.html, etc. I need to send an email with each file pair (signal1.txt and signal1.html, signal2.txt and signal.2.html, and so forth). I've tried several different ways, but I keep getting just one file pair attached (the last file number whatever it is). I have no problem sending one file type, but it gets messy when I try with two different files.
Any help is appreciated. The code is as follows.
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email import encoders
import smtplib, ssl
import os
dirname = r'C:\Path\To\Files'
ext = ('.txt','html')
for files in os.scandir(dirname):
if files.path.endswith(ext):
def sendmail():
html_body = '''
<html>
<body>
<p style="font-size: 12;"> <strong>Alert</strong><br>{html}</p>
</body>
</html>
'''.format(html=html)
subject = f'Text file content'
senders_email = 'mail#mail.com'
receiver_email = 'mail#mail.com'
# Create a multipart message and set headers
message = MIMEMultipart('alternative')
message['From'] = senders_email
message['To'] = receiver_email
message['Subject'] = subject
#Attach email body
message.attach(MIMEText(html_body, 'html'))
# Name of the file to be attached
filename = f'signal.html'
# Open file in binary mode
with open(filename, 'rb') as attachment:
# Add file as application/octet-stream
part = MIMEBase('application', 'octet-stream')
part.set_payload(attachment.read())
# Encodes file in ASCII characters to send via email
encoders.encode_base64(part)
# Add header as key/value pair to attachment part
part.add_header(
'Content-Disposition',
f"attachment; filename= {filename}",
)
# Add attachment to message and convert message to string
message.attach(part)
text = message.as_string()
# Log into server using secure connection
context = ssl.create_default_context()
with smtplib.SMTP("smtp.mail.com", 25) as server:
# server.starttls(context=context)
# server.login(senders_email, 'password')
server.sendmail(senders_email, receiver_email, text)
print("Email sent!")
sendmail()
I've adapted one of these examples for your problem. This puts all the files in one email:
# Import smtplib for the actual sending function.
import smtplib
# Here are the email package modules we'll need.
from email.message import EmailMessage
import os
dirname = 'C:\Path\To\Files'
ext = ('.txt','html')
msg = EmailMessage()
msg['Subject'] = 'Text file content'
msg['From'] = 'mail#mail.com'
msg['To'] = 'mail#mail.com'
# Open the files in binary mode. You can also omit the subtype
# if you want MIMEImage to guess it.
for filename in os.scandir(dirname):
if filename.path.endswith(ext):
with open(filename, 'rb') as fp:
data = fp.read()
msg.add_attachment(data)
# Send the email via our own SMTP server.
with smtplib.SMTP('localhost') as s:
s.send_message(msg)
Found a way that worked using glob.
dirname = r'C:\Path\To\Files'
regex = create_txt_files(event_dict)
html_file = create_html_files(event_dict)
signalfiles = sorted(list(pathlib.Path(dirname).glob('*.txt')))
htmlfiles = sorted(list(pathlib.Path(dirname).glob('*.html')))
for i, path_html_file in enumerate(htmlfiles):
sendmail(html_file[i], regex[i], path_html_file)
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.
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 ?
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 using the following code to send email from unix.
Code
#!/usr/bin/python
import os
def sendMail():
sendmail_location = "/usr/sbin/sendmail" # sendmail location
p = os.popen("%s -t" % sendmail_location, "w")
p.write("From: %s\n" % "myname#company.com")
p.write("To: %s\n" % "yourname#company.com")
p.write("Subject: My Subject \n")
p.write("\n") # blank line separating headers from body
p.write("body of the mail")
status = p.close()
if status != 0:
print "Mail Sent Successfully", status
sendMail()
I am not sure how to add attachment to this email (attachment being on a different directory /my/new/dir/)
Sendmail is an extremely simplistic program. It knows how to send a blob of text over smtp. If you want to have attachments, you're going to have to do the work of converting them into a blob of text and using (in your example) p.write() to add them into the message.
That's hard - but you can use the email module (part of python core) to do a lot of the work for you.
Even better, you can use smtplib (also part of core) to handle sending the mail.
Check out http://docs.python.org/2/library/email-examples.html#email-examples for a worked example showing how to send a mail with attachments using email and smtplib
Use the email.mime package to create your mail instead of trying to generate it manually, it will save you a lot of trouble.
For example, sending a text message with an attachment could be as simple as:
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
msg = MIMEMultipart()
msg['From'] = 'fromaddress'
msg['To'] = 'toaddres'
msg['Subject'] = 'subject'
msg.attach(MIMEText('your text message'))
with open(filename, 'rb') as f:
attachment = MIMEApplication(f.read(), 'subtype')
attachment['Content-Disposition'] = 'attachment; filename="%s";' % filename
msg.attach(attachment)
message = msg.as_string()
Then you can write the message to sendmail, or use smtplib to send it.
'subtype' should either be replaced with the mime subtype of the attached document, or left out to send the attachment with the default type of application/octet-stream. Or if you know your file is text, you can use MIMEText instead of MIMEApplication.
I normally use the following to send a file "file_name.dat" as attachment:
uuencode file_name.dat file_name.dat | mail -s "Subject line" arnab.bhagabati#gmail.com