How to send HTML content in email using Python? I can send simple texts.
- 
        2Just a big fat warning. If you are sending non-ASCII email using Python < 3.0, consider using the email in Django. It wraps UTF-8 strings correctly, and also is much simpler to use. You have been warned :-)Anders Rune Jensen– Anders Rune Jensen2009-12-14 14:42:05 +00:00Commented Dec 14, 2009 at 14:42
- 
        3If you want to send a HTML with unicode see here: stackoverflow.com/questions/36397827/…guettli– guettli2016-04-11 10:53:18 +00:00Commented Apr 11, 2016 at 10:53
12 Answers
From Python v2.7.14 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 = "[email protected]"
you = "[email protected]"
# 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 <a href="http://www.python.org">link</a> 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()
13 Comments
quit the s object. What if I want to send multiple messages? Should I quit everytime I send the message or send them all (in a for loop) and then quit once and for all?# According to RFC 2046, the last part of a multipart message, in this case # the HTML message, is best and preferred.  I wish i read this 2hrs agoHere is a Gmail implementation of the accepted answer:
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
# me == my email address
# you == recipient's email address
me = "[email protected]"
you = "[email protected]"
# 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 <a href="http://www.python.org">link</a> 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.
mail = smtplib.SMTP('smtp.gmail.com', 587)
mail.ehlo()
mail.starttls()
mail.login('userName', 'password')
mail.sendmail(me, you, msg.as_string())
mail.quit()
5 Comments
You might try using my mailer module.
from mailer import Mailer
from mailer import Message
message = Message(From="[email protected]",
                  To="[email protected]")
message.Subject = "An HTML Email"
message.Html = """<p>Hi!<br>
   How are you?<br>
   Here is the <a href="http://www.python.org">link</a> you wanted.</p>"""
sender = Mailer('smtp.example.com')
sender.send(message)
5 Comments
use_tls=True,usr='email' and pwd='password' when initializing Mailer and it will work.message.Body = """Some text to show when the client cannot show HTML emails"""Here is a simple way to send an HTML email, just by specifying the Content-Type header as 'text/html':
import email.message
import smtplib
msg = email.message.Message()
msg['Subject'] = 'foo'
msg['From'] = '[email protected]'
msg['To'] = '[email protected]'
msg.add_header('Content-Type','text/html')
msg.set_payload('Body of <b>message</b>')
# Send the message via local SMTP server.
s = smtplib.SMTP('localhost')
s.starttls()
s.login(email_login,
        email_passwd)
s.sendmail(msg['From'], [msg['To']], msg.as_string())
s.quit()
3 Comments
smtplib.SMTP() example, which doesn't use tls. I used this for an internal script at work where we use ssmtp and a local mailhub. Also, this example is missing s.quit().for python3, improve @taltman 's answer:
- use email.message.EmailMessageinstead ofemail.message.Messageto construct email.
- use email.set_contentfunc, assignsubtype='html'argument. instead of low level funcset_payloadand add header manually.
- use SMTP.send_messagefunc instead ofSMTP.sendmailfunc to send email.
- use withblock to auto close connection.
from email.message import EmailMessage
from smtplib import SMTP
# construct email
email = EmailMessage()
email['Subject'] = 'foo'
email['From'] = '[email protected]'
email['To'] = '[email protected]'
email.set_content('<font color="red">red color text</font>', subtype='html')
# Send the message via local SMTP server.
with SMTP('localhost') as s:
    s.login('foo_user', 'bar_password')
    s.send_message(email)
4 Comments
email.add_alternative() (in the same way as you have with email.set_content() to add HTML, and then add an attachment using email.add_attachment() (This took me bloomin ages to figure out)EmailMessage API was only officially available starting in Python 3.6, though it was shipped as an alternative already in 3.3. New code should absolutely use this instead of the old email.message.Message legacy API which most of the answers here unfortunately still suggest. Anything with MIMEText or MIMEMultipart is the old API and should be avoided unless you have legacy reasons.email.set context?Here's sample code. This is inspired from code found on the Python Cookbook site (can't find the exact link)
def createhtmlmail (html, text, subject, fromEmail):
    """Create a mime-message that will render HTML in popular
    MUAs, text in better ones"""
    import MimeWriter
    import mimetools
    import cStringIO
    out = cStringIO.StringIO() # output buffer for our message 
    htmlin = cStringIO.StringIO(html)
    txtin = cStringIO.StringIO(text)
    writer = MimeWriter.MimeWriter(out)
    #
    # set up some basic headers... we put subject here
    # because smtplib.sendmail expects it to be in the
    # message body
    #
    writer.addheader("From", fromEmail)
    writer.addheader("Subject", subject)
    writer.addheader("MIME-Version", "1.0")
    #
    # start the multipart section of the message
    # multipart/alternative seems to work better
    # on some MUAs than multipart/mixed
    #
    writer.startmultipartbody("alternative")
    writer.flushheaders()
    #
    # the plain text section
    #
    subpart = writer.nextpart()
    subpart.addheader("Content-Transfer-Encoding", "quoted-printable")
    pout = subpart.startbody("text/plain", [("charset", 'us-ascii')])
    mimetools.encode(txtin, pout, 'quoted-printable')
    txtin.close()
    #
    # start the html subpart of the message
    #
    subpart = writer.nextpart()
    subpart.addheader("Content-Transfer-Encoding", "quoted-printable")
    #
    # returns us a file-ish object we can write to
    #
    pout = subpart.startbody("text/html", [("charset", 'us-ascii')])
    mimetools.encode(htmlin, pout, 'quoted-printable')
    htmlin.close()
    #
    # Now that we're done, close our writer and
    # return the message body
    #
    writer.lastpart()
    msg = out.getvalue()
    out.close()
    print msg
    return msg
