Building Custom Email Templates with HTML and CSS in Python

An HTML email utilizes HTML code for presentation. Its design is heavy and looks like a modern web page, rich with visual elements like images, videos, etc., to emphasize different parts of an email's content.

Building email templates tailored to your brand is useful for various email marketing purposes such as welcoming new customers, order confirmation, and so on. Email template customization allows you to save time by not having to create emails from scratch each time. You can also include an email link in HTML to automatically compose emails in your email client.

In this step-by-step guide, you'll learn how to build an HTML email template, add a CSS email design to it, and send it to your target audience.

Setting Up Your Template Directory and Jinja2

Follow the steps below to set up your HTML email template directory and Jinja2 for Python email automation:

  • Create a Template Directory: To hold your HTML email templates, you will need to set up a template directory inside your project module. Let's name this directory - html_emailtemp.

  • Install Jinja2: Jinja is a popular templating engine for Python that developers use to create configuration files, HTML documents, etc. Jinja2 is its latest version. It lets you create dynamic content via loops, blocks, variables, etc. It's used in various Python projects, like building websites and microservices, automating emails with Python, and more.

    Use this command to install Jinja2 on your computer:

    pip install jinja2
    

Creating an HTML Email Template

To create an HTML email template, let's understand how to code your email step by step. If you want to modify your templates, you can do it easily by following the steps below:

Step 1: Structure HTML

A basic email will have a proper structure - a header, a body, and a footer.

  • Header: Used for branding purposes (in emails, at least)
  • Body: It will house the main text or content of the email
  • Footer: It's at the end of the email if you want to add more links, information, or call-to-actions (CTA)

Begin by creating your HTML structure, keeping it simple since email clients are less compatible than web browsers. For example, using tables is preferable for custom email layouts.

Here's how you can create a basic HTML mail with a defined structure:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>HTML Email Template</title>
    <style type="text/css">
        /* Add your CSS here */
    </style>
</head>
<body>
    <table width="100%" cellpadding="0" cellspacing="0">
        <tr>
            <td align="center">
                <table width="600" cellpadding="0" cellspacing="0">
                    <!-- Header -->
                    <tr>
                        <td style="background-color: #1c3f60; color: #ffffff; text-align: center; padding: 20px;">
                            <h1>Your order is confirmed</h1>
                        </td>
                    </tr>
                    <!-- Body -->
                    <tr>
                        <td style="padding: 20px; font-size: 16px; line-height: 1.6; color:#ffffff;">
                            <p>The estimated delivery date is 22nd August 2024.</p>
                        </td>
                    </tr>
                    <!-- Footer -->
                    <tr>
                        <td style="background-color: #ff6100; color: #000000; text-align: center; padding: 20px;">
                            <p>For additional help, contact us at [email protected]</p>
                        </td>
                    </tr>
                </table>
            </td>
        </tr>
    </table>
</body>
</html>

Explanation:

  • <!DOCTYPE html>: This declares HTML as your document type.
  • <html>: This is an HTML page's root element.
  • <head>: This stores the document's metadata, like CSS styles.
  • <style>: CSS styles are defined here.
  • <body>: This stores your email's main content.
  • <table>: This tag defines the email layout, giving it a tabular structure with cells and rows, which makes rendering easier for email clients.
  • <tr>: This tag defines the table's row, allowing vertical content stacking.
  • <td>: This tag is used to define a cell inside a row. It contains content like images, text, buttons, etc.

Step 2: Structure Your Email

Now, let's create the structure of your HTML email. To ensure it's compatible with different email clients, use tables to generate a custom email layout, instead of CSS.

<table width="100%" cellpadding="0" cellspacing="0">
    <tr>
        <td align="center">
            <table width="600" cellpadding="0" cellspacing="0" style="border: 1px solid #1c3f60; padding: 20px;">
                <tr>
                    <td align="center">
                        <h1 style="color: #7ed957;">Hi, Jon!</h1>
                        <p style="font-size: 16px; color: #ffde59;">Thank you for being our valuable customer!</p>
                    </td>
                </tr>
            </table>
        </td>
    </tr>
</table>

Styling the Email with CSS

Once you've defined your email structure, let's start designing emails with HTML and CSS:

Inline CSS

Use inline CSS to ensure different email clients render CSS accurately and preserve the intended aesthetics of your email style.

<p style="font-size: 16px; color: blue;">Styled paragraph.</p>

Adjusting Style

