HTML email in Python - python

I'm trying to send an HTML email using smtplib. But I need the HTML content to have a table that is populated using values from a dictionary. I did look at the examples on the Python website. But it doesn't explain how to embed Python code within HTML. Any solutions/suggestions?
I also looked at this question. Can I just format it this way?
.format(dict_name)

From your link:
Here’s an example of how to create an HTML message with an alternative
plain text version: 2
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
# me == my email address
# you == recipient's email address
me = "my#email.com"
you = "your#email.com"
# Create message container - the correct MIME type is multipart/alternative.
msg = MIMEMultipart('alternative')
msg['Subject'] = "Link"
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:\nhttp://www.python.org"
html = """\
<html>
<head></head>
<body>
<p>Hi!<br>
How are you?<br>
Here is the link you wanted.
</p>
</body>
</html>
"""
and the sending section of it:
# 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()
Edit 2022: for new comers, please advise with python’s latest stable release docs.

What you need is a template engine. That is, you need a python library that reads a file written in both HTML and code, interprets the code written within the HTML file (e.g. code that retrieves values from a dictionary), and then produces an HTML file for you.
The python wiki seems to have some suggestions

Related

HTML and Plaintext email over Python through Zabbix

I'm working on a script that creates both an HTML and Plaintext email. This didn't seem like a hassle, but I can't hardcode the e-mail into the script I'm using. Allow me to explain why.
I'm using the Zabbix Monitoring system to keep an eye out for my systems. Allow me to use a printer for example. Once one of the toners is close to dying, I want both an HTML and plain text mail to be sent. Zabbix uses several macros however, which can be used to identify what system is being affected by what.
So, the HTML body needs to received before the script is run. Once the HTML body has been received with the correct values, it needs to have a plain copy too. As much as I'd like to have the plain-text contain the correct parameters (copied from the macros) too, I don't consider this a necessity.
This is what my script currently looks like.
#!/usr/bin/env python
list1=[0, 1, 2, 3, 4];
import mimetypes, os, smtplib, sys
from email import encoders
from email.mime.audio import MIMEAudio
from email.mime.base import MIMEBase
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
me = "x"
you = "y"
DESTINATION=sys.argv[1]
SUBJECT=sys.argv[2]
MESSAGE=sys.argv[3]
PASS='password'
# Create message container - the correct MIME type is multipart/alternative.
msg = MIMEMultipart('alternative')
msg['Subject'] = "Link"
msg['From'] = me
msg['To'] = you
text = "A problem has been detected on {HOST.NAME} \n \n Trigger: {TRIGGER.NAME} \n Status: {TRIGGER.STATUS} \n Severity: {TRIGGER.SEVERITY} "
#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('mysmtpserver')
s.ehlo()
s.starttls()
s.ehlo()
s.login(me, PASS)
# 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()
The reason why I can't have them being sent seperately or sending the HTML copy alone is because my e-mails get nuked by SpamAssassin. I'm intending to send certain error messages to my customers. So they are immediately notified when their toner is nearly empty, so they can place a new order. The HTML-email has been set up and has been working without failure.
So to put it onto perspective one more time.
Zabbix recieves an error.
There is a default HTML message written, macros become filled, this then needs to be imported to the script.
The script is then run.
There's an e-mail sent with both HTML content as well as the
plain-text for users that can't read the HTML-emails.
The reason the script is a mess is because I've already tried several options, but I can't seem to figure this one out.

Python: What is the correct MIME type for attaching html file to email