if __name__=="__main__":
    import smtplib
    html = 'html version'
    text = 'TEST VERSION'
    subject = "BACKUP REPORT"
    message = createhtmlmail(html, text, subject, 'From Host <[email protected]>')
    server = smtplib.SMTP("smtp_server_address","smtp_port")
    server.login('username', 'password')
    server.sendmail('[email protected]', '[email protected]', message)
    server.quit()
2 Comments
email.message.Message API. The MimeWriter library was deprecated in Python 2.3 in 2003.Actually, yagmail took a bit different approach.
It will by default send HTML, with automatic fallback for incapable email-readers. It is not the 17th century anymore.
Of course, it can be overridden, but here goes:
import yagmail
yag = yagmail.SMTP("[email protected]", "mypassword")
html_msg = """<p>Hi!<br>
              How are you?<br>
              Here is the <a href="http://www.python.org">link</a> you wanted.</p>"""
yag.send("[email protected]", "the subject", html_msg)
For installation instructions and many more great features, have a look at the github.
1 Comment
Here's a working example to send plain text and HTML emails from Python using smtplib along with the CC and BCC options.
https://varunver.wordpress.com/2017/01/26/python-smtplib-send-plaintext-and-html-emails/
#!/usr/bin/env python
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
def send_mail(params, type_):
      email_subject = params['email_subject']
      email_from = "[email protected]"
      email_to = params['email_to']
      email_cc = params.get('email_cc')
      email_bcc = params.get('email_bcc')
      email_body = params['email_body']
      msg = MIMEMultipart('alternative')
      msg['To'] = email_to
      msg['CC'] = email_cc
      msg['Subject'] = email_subject
      mt_html = MIMEText(email_body, type_)
      msg.attach(mt_html)
      server = smtplib.SMTP('YOUR_MAIL_SERVER.DOMAIN.COM')
      server.set_debuglevel(1)
      toaddrs = [email_to] + [email_cc] + [email_bcc]
      server.sendmail(email_from, toaddrs, msg.as_string())
      server.quit()
# Calling the mailer functions
params = {
    'email_to': '[email protected]',
    'email_cc': '[email protected]',
    'email_bcc': '[email protected]',
    'email_subject': 'Test message from python library',
    'email_body': '<h1>Hello World</h1>'
}
for t in ['plain', 'html']:
    send_mail(params, t)
1 Comment
In case you want something simpler:
from redmail import EmailSender
email = EmailSender(host="smtp.myhost.com", port=1)
email.send(
    subject="Example email",
    sender="[email protected]",
    receivers=["[email protected]"],
    html="<h1>Hi, this is HTML body</h1>"
)
Pip install Red Mail from PyPI:
pip install redmail
Red Mail has most likely all you need from sending emails and it has a lot of features including:
- Attachments
- Templating (with Jinja)
- Embedded images
- Prettified tables
- Send as cc or bcc
- Gmail preconfigured
Documentation: https://red-mail.readthedocs.io/en/latest/index.html
Source code: https://github.com/Miksus/red-mail
Comments
I may be late in providing an answer here, but the Question asked a way to send HTML emails. Using a dedicated module like "email" is okay, but we can achieve the same results without using any new module. It all boils down to the Gmail Protocol.
Below is my simple sample code for sending HTML mail only by using "smtplib" and nothing else. This code is suitable for sending simple and small HTML Contents only.
import smtplib
FROM = "[email protected]"
TO = "[email protected]"
SUBJECT= "Subject"
PWD = "thesecretkey"
TEXT="""
<h1>Hello</h1>
""" #Your Message (Even Supports HTML Directly)
message = f"Subject: {SUBJECT}\nFrom: {FROM}\nTo: {TO}\nContent-Type: text/html\n\n{TEXT}" #This is where the stuff happens
try:
    server=smtplib.SMTP("smtp.gmail.com",587)
    server.ehlo()
    server.starttls()
    server.login(FROM,PWD)
    server.sendmail(FROM,TO,message)
    server.close()
    print("Successfully sent the mail.")
except Exception as e:
    print("Failed to send the mail..", e)
1 Comment
email library is not a "new module", it is part of the standard library just like smtplib. You should absolutely not create messages by combining strings like this; it will seem to work for very simple messages, but fail in catastrophic ways as soon as you move outside the comfortable realm of a single text/plain payload with only 7-bit US-ASCII contents (and even then there are corner cases which are likely to trip you up, especially if you don't know exactly what you are doing).Here is my answer for AWS using boto3
    subject = "Hello"
    html = "<b>Hello Consumer</b>"
    client = boto3.client('ses', region_name='us-east-1', aws_access_key_id="your_key",
                      aws_secret_access_key="your_secret")
client.send_email(
    Source='ACME <[email protected]>',
    Destination={'ToAddresses': [email]},
    Message={
        'Subject': {'Data': subject},
        'Body': {
            'Html': {'Data': html}
        }
    }
Comments
Simplest solution for sending email from Organizational account in Office 365:
from O365 import Message
html_template =     """ 
            <html>
            <head>
                <title></title>
            </head>
            <body>
                    {}
            </body>
            </html>
        """
final_html_data = html_template.format(df.to_html(index=False))
o365_auth = ('sender_username@company_email.com','Password')
m = Message(auth=o365_auth)
m.setRecipients('receiver_username@company_email.com')
m.setSubject('Weekly report')
m.setBodyHTML(final_html_data)
m.sendMessage()
here df is a dataframe converted to html Table, which is being injected to html_template