Users might use different devices and screen sizes to view your email. Therefore, it's necessary to adapt the style to suit various screen sizes. In this case, we'll use media queries to achieve this goal and facilitate responsive email design.

<style type="text/css">
    @media screen and (max-width: 600px) {
        .container {
            width: 100% !important;
            padding: 10px !important;
        }
    }
</style>

<table class="container" width="600">
    <!-- Content -->
</table>

Explanation:

  • @media screen and (max-width: 600px) {....}: This is a media query that targets device screens of up to 600 pixels, ensuring the style applies only to these devices, such as tablets and smartphones.
  • width: 100% !important;: This style changes the width of the table - .container. The code instructs that the table width be set to full screen, not 600px.
  • !important: This rule overrides other styles that may conflict with it.
  • padding: 10px !important;: Inside the .container table, a padding of 10px is added to the table.

Here, we are adding a call to action (CTA) link at the button - "Get a 30-day free trial" that points to this page - https://www.mydomain.com.

<table cellpadding="0" cellspacing="0" style="margin: auto;">
    <tr>
        <td align="center" style="background-color: #8c52ff; padding: 10px 20px; border-radius: 5px;">
            <a href="https://www.mydomain.com" target="_blank" style="color: #ffffff; text-decoration: none; font-weight: bold;">Get a 30-day free trial</a>
        </td>
    </tr>
</table>

Let's Now Look at the Complete HTML Email Template:

<!DOCTYPE html>

<html lang="en">

<head>

  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">

  <title>HTML Email Template</title>

  <style type="text/css">
    /* Adding the CSS */
    
    body {
      margin: 0;
      padding: 0;
      background-color: #f4f4f4;
      font-family: Arial, sans-serif;
    }
    
    table {
      border-collapse: collapse;
    }
    
    .mailcontainer {
      width: 100%;
      max-width: 600px;
      margin: auto;
      background-color: #ffffff;
    }
    
    .header {
      background-color: #1c3f60;
      color: #ffffff;
      text-align: center;
      padding: 20px;
    }
    
    .body {
      padding: 20px;
      font-size: 16px;
      line-height: 1.6;
      background-color: #1c3f60;
      color: #7ed957;
    }
    
    .footer {
      background-color: #ff6100;
      color: #000000;
      text-align: center;
      padding: 20px;
    }
    
    .cta {
      background-color: #8c52ff;
      padding: 10px 20px;
      border-radius: 5px;
      color: #ffffff;
      text-decoration: none;
      font-weight: bold;
    }
    
    @media screen and (max-width: 600px) {
      .container {
        width: 100% !important;
        padding: 10px !important;
      }
    }
  </style>
</head>

<body>
  <table width="100%" cellpadding="0" cellspacing="0">
    <tr>
      <td align="center">
        <table class="container" width="600" cellpadding="0" cellspacing="0">

          <!-- Header -->
          <tr>
            <td class="header">
              <h1>Your order is confirmed</h1>
            </td>
          </tr>

          <!-- Body -->
          <tr>
            <td class="body">
              <p>The estimated delivery date is 22nd August 2024.</p>
              <p style="font-size: 16px; color: blue;">Styled paragraph.</p>
              <table width="100%" cellpadding="0" cellspacing="0" style="border: 1px solid #1c3f60; padding: 20px;">
                <tr>
                  <td align="center">
                    <h1 style="color: #7ed957;">Hi, Jon!</h1>  
                    <p style="font-size: 16px; color: #ffde59;">Thank you for being our valuable customer!</p>
                  </td>
                </tr>
              </table>
              <table cellpadding="0" cellspacing="0" style="margin: auto;">
                <tr>
                  <td align="center" style="background-color: #8c52ff; padding: 10px 20px; border-radius: 5px;">
                    <a href="https://www.mydomain.com" target="_blank" rel="noopener noreferrer" style="color: #ffffff; text-decoration: none; font-weight: bold;">Get a 30-day free trial</a>
                  </td>
                </tr>
              </table>
            </td>
          </tr>

          <!-- Footer -->
          <tr>
            <td style="background-color: #ff6100; color: #000000; text-align: center; padding: 20px;">
              <p>For additional help, contact us at [email protected]</p>
            </td>
          </tr>

        </table>
      </td>
    </tr>
  </table>
</body>

</html>

Explanation:

Free eBook: Git Essentials

