Creating and sending HTML emails with python

Creating and sending HTML email with Python

When you want to send tidy and attractive emails for marketing or other purposes you quickly come across the common solution of using HTML, and CSS code within emails. In this post we will show you a code snippet that allows you to send HTML emails using pyhton libraries.

However, before we start you should know that there are quite a few articles and posts mentioning that creating HTML emails is a (very) bad idea. That post was written in 2002, when web content and email was a lot simpler, so it is prefectly fine to send out HTML emails these days. I would dare say that it is even expected for emails to look nice and therefore make use of HTML and CSS. There are loads of support within email clients has been added and you can see the number of HTML emails growing every day. MailChimp, or any other email marketing service, provides the ability to create HTML based emails, so if they do it, then it’s safe for you to as well. You may be sending out these emails in an automated process from eCommerce shop. If that is the case I would recommend that read about our 5 best practices for eCommerce testing.

Are you interested in Test Automation? Read our guide, ‘Test Automation: nearly everything you need to know’.

However, there are a few caveats that you should be aware of! Lets list some of them first…

CSS support

Obviously, you want to use some CSS styles in your HTML email. There are some differences with the support of CSS in an email, support per CSS property can really differ per e-mail client/browser. Since it is really hard, and not too much fun, to try out all the different email clients/portals you’d be better off to first see what HTML tags and CSS properties are actually supported. The best guide to this CSS support maze in email clients is probably this one.

When you are using CSS in your HTML email, the best thing to do is to just put the CSS in a <style> tag in the <head>. Another possibility is to put a link to the CSS file but since that needs to be retrieved and might be blocked upon first view, so that is not the best solution. At the time of writing, Google Gmail only supports embedded styles (<styles>) in the head. Though not all styling displays properly when sent from non-Google accounts, and on the forums some developers have mentioned issues with CSS styles in the head tag. Thus, if you want your style to be processed and visible in Gmail, it is safest to include it in the HTML tags itself as inline styling. Now, this is not the most ideal situation, but one thing you can do is to just put some minimal style in the HTML tags and put the rest in the CSS style tag. This approach has been used in the table below. This way, even when style tags are not supported you would still get the minimal “display tidiness.”

HTML5 DOCTYPE

The emails you send will be rendered in the HTML5 DOCTYPE in Gmail, regardless of what DOCTYPE you define in your email. It’s important to be aware of this as you might be surprised to find that some of your code no or design looks as you expected it would.

Catch Email Clients Where HTML Email is Unsupported

With an HTML email you need to change the “MIME type” of the email. Nearly all email clients support this nowadays, but it can still happen that you come across a client that doesn’t. In the example you can see that, with a very simple setting, you can prevent the user from not receiving any feedback. Here is a great example of how to include an alternative plain-text version in an HTML email. Some users will prefer plain-text emails for security reason, and as we have noted before, hacking is on the rise.

Always Give a Reference to the Source/Online Example

Perhaps obvious, but it is advised to always have an example or reference to the content in the email online and point to that. For many email marketing service providers like MailChimp, this is typically the “view this email in your browser” link. This way the receiver will not only be able to see the content in any situation, but you also have another option to drive users to your website or service. This is something that is very important now that many users view their emails on their mobile phones.

Reason and Unsubscribe

Another obvious point, you should always give a reference to why someone is receiving the email (e.g. “subscribed to a newsletter”) so the receiver doesn’t feel like he just received spam/unwanted marketing. Also, an option to unsubscribe/stop receiving the emails should be included. This has nothing to do with a requirement to get the python code to work, but everything to do with usability and compliance. In Europe, GDPR requires that users have the ability to unsubscribe and, in the US, CAN-SPAM also requires this ability.

The Example

import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
 
def py_mail(SUBJECT, BODY, TO, FROM):
    """With this function we send out our HTML email"""
 
    # Create message container - the correct MIME type is multipart/alternative here!
    MESSAGE = MIMEMultipart('alternative')
    MESSAGE['subject'] = SUBJECT
    MESSAGE['To'] = TO
    MESSAGE['From'] = FROM
    MESSAGE.preamble = """
Your mail reader does not support the report format.
Please visit us <a href="http://www.mysite.com">online</a>!"""
 
    # Record the MIME type text/html.
    HTML_BODY = MIMEText(BODY, '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.
    MESSAGE.attach(HTML_BODY)
 
    # The actual sending of the e-mail
    server = smtplib.SMTP('smtp.gmail.com:587')
 
    # Print debugging output when testing
    if __name__ == "__main__":
        server.set_debuglevel(1)
 
    # Credentials (if needed) for sending the mail
    password = "mypassword"
 
    server.starttls()
    server.login(FROM,password)
    server.sendmail(FROM, [TO], MESSAGE.as_string())
    server.quit()
 
if __name__ == "__main__":
    """Executes if the script is run as main script (for testing purposes)"""
 
    email_content = """
 
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <title>html title</title>
  <style type="text/css" media="screen">
    table{
        background-color: #AAD373;
        empty-cells:hide;
    }
    td.cell{
        background-color: white;
    }
  </style>
 
 
 
<table style="border: blue 1px solid;">
 
 
 
 
<tbody>
 
 
 
 
<tr>
 
 
 
 
<td class="cell">Cell 1.1</td>
 
 
 
 
 
<td class="cell">Cell 1.2</td>
 
 
 
</tr>
 
 
 
 
 
 
<tr>
 
 
 
<td class="cell">Cell 2.1</td>
 
 
 
 
 
<td class="cell"></td>
 
 
 
 
</tr>
 
 
 
 
</tbody>
 
 
 
 
</table>
 
 
 
 
 
 
"""
 
    TO = 'receiver@email.com'
    FROM ='sender@mysite.com'
 
    py_mail("Test email subject", email_content, TO, FROM)

The Example Aftermath

The example requires you to change the FROM and TO email addresses and the password to send the email. If you do not use Gmail to send the email, you can probably find your SMTP server settings here. The debugging option should give you a clear idea what the problem is, if something goes wrong regarding the sending process. There are also a lot of posts online about troubleshooting with python’s SMTP library.

There is a possibility that when you execute the example and view the email in your Gmail browser client you will see that the ‘in-tag-HTML” styles are processed but not the style defined in the style tag. In other clients however, all the styles in the example are processed.

If you found this article useful and are interested in other testing tools and languages, we’ve got a specific page with posts related to this topic.

If all this technical talk seems a bit too much for you and you just need some way to ensure that your email campaigns are working with your fulfillment and notification systems, then get in touch with us. We are experts in eCommerce testing and particularly integration testing. We can help ensure that your webshop performs correctly during those important periods like winter holidays.

We can provide:

  • Functional testing to make sure your website works properly and doesn’t damage your reputation with potential customers.
  • Penetration testing to ensure no hackers break into your website or steal customer’s credit card information.
  • Performance and load testing to make sure your website continues to work even when your successful marketing campaign attracts more customers than expected.
  • Test Automation help to allow your development team to test easier and quicker.

Author: Mark Barzilay

Graduated with honors from TU Delft in 2007 studying Electrical Engineering and Media & Knowledge Engineering. Founded spriteCloud in 2009 and worked on test automation ever since, helping out small and large companies with their test automation strategy and infrastructure. Mark is also leading the development on Calliope.pro, an online platform for all your automated test results.

We’re spriteCloud, a leader in software and cybersecurity testing.

Aside from interesting articles, we also have a team of software testers that can help your organisation.

Have a look at our testing solutions.