I've got a script that sends emails with html content in them.. works as expected...
I'm having trouble sending an attachment with the email.
The attachment is an html file stored in the active directory of the script... "test.html"
How do I attach the html file to the email? I've tried snippets from various other posts I've found relating to this, but each returned the same output of "no such file or directory".
code as follows:
import smtplib
import os
import email.encoders
import email.mime.text
import email.mime.base
import mimetools
import base64
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
# me == Outgoing email address
# you == Recipient's email address
me = "secret"
you = "secret"
# Create message container - the correct MIME type is multipart/alternative.
msg = MIMEMultipart('alternative')
msg['Subject'] = "TEST"
msg['From'] = me
msg['To'] = you
emailMsg = email.MIMEMultipart.MIMEMultipart('alternative')
# Create the body of the message (a plain-text and an HTML version).
html = """\
<html>
<head></head>
<body>test</p>
</body>
</html>"""
# Record the MIME types of both parts - text/plain and text/html.
part1 = MIMEText(text, 'plain')
part2 = MIMEText(html, 'html')
filename = "C:/CHRIS/ServerStatus/Oceaneering_Server_Status.html"
f = file(filename)
attachment = MIMEText(f.read(), _subtype='html')
attachment.add_header('Content-Disposition', 'attachment', filename=filename)
# 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)
msg.attach(attachment)
# Send the message via local SMTP server.
mail = smtplib.SMTP('smtp.gmail.com', 587)
mail.ehlo()
# mail.login(username, password) to Outgoing email account
mail.login('secret', 'secret')
mail.sendmail(me, you, msg.as_string())
mail.quit()
i've updated my code in hopes to get this question back on topic... i've made a little progress with the help of Dirk and this link:
Attach a txt file in Python smtplib...
I've been able to physically send an attachment now, but the attachment is still coming through as a text type of file of sort and does not open as the original html file does.
So to reword my question... What is the corrective action for changing the MIME type of this code to correctly attach an .html file to an html based email?
The relative path and directory of my py script and the html file needed to be sent is as follows:
C:\CHRIS\ServerStatus\
This is the output i'm receiving with the code I have:
This is the way the html doc looks outside of the email script (The way it's supposed to look):
I would encourage you to use a library rather than deal with the -rather unpythonic- built-in mail modules, such as the highly recommended envelopes:
https://tomekwojcik.github.io/envelopes/index.html
install with:
pip install envelopes
Python code:
import os
from envelopes import Envelope
filename = "C:/CHRIS/ServerStatus/Oceaneering_Server_Status.html"
envelope = Envelope(
from_addr=(me),
to_addr=(you),
subject=u'Test',
text_body=u'Plain text version',
html_body=html
)
envelope.add_attachment(filename)
envelope.send('smtp.gmail.com', login='secret', password='secret', tls=True)

Python, Insert HTML table to email body (not attached) [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I'm looking for a way to insert an html table into emails body (not attached / not hyperlinked).
What i did so far, and it is not good enough is:
1: Attach the table as a file to mail.
2: Convert html to csv and paste to email body.
3: Added a hyperlink to mail with link to table.
Tried with Mailer and email.MIMEMultipart
I guess i am missing something, it seems so trivial.
Thanks
From Python email documentation - 18.1.11. email: Examples:
Here’s an example of how to create an HTML message with an alternative
plain text version:
#! /usr/bin/python
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
# me == my email address
# you == recipient's email address
me = "my#email.com"
you = "your#email.com"
# Create message container - the correct MIME type is multipart/alternative.
msg = MIMEMultipart('alternative')
msg['Subject'] = "Link"
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:\nhttp://www.python.org"
html = """\
<html>
<head></head>
<body>
<p>Hi!<br>
How are you?<br>
Here is the link you wanted.
</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()

Python3 multipartmime email (text, email, and attachment)

I'm creating some emails in Python and I'd like to have HTML, text, and an attachment. My code is 'working', though its outputs are shown by Outlook as EITHER HTML or text, while showing the other 'part' (email or txt) as an attachment. I'd like to have the robust-ness of both email and text versions along with the file attachment.
Is there a fundamental limitation or am I making a mistake?
#!/usr/bin/env python3
import smtplib,email,email.encoders,email.mime.text,email.mime.base
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
# me == my email address
# you == recipient's email address
me = "me#me.com"
you = "you#you.com"
# Create message container - the correct MIME type is multipart/alternative.
msg = MIMEMultipart('mixed')
msg['Subject'] = "msg"
msg['From'] = me
msg['To'] = you
# Create the body of the message (a plain-text and an HTML version).
text = "Hi\nThis is text-only"
html = """\
<html> This is email</html>
"""
part1 = MIMEText(text, 'plain')
part2 = MIMEText(html, 'html')
#attach an excel file:
fp = open('excelfile.xlsx', 'rb')
file1=email.mime.base.MIMEBase('application','vnd.ms-excel')
file1.set_payload(fp.read())
fp.close()
email.encoders.encode_base64(file1)
file1.add_header('Content-Disposition','attachment;filename=anExcelFile.xlsx')
# 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(part2)
msg.attach(part1)
msg.attach(file1)
composed = msg.as_string()
fp = open('msgtest.eml', 'w')
fp.write(composed)
fp.close()
I found this has in fact been answered. Strange how the search feature is less effective than the 'related' boxes.
Sending Multipart html emails which contain embedded images

Sending Multipart html emails which contain embedded images

I've been playing around with the email module in python but I want to be able to know how to embed images which are included in the html.
So for example if the body is something like
<img src="../path/image.png"></img>
I would like to embed image.png into the email, and the src attribute should be replaced with content-id. Does anybody know how to do this?
Here is an example I found.
Recipe 473810: Send an HTML email with embedded image and plain text alternate:
HTML is the method of choice for those
wishing to send emails with rich text,
layout and graphics. Often it is
desirable to embed the graphics within
the message so recipients can display
the message directly, without further
downloads.
Some mail agents don't support HTML or
their users prefer to receive plain
text messages. Senders of HTML
messages should include a plain text
message as an alternate for these
users.
This recipe sends a short HTML message
with a single embedded image and an
alternate plain text message.
# Send an HTML email with an embedded image and a plain text message for
# email clients that don't want to display the HTML.
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
from email.MIMEImage import MIMEImage
# Define these once; use them twice!
strFrom = 'from#example.com'
strTo = 'to#example.com'
# Create the root message and fill in the from, to, and subject headers
msgRoot = MIMEMultipart('related')
msgRoot['Subject'] = 'test message'
msgRoot['From'] = strFrom
msgRoot['To'] = strTo
msgRoot.preamble = 'This is a multi-part message in MIME format.'
# Encapsulate the plain and HTML versions of the message body in an
# 'alternative' part, so message agents can decide which they want to display.
msgAlternative = MIMEMultipart('alternative')
msgRoot.attach(msgAlternative)
msgText = MIMEText('This is the alternative plain text message.')
msgAlternative.attach(msgText)
# We reference the image in the IMG SRC attribute by the ID we give it below
msgText = MIMEText('<b>Some <i>HTML</i> text</b> and an image.<br><img src="cid:image1"><br>Nifty!', 'html')
msgAlternative.attach(msgText)
# This example assumes the image is in the current directory
fp = open('test.jpg', 'rb')
msgImage = MIMEImage(fp.read())
fp.close()
# Define the image's ID as referenced above
msgImage.add_header('Content-ID', '<image1>')
msgRoot.attach(msgImage)
# Send the email (this example assumes SMTP authentication is required)
import smtplib
smtp = smtplib.SMTP()
smtp.connect('smtp.example.com')
smtp.login('exampleuser', 'examplepass')
smtp.sendmail(strFrom, strTo, msgRoot.as_string())
smtp.quit()
For Python versions 3.4 and above.
The accepted answer is excellent, but only suitable for older Python versions (2.x and 3.3). I think it needs an update.
Here's how you can do it in newer Python versions (3.4 and above):
from email.message import EmailMessage
from email.utils import make_msgid
import mimetypes
msg = EmailMessage()
# generic email headers
msg['Subject'] = 'Hello there'
msg['From'] = 'ABCD <abcd#xyz.com>'
msg['To'] = 'PQRS <pqrs#xyz.com>'
# set the plain text body
msg.set_content('This is a plain text body.')
# now create a Content-ID for the image
image_cid = make_msgid(domain='xyz.com')
# if `domain` argument isn't provided, it will
# use your computer's name
# set an alternative html body
msg.add_alternative("""\
<html>
<body>
<p>This is an HTML body.<br>
It also has an image.
</p>
<img src="cid:{image_cid}">
</body>
</html>
""".format(image_cid=image_cid[1:-1]), subtype='html')
# image_cid looks like <long.random.number#xyz.com>
# to use it as the img src, we don't need `<` or `>`
# so we use [1:-1] to strip them off
# now open the image and attach it to the email
with open('path/to/image.jpg', 'rb') as img:
# know the Content-Type of the image
maintype, subtype = mimetypes.guess_type(img.name)[0].split('/')
# attach it
msg.get_payload()[1].add_related(img.read(),
maintype=maintype,
subtype=subtype,
cid=image_cid)
# the message is ready now
# you can write it to a file
# or send it using smtplib
I realized how painful some of the things are with SMTP and email libraries and I thought I have to do something with it. I made a library that makes embedding images to HTML way easier:
from redmail import EmailSender
email = EmailSender(host="<SMTP HOST>", port=0)
email.send(
sender="me#example.com",
receivers=["you#example.com"]
subject="An email with image",
html="""
<h1>Look at this:</h1>
{{ my_image }}
""",
body_images={
"my_image": "path/to/image.png"
}
)
Sorry for promotion but I think it's pretty awesome. You can supply the image as Matplotlib Figure, Pillow Image or just as bytes if your image is in those formats. It uses Jinja for templating.
If you need to control the size of the image, you can also do this:
email.send(
sender="me#example.com",
receivers=["you#example.com"]
subject="An email with image",
html="""
<h1>Look at this:</h1>
<img src="{{ my_image.src }}" width=200 height=300>
""",
body_images={
"my_image": "path/to/image.png"
}
)
You can just pip install it:
pip install redmail
It's (hopefully) all you need for email sending (has a lot more) and it is well tested. I also wrote extensive documentation: https://red-mail.readthedocs.io/en/latest/ and source code is found here.
There's actually a really good post with multiple solutions to this problem here. I was able to send an email with HTML, an Excel attachment, and an embedded images because of it.
Code working
att = MIMEImage(imgData)
att.add_header('Content-ID', f'<image{i}.{imgType}>')
att.add_header('X-Attachment-Id', f'image{i}.{imgType}')
att['Content-Disposition'] = f'inline; filename=image{i}.{imgType}'
msg.attach(att)

Categories