Check out our hands-on, practical guide to learning Git, with best-practices, industry-accepted standards, and included cheat sheet. Stop Googling Git commands and actually learn it!

  • .mailcontainer: This is a class that you can use to style your email content's main section. It's given a set width, margin, border, and color.
  • .header, .footer, .body: These are classes used to style your email's header, footer, and body, respectively.
  • .cta: This class allows you to style your buttons, such as CTA buttons, with a specified color, border design, padding, etc.

Bringing Everything Together With Jinja2

Having created our HTML template, it's now time to bring everything together using the Jinja2 templating engine.

Import Project Modules

You've already set up your template directory - html_emailtemp. Now you can find and render templates using code. But before you do that, import the relevant project modules using the code below:

from jinja2 import Environment, PackageLoader, select_autoescape

env = Environment(loader=PackageLoader('email_project', 'html_emailtemp'), autoescape=select_autoescape(['html', 'xml']))

Explanation:

  • Environment: Jinja2 utilizes a central object, the template Environment. Its instances store global objects and configurations, and load your email templates from a file.

  • PackageLoader: This configures Jinja2 to load email templates.

  • autoescape: To mitigate security threats such as cross-site scripting (XSS) attacks and protect your code, you can escape values (that are passed to the email template) while rendering HTML using the command autoescape. Or, you can validate user inputs to reject malicious code.

    For security, autoescape is set to True to enable escaping values. If you turn it to False, Jinja2 won't be able to escape values, and XSS attacks may occur. To enable autoescape, set autoescape to True:

    env = Environment(loader=PackageLoader("myapp"), autoescape=True)

Load Your Template

Once done, a template environment will be created with a template loader to find email templates created inside your project module's template folder.

Next, load your HTML email template using the method - get_template(). This function will return your loaded template. It also offers several benefits such as enabling email template inheritance, so you can reuse the template in multiple scenarios.

template1 = env.get_template("myemailtemplate.html")

Render the Template

To render your email template, use the method - render()

html1 = template1.render()

As these HTML email templates are dynamic, you can pass keyworded arguments (kwargs) with Jinja2 to the render function. The kwargs will then be passed to your email template. Here's how you can render your templates using the destined user's name - "Jon Doe" - in your email.

html1 = template1.render(name="Jon Doe")

Let's look at the complete code for this section:

from jinja2 import Environment, PackageLoader, select_autoescape

env = Environment(loader=PackageLoader("email_project", "html_emailtemp"),
                  autoescape=select_autoescape(["html", "xml"]))

template1 = env.get_template("myemailtemplate.html")
html1 = template1.render()

Sending the Email

To send an email, you can use the application-level, straightforward protocol - Simple Mail Transfer Protocol (SMTP). This protocol streamlines the email sending process and determines how to format, send, and encrypt your emails between the source and destination mail servers.

In this instance, we'll send emails in Python via SMTP since Python offers a built-in module for email sending. To send emails, Python provides a library, 'smtplib', to facilitate effortless interaction with the SMTP protocol.

To get started:

Install 'smtplib': Ensure you have installed Python on your system. Now, import 'smtplib' to set up connectivity with the mail server.

import smtplib

Define your HTML parameter: Define your HTML parameter for the mail object where you'll keep your HTML template. It will instruct email clients to render the template.

Here's the full code for this section:

import smtplib

from email.mime.text import MIMEText    # MIMEText is a class from the email package 

from jinja2 import Template   # Let's use Template class for our HTML template 

sender = "<a href='mailto:[email protected]' target='_blank' rel='noopener noreferrer'>[email protected]</a>"

recipient = "<a href='mailto:[email protected]' target='_blank' rel='noopener noreferrer'>[email protected]</a>"

subject = "Your order is confirmed!"

with open('myemailtemplate.html', 'r') as f:
    template1 = Template(f.read())

# Enter the HTML template

html_emailtemp = """
<!DOCTYPE html>
<html lang='en'>
<head>
    <meta charset='UTF-8'>
    <meta name='viewport' content='width=device-width, initial-scale=1'>

    <title>HTML Email Template</title>

    <style type='text/css'>   # Adding the CSS
        body { margin: 0; padding: 0; background-color: #f4f4f4; font-family: Arial, sans-serif; }
        table { border-collapse: collapse; }
        .mailcontainer { width: 100%; max-width: 600px; margin: auto; background-color: #ffffff; }
        .header { background-color: #1c3f60; color: #ffffff; text-align: center; padding: 20px; }
        .body { padding: 20px; font-size: 16px; line-height: 1.6; background-color: #1c3f60; color: #7ed957; }
        .footer { background-color: #ff6100; color: #000000; text-align: center; padding: 20px; }
        .cta { background-color: #8c52ff; padding: 10px 20px; border-radius: 5px; color: #ffffff; text-decoration: none; font-weight: bold; }

        @media screen and (max-width: 600px) {
            .container {
                width: 100% !important;
                padding: 10px !important;
            }
        }
    </style>
</head>
<body>
    <table width='100%' cellpadding='0' cellspacing='0'>
        <tr>
            <td align='center'>
                <table class='container' width='600' cellpadding='0' cellspacing='0'>
                    <!-- Header -->
                    <tr>
                        <td class='header'>
                            <h1>Your order is confirmed</h1>
                        </td>
                    </tr>
                    <!-- Body -->
                    <tr>
                        <td class='body'>
                            <p>The estimated delivery date is 22nd August 2024.</p>
                            <p style='font-size: 16px; color: blue;'>Styled paragraph.</p>
                            <table width='100%' cellpadding='0' cellspacing='0' style='border: 1px solid #1c3f60; padding: 20px;'>
                                <tr>
                                    <td align='center'>
                                        <h1 style='color: #7ed957;'>Hi, Jane!</h1>  
                                        <p style='font-size: 16px; color: #ffde59;'>
                                            Thank you for being our valuable customer!
                                        </p>
                                    </td>
                                </tr>
                            </table>
                            <table cellpadding='0' cellspacing='0' style='margin: auto;'>
                                <tr>
                                    <td align='center' style='background-color: #8c52ff; padding: 10px 20px; border-radius: 5px;'>
                                        <a href='https://www.mydomain.com' target='_blank' rel='noopener noreferrer' style='color: #ffffff; text-decoration: none; font-weight: bold;'>Get a 30-day free trial</a>
                                    </td>
                                </tr>
                            </table>
                        </td>
                    </tr>
                    <!-- Footer -->
                    <tr>
                        <td style='background-color: #ff6100; color: #000000; text-align: center; padding: 20px;'>
                            <p>For additional help, contact us at [email protected]</p>
                        </td>
                    </tr>
                </table>
            </td>
        </tr>
    </table>
</body>

</html>
"""

template1 = Template(html_emailtemp)
html1 = template1.render(name="Jon Doe")

# Attach your MIMEText objects for HTML

message = MIMEText(html1, 'html')
message['Subject'] = subject
message['From'] = sender
message['To'] = recipient

# Send the HTML email

with smtplib.SMTP_SSL('smtp.gmail.com', 465) as server:
    server.login(username, password)
    server.sendmail(sender, recipient, message.as_string())

Explanation:

  • sender: The sender's email address
  • recipient: The recipient's email address
  • from email.mime.text import MIMEText: This is used to import the class MIMEText, enabling you to attach your HTML template in the email.
  • smtplib.SMTP_SSL('smtp.gmail.com', 465) as server:: This establishes a connection with your email provider's (Gmail's) SMTP server using port 465. If you are using another SMTP provider, use their domain name, such as smtp.domain.com, with an appropriate port number. The connection is secured with SSL.
  • server.login(username, password): This function allows you to log in to the email server using your username and password.
  • server.sendemail(sender, recipient, message.as_string()): This command sends the HTML email.

Testing

Before sending your HTML email, test it to understand how different email clients render CSS and HTML. Testing tools like Email on Acid, Litmus, etc. can assist you.

Conclusion

To build custom email templates with HTML and CSS in Python, follow the above instructions. First, begin structuring your HTML email template, style emails with CSS, and then send them to your recipients. Always check your email template's compatibility with different email clients and ensure to keep your HTML simple using tables. Adding an email link in HTML will also allow you to compose an email automatically in your email client and send it to a specific email address.

Last Updated: August 21st, 2024
Was this article helpful?

Improve your dev skills!

Get tutorials, guides, and dev jobs in your inbox.

No spam ever. Unsubscribe at any time. Read our Privacy Policy.

Ivan DjuricAuthor

I’m a Technical Content Writer with 5 years of background covering email-related topics in tight collaboration with software engineers and email marketers. I just love to research and share actionable insights with you about email sending, testing, deliverability improvements, and more. Happy to be your guide in the world of emails!

© 2013-2024 Stack Abuse. All rights reserved.

AboutDisclosurePrivacyTerms