How to Send HTML Emails in Python using SMTP and email API

On April 24, 2024
20min read
Veljko Ristić Content Manager @ Mailtrap
This is a cover image for an article that explains in detail how to send HTML emails with Python

For developers, especially those harnessing the power of Python, sending HTML emails can be a game-changer.

In this ‘Python send HTML email’ guide, we aim to demystify the process for junior developers.

To skip the setup process and jump straight to sending emails with SMTP, [click here].

Setup smtplib and email lib

The native libraries that allow you to craft and send HTML emails effortlessly are the smtplib and email modules.

smtplib module

The smtplib module is a part of Python’s standard library, making it readily available for all Python installations. It empowers you to establish connections with SMTP servers and send emails using the SMTP protocol.

Here’s a high-level overview of how smtplib works:

  • First, you establish a connection to the SMTP server of your choice, like Mailtrap’s SMTP email server.
  • You provide your SMTP server credentials (username and password) and any necessary security settings (TLS/SSL).
  • Then, you create an email message using the email module.
  • Finally, you send the email using the established SMTP connection.

email Module

The email module, another built-in Python library, is used for managing email messages. It allows you to create structured emails with various components such as subject, sender, recipient, and most importantly, the email’s content, including HTML content.

Here’s how the email module typically works:

  • You create an EmailMessage object and set its attributes like subject, from, and to.
  • For the HTML content, you add an HTML email body part to the email message.
  • Attachments, inline images, and alternative plain text content can also be added as needed.
  • The email module helps ensure that your email conforms to email standards.

Together, these two modules provide the fundamental building blocks for sending HTML emails directly from Python, making it accessible to developers of all levels of experience. 

Also, we’ll add the MIME message type, handled by the email.mime module since it can combine HTML and CSS and plain text. 

Note: It’s advisable to have the HTML and plain text versions of an email separate, then merge them using the MIMEMultipart("alternative") instance. This way, you ensure that the text version of the email gets displayed in case there’s an issue with the HTML version. 

Here’s the full code snippet: 

# import the necessary components first
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

port = 587
smtp_server = "live.smtp.mailtrap.io"
login = "1a2b3c4d5e6f7g" # paste your login generated by Mailtrap
password = "1a2b3c4d5e6f7g" # paste your password generated by Mailtrap

sender_email = "mailtrap@example.com"
receiver_email = "new@example.com"
message = MIMEMultipart("alternative")
message["Subject"] = "multipart test"
message["From"] = sender_email
message["To"] = receiver_email

# write the text/plain part
text = """\
Hi,
Check out the new post on the Mailtrap blog:
SMTP Server for Testing: Cloud-based or Local?
https://blog.mailtrap.io/2018/09/27/cloud-or-local-smtp-server/
Feel free to let us know what content would be useful for you!"""

# write the HTML part
html = """\
<html>
  <body>
    <p>Hi,<br>
      Check out the new post on the Mailtrap blog:</p>
    <p><a href="https://blog.mailtrap.io/2018/09/27/cloud-or-local-smtp-server">SMTP Server for Testing: Cloud-based or Local?</a></p>
    <p> Feel free to <strong>let us</strong> know what content would be useful for you!</p>
  </body>
</html>
"""

# convert both parts to MIMEText objects and add them to the MIMEMultipart message
part1 = MIMEText(text, "plain")
part2 = MIMEText(html, "html")
message.attach(part1)
message.attach(part2)

# send your email
with smtplib.SMTP("live.smtp.mailtrap.io", 587) as server:
    server.login(login, password)
    server.sendmail(
        sender_email, receiver_email, message.as_string()
    )

print('Sent')

This script establishes a connection to the Mailtrap SMTP server using the provided credentials. After crafting the email with both plain text and HTML content, it sends the email. 

Always remember to replace the credentials with your actual username and password.

Note: api is the default username for all Mailtrap Sending SMTP users, but the password is unique to each user. 

Send HTML Email in Python using SMTP

You’ve already got the exemplary script. Now, we’ll break it down and walk you through the code step by step.

1. Importing the necessary modules

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

These modules provide tools for working with SMTP (Simple Mail Transfer Protocol) and for constructing email messages.

2. SMTP configuration

port = 587
smtp_server = "live.smtp.mailtrap.io"
login = "1a2b3c4d5e6f7g"
password = "1a2b3c4d5e6f7g"

These are the SMTP server details. The login and password are generated by Mailtrap for each Mailtrap user.

3. Setting the email headers 

sender_email = "mailtrap@example.com"
receiver_email = "new@example.com"
message = MIMEMultipart("alternative")
message["Subject"] = "multipart test"
message["From"] = sender_email
message["To"] = receiver_email

Here, the sender and receiver email addresses are defined. An “alternative” MIMEMultipart message is created, which means the email client will try to render the last part first (in this case, HTML), and if it can’t, it will fall back to the earlier parts (here, plain text).

4. The plain text version

text = """\
...
"""

This is where the plain text (fallback) version of your email goes.

5. The HTML version of the email

html = """\
...
"""

The HTML version – check the full script above for the complete snippet. 

6. Attaching the content to the email

part1 = MIMEText(text, "plain")
part2 = MIMEText(html, "html")
message.attach(part1)
message.attach(part2)

Both the plain text and HTML parts are converted to MIMEText objects. These are then attached to the MIMEMultipart message, making the email multipart.

7. Sending the email

with smtplib.SMTP("live.smtp.mailtrap.io", 587) as server:
    server.login(login, password)
    server.sendmail(
        sender_email, receiver_email, message.as_string()
    )

This section actually sends the email. An SMTP connection to the server is opened, the server is logged into with the provided credentials, and the email is sent using the sendmail method. The email message is converted to a string format using message.as_string().

8. Confirmation

print('Sent')

And that’s it, this simple print() statement confirms your email has been sent via Mailtrap’s SMTP server. Remember always to use the correct SMTP server credentials, be it Mailtrap or other providers, and tailor the email content to your needs.

Important notes:

  • To use Mailtrap Email Sending, you need to add and verify a domain with us, otherwise, the methods won’t work. 

Send HTML emails to multiple recipients

Sending emails to multiple recipients is a common task, especially when disseminating information like newsletters, announcements, or updates. The native Python modules make this task easy and efficient.

  • Modifying the recipient field

The To field in the EmailMessage object accepts a list of email addresses. If you provide multiple email addresses in this list, the email will be sent to each of these recipients. 

Here’s a quick example:

recipients = ['recipient1@example.com', 'recipient2@example.com', 'recipient3@example.com']
msg['To'] = ', '.join(recipients)
  • Using CC and BCC

When sending emails, sometimes you want to include recipients in the Carbon Copy (CC) or Blind Carbon Copy (BCC) fields. 

The former is used to send a copy to interested parties who are not the primary audience, while the latter is for recipients who shouldn’t see the other email addresses the email is sent to.

To send emails with CC and BCC in Python:

cc_recipients = ['cc1@example.com', 'cc2@example.com']
bcc_recipients = ['bcc1@example.com', 'bcc2@example.com']

msg['Cc'] = ', '.join(cc_recipients)
msg['Bcc'] = ', '.join(bcc_recipients)

Reminder: In the context of the smtplib, the BCC recipients won’t see the email addresses of the other BCC recipients, and the primary recipients won’t see any of the BCC email addresses.

However, if you’re sending in bulk, to dozens or hundreds of recipients, Python saves you a lot of headaches if you use loops.

For example, one option is to create a database, formatted in .csv, and save that file in the same folder as your Python sending script. I’ll cover this example here as it’s the closest to what you may encounter in a production scenario. Of course, we assume you already created and saved the recipients’ .csv file. 

Sending personalized HTML emails to multiple recipients

The exemplary script below sends an order confirmation email to multiple recipients whose names and email addresses are stored in a contacts.csv file. The script uses the smtplib module to send the emails and the csv module to read the contacts from the CSV file.

import csv, smtplib

port = 587
smtp_server = "live.smtp.mailtrap.io"
login = "1a2b3c4d5e6f7g" # paste your login generated by Mailtrap
password = "1a2b3c4d5e6f7g" # paste your password generated by Mailtrap
sender = "new@example.com"
message = """Subject: Order confirmation
To: {recipient}
From: {sender}

Hi {name}, thanks for your order! We are processing it now and will contact you soon"""

with smtplib.SMTP("smtp.mailtrap.io", 2525) as server:
    server.login(login, password)
    with open("contacts.csv") as file:
        reader = csv.reader(file)
        next(reader)  # it skips the header row
        for name, email in reader:
            server.sendmail(
                sender,
                email,
                message.format(name=name, recipient=email, sender=sender)
            )
            print(f'Sent to {name}')

Here’s the code breakdown so you can better understand the flow:

  1. Importing modules 
import csv, smtplib

The csv module is used for reading from and writing to CSV files. And the smtplib is used for sending emails using SMTP.

  1. Configuration
port = 587
smtp_server = "live.smtp.mailtrap.io"
login = "1a2b3c4d5e6f7g"
password = "1a2b3c4d5e6f7g"
sender = "new@example.com"

Like before, this part of the script handles SMTP server details, the sender email address, and the corresponding credentials. 

  1. String email template
message = """...
"""

This is a string template for the email. It uses placeholders {recipient}, {sender}, and {name} that will be replaced with actual values for each recipient.

  1. Email sending
with smtplib.SMTP("live.smtp.mailtrap.io", 587) as server:
    server.login(login, password)

Here, a connection to the SMTP server gets established and it logs into the server with the provided credentials.

  1. Open and read the .csv
with open("contacts.csv") as file:
        reader = csv.reader(file)
        next(reader)  # it skips the header row

The script reads the contacts.csv file. The next(reader) line is used to skip the header row of the CSV file, assuming the first row contains column names and not actual data.

  1. Loop through contacts and send
for name, email in reader:
            server.sendmail(
                sender,
                email,
                message.format(name=name, recipient=email, sender=sender)
            )
            print(f'Sent to {name}')

For each name and email pair in the CSV file, the following actions are performed:

  • The message template is filled using the .format() method with the current name, email, and sender values.
  • The email is sent to the current email address using server.sendmail().
  • A print statement indicates to the console that the email has been sent to the current name.

To recap, the script allows for batch sending of personalized emails. It’s particularly useful for situations like order confirmations, event invitations, and other scenarios where you might want to send a similar message to multiple recipients, but with some personalized details.

Pro Tip: If you need to validate email addresses before sending emails, click the link to check our detailed tutorial.

Send HTML email with attachments

Sending attachments via email using Python is a fairly common task, especially when automating certain processes, such as sending reports or invoices. Attachments can be of various types – from simple text files and documents to images and compressed files.

To be exact, you can attach .txt, rich text, text files, images, audio files, and applications. You only need to use the right class, for example:

Audio files – email.mime.audio.MIMEAudio

Image files – email.mime.image.MIMEImage

Here’s the modified version of the script to include the attachments. 

import smtplib

# import the corresponding modules
from email import encoders
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

port = 587
smtp_server = "live.smtp.mailtrap.io"
login = "1a2b3c4d5e6f7g" # paste your login generated by Mailtrap
password = "1a2b3c4d5e6f7g" # paste your password generated by Mailtrap

subject = "An example of boarding pass"
sender_email = "mailtrap@example.com"
receiver_email = "new@example.com"

message = MIMEMultipart()
message["From"] = sender_email
message["To"] = receiver_email
message["Subject"] = subject

# Add body to email
body = "This is an example of how you can send a boarding pass in attachment with Python"
message.attach(MIMEText(body, "plain"))

filename = "yourBP.pdf"
# Open PDF file in binary mode

# We assume that the file is in the directory where you run your Python script from
with open(filename, "rb") as attachment:
    # The content type "application/octet-stream" means that a MIME attachment is a binary file
    part = MIMEBase("application", "octet-stream")
    part.set_payload(attachment.read())

# Encode to base64
encoders.encode_base64(part)

# Add header
part.add_header(
    "Content-Disposition",
    f"attachment; filename= {filename}",
)

# Add attachment to your message and convert it to string
message.attach(part)
text = message.as_string()

# send your email
with smtplib.SMTP("live.smtp.mailtrap.io", 587) as server:
    server.login(login, password)
    server.sendmail(
        sender_email, receiver_email, text
    )
print('Sent')

The script shows how to attach a binary file (in this case, a PDF) to an email. The process involves reading the binary content of the file, wrapping it in a MIME object with the appropriate headers, encoding it with base64, and finally attaching it to the email message.

Here’s the breakdown of the steps, focusing on attaching the image:

  1. Importing the modules
from email import encoders
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

Note that we included the following, on top of the existing modules:

  • encoders – provide access to the base64 encoder which we use for encoding the attachment.
  • MIMEBase – acts as the base for creating MIME objects of a specific content type.
  1. Defining the file to attach
filename = "yourBP.pdf"

The line’s function is pretty self-explanatory, only make sure that the file names match. 

  1. Open the file and create the attachment
with open(filename, "rb") as attachment:
    # The content type "application/octet-stream" means that a MIME attachment is a binary file
    part = MIMEBase("application", "octet-stream")
    part.set_payload(attachment.read())

Here, the file is opened in binary read mode ("rb") and its content is read. The MIME attachment is then created as a binary file with the content type "application/octet-stream". This content type is a general binary file MIME type and is used here to represent the PDF.

  1. Encoding the attachment
encoders.encode_base64(part)

The MIME attachment (which is the PDF content) is then encoded using base64 encoding, which ensures secure data transfer as text, without any corruptions in the PDF contents.  

  1. Adding headers
part.add_header(
    "Content-Disposition",
    f"attachment; filename= {filename}",
)

The header "Content-Disposition" is added to indicate that the MIME object is an attachment. It also specifies the filename for the attachment. This ensures that when the recipient opens the email, they will see the file presented as an attachment named “yourBP.pdf”.

  1. Attaching the file to the email
message.attach(part)
text = message.as_string()

The attachment (part) is added to the overall email message. The entire message, including its text and the attachment, is then converted to a string using message.as_string(). This string representation is what’s sent through the SMTP server.

Pro tips:

  1. Relevance is key: Only attach files that are relevant to the content of your email. Unnecessary attachments can be confusing for the recipient.
  1. File naming conventions: Adopt clear and descriptive file names. This helps the recipient understand the content without opening it. For example, instead of naming a file `report.pdf`, consider a more descriptive name like `Q3_Sales_Report_2023.pdf`.
  1. Compress large files: To ensure the efficient sending and downloading of files, use compression tools to reduce the size of larger attachments. Tools like `zip` or `rar` can be invaluable.

Note: If you’re an Apple user, it’s best to opt for the native compression/”zipping” option. Two-finger tap or right-click on a file or folder, then choose “Compress “file_name””. 

  1. File type considerations: Always ensure that the file type you’re sending is commonly used and can be easily accessed by the recipient. It might be frustrating for them if they need to download special software just to view your attachment.

The rule of thumb is to stick to widely recognized file formats, such as `.pdf`, `.docx`, or `.xlsx`, when sending documents. This ensures maximum compatibility with the recipient’s software.

Tip: Mailtrap doesn’t have any limitations for attachment file types. 

  1. Alert the recipient: If you’re sending a particularly large file or multiple attachments, it’s a good practice to notify the recipient in the body of the email. This gives them a heads-up and ensures they check all the attachments.
  1. Scan for malware: Always ensure that the files you’re attaching are free from malware or viruses. This not only protects the recipient but also your reputation.
  1. Limit the number: Avoid sending too many attachments in a single email. If you have multiple files, consider combining them into a single compressed file or sharing a cloud storage link where the recipient can access them.
  1. Test before sending: Especially when working with important emails or a new system, send a test email to yourself or a colleague first. Ensure that the attachments come through correctly and can be opened without issues.

Note: Later in the article, you’ll find a tutorial on how to test emails with Mailtrap and check mobile compatibility, HTML and CSS, and get a spam score.

Send HTML email with embedded image

When you send marketing emails, newsletters, or any communication that demands user attention, images play an indispensable role. They add aesthetic appeal and can convey complex ideas quickly. 

Embedding an image from a local directory

Keep in mind that images are still regarded as attachments, even if they’re a part of the email body. There are three ways, or three methods, to embed the image:

  1. CID attachments (which get embedded with a MIME object)
  2. Base64 images (which is the so-called inline embedding)
  3. Linked images

In this section, we’ll explore the CID attachments and the Base64 images. Then, we’ll just touch upon linking images from an external resource. 

CID attachments

The script below features a MIME multipart message, containing the MIMEImage component. Here’s the full script. 

# import all necessary components
import smtplib
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart

port = 587
smtp_server = "live.smtp.mailtrap.io"
login = "1a2b3c4d5e6f7g" # paste your login generated by Mailtrap
password = "1a2b3c4d5e6f7g" # paste your password generated by Mailtrap

sender_email = "mailtrap@example.com"
receiver_email = "new@example.com"
message = MIMEMultipart("alternative")
message["Subject"] = "CID image test"
message["From"] = sender_email
message["To"] = receiver_email

# write the HTML part
html = """\
<html>
<body>
  <img src="cid:Mailtrapimage">
</body>
</html>
"""

part = MIMEText(html, "html")
message.attach(part)

# We assume that the image file is in the same directory that you run your Python script from
fp = open('mailtrap.jpg', 'rb')
image = MIMEImage(fp.read())
fp.close()

# Specify the  ID according to the img src in the HTML part
image.add_header('Content-ID', '<Mailtrapimage>')
message.attach(image)

# send your email
with smtplib.SMTP("live.smtp.mailtrap.io", 587) as server:
    server.login(login, password)
    server.sendmail(
        sender_email, receiver_email, message.as_string()
    )
print('Sent')

Check the code breakdown, we’ll only focus on MIME components and embedded images. 

  1. Importing the modules
from email.mime.image import MIMEImage

The MIMEImage class creates the MIME message object specific to the image attachments. 

  1. The HTML email with the embedded image
# write the HTML part
html = """\
<html>
<body>
  <img src="cid:Mailtrapimage">
</body>
</html>
"""

This section defines the HTML content of the email. The <img> tag features the src attribute value of the cid:Mailtrapimage.  The “cid” stands for Content ID and is a way to reference attachments embedded within the email. In this instance, the image with the content ID Mailtrapimage will be displayed wherever the <img> tag appears in the HTML.

  1. Attaching the HTML to the message: 
part = MIMEText(html, "html")
message.attach(part)

The snippet constructs a MIMEText object from the HTML string and attaches it to the main email message.

  1. Embedding the image 
# We assume that the image file is in the same directory that you run your Python script from
fp = open('mailtrap.jpg', 'rb')
image = MIMEImage(fp.read())
fp.close()

# Specify the  ID according to the img src in the HTML part
image.add_header('Content-ID', '<Mailtrapimage>')
message.attach(image)

Here, the script does the following:

  • It opens the image file mailtrap.jpg in binary reading mode ('rb').
  • A MIMEImage object named image is created from the binary content of the image.
  • The Content ID header is added to the image object. This Content ID (<Mailtrapimage>) corresponds to the cid used in the HTML content. This association allows the email client to understand where to display the embedded image.
  • Finally, the image object is attached to the main email message.

Base64 module method

The refactored script below demonstrates an alternative way of embedding images in emails with Base64 encoding. This method involves directly embedding the Base64 encoded string of an image within the HTML content of the email. 

More importantly, the email becomes self-contained without the need for external image references or Content IDs (as in the previous method). It’s an effective way to ensure images are displayed in most email clients without relying on external servers. 

However, it might increase the size of the email, especially for larger images. With Base64 encoding, you may expect a data size increase of up to 33%.

# import the necessary components first
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import base64

port = 587
smtp_server = "live.smtp.mailtrap.io"
login = "1a2b3c4d5e6f7g" # paste your login generated by Mailtrap
password = "1a2b3c4d5e6f7g" # paste your password generated by Mailtrap

sender_email = "mailtrap@example.com"
receiver_email = "new@example.com"
message = MIMEMultipart("alternative")
message["Subject"] = "inline embedding"
message["From"] = sender_email
message["To"] = receiver_email

# We assume that the image file is in the same directory that you run your Python script from
encoded = base64.b64encode(open("mailtrap.jpg", "rb").read()).decode()

html = f"""\
<html>
<body>
  <img src="data:image/jpg;base64,{encoded}">
</body>
</html>
"""

part = MIMEText(html, "html")
message.attach(part)

# send your email
with smtplib.SMTP("live.smtp.mailtrap.io", 587) as server:
    server.login(login, password)
    server.sendmail(
        sender_email, receiver_email, message.as_string()
    )
print('Sent')

Check the code breakdown, again we’re focusing only on embedding images:

  1. Importing the base64 module
import base64

The line imports the base64 module, which provides functions to encode and decode data using the Base64 encoding scheme. 

  1. Encoding 
# We assume that the image file is in the same directory that you run your Python script from
encoded = base64.b64encode(open("mailtrap.jpg", "rb").read()).decode()

Here, the following actions take place:

  • The script opens the image file mailtrap.jpg in binary reading mode ('rb').
  • The content of the image file is read and then encoded using base64.b64encode(). This function returns a bytes-like object.
  • The .decode() method is applied to convert the bytes-like object into a UTF-8 encoded string representation of the Base64 encoded image. This string representation is stored in the encoded variable.
  1. Embedding the encoded image into HTML
html = f"""\
<html>
<body>
  <img src="data:image/jpg;base64,{encoded}">
</body>
</html>
"""

The encoded Base64 string basically gets embedded directly into HTML and here’s how:

  • The src attribute of the <img> tag is set to a Data URL. This URL starts with the prefix data:image/jpg;base64, followed by the Base64 encoded string of the image (represented by {encoded} in the f-string).
  • Data URLs allow you to embed data directly into web documents, thereby avoiding external image references. It’s especially useful for smaller images, ensuring they get displayed even if the recipient is offline or their email client blocks external loads.

Embedding an image from a remote server

If your image is hosted on a remote server, it’s generally recommended to link it directly:

<img src="https://yourserver.com/path_to_image.jpg">

However, this means the email client must fetch the image from the server, which may or may not happen based on the client’s settings. Honestly, more secure apps would typically block the request. 

Anyway, always ensure you have permission to link directly to an image on a remote server before using this method.

Supported image formats

While many image formats exist, the most commonly supported formats in email clients are JPEG and PNG. Both are well-suited for emails due to their wide support and compression capabilities.

  • JPEG (.jpeg): Best suited for photographs or images with gradients.
  • PNG (.png): Ideal for images with transparency, logos, or text.

Tip on HEIC: Apple’s image format, offers great compression advantages. However, it’s not universally supported across all email clients. It might be best to convert HEIC images to JPEG or PNG before embedding them in emails.

Mailtrap image size limits

If you’re using Mailtrap Email Sending via API, you can leverage Mailtrap Email Templates and upload the images you want to embed directly to our platform. 

Mailtrap templates use the Hanlebars syntax, so it’s possible to add logical operators to automate and customize the templates. As for the image limitations, we support the following:
 

  • Formats: JPG, PNG, GIF
  • Max file size: 2 MB 

Image size optimization tips

Embedding images can make your emails quite “heavy”, leading to slow load times and possible delivery issues. Here are a few tips to avoid that:

  1. Resize images: Ensure your image dimensions are no larger than they need to be.
  2. Compress Images: Use tools like TinyPNG or Compressor.io to reduce file size without compromising on quality.
  3. Avoid embedding large images: If an image is too large, consider linking to it instead of embedding it. Or you may send it as a compressed attachment. 

Python snippet for image compression (using the Pillow library)

Now, the best method could probably be, to stay within the Python environment and leverage the Pillow library to optimize image size. Here’s how to do it:

First, install the required library:

pip install Pillow

Now, you can use the following snippet to compress images:

from PIL import Image

def compress_image(image_path, output_path, quality=85):
    with Image.open(image_path) as img:
        img.save(output_path, "JPEG", optimize=True, quality=quality)

compress_image("path_to_image.jpg", "compressed_image.jpg")

Adjust the quality parameter as needed. Lower values will result in higher compression but might decrease image quality.

No doubt, images can immensely boost the impact of your emails. Only ensure you’re using the right formats, optimize appropriately, and respect permissions when sourcing from external servers.

Mailtrap email size limits

Previously, we mentioned that the max size of an embedded image within a Mailtrap email template is 2 MB. Here we discuss the size of the entire email. 

The max size of an entire email, attachments included, is 10 MB (10240 KB) across all plans, Free plan included. Upon request, users can get the limit extended up to 30 MB (30720 KB). 

As a general guideline, please ensure that your total email size, including all attachments, doesn’t go beyond the set limit. Exceeding this limit could result in your email not being sent or delivered as expected.

Send HTML email using API

Email Application Programming Interfaces (APIs) offer a more scalable, efficient, and often simpler way to send emails, as opposed to traditional SMTP setups. 

For this tutorial, we will delve into the Mailtrap Python SDK, as it offers a simplified interface to send, receive, and test emails; all while interacting with Mailtrap’s API.

Mailtrap-python on GitHub is the official repository for Mailtrap’s Python SDK, and Mailtrap’s API Documentation provides in-depth details on how to harness the full power of this tool.

To get started, you’ll need to first install the SDK.

pip install mailtrap

Now, here’s a basic example to send an email with minimal resource usage. 

import mailtrap as mt

# create mail object
mail = mt.Mail(
    sender=mt.Address(email="mailtrap@example.com", name="Mailtrap Test"),
    to=[mt.Address(email="your@email.com")],
    subject="You are awesome!",
    text="Congrats for sending test email with Mailtrap!",
)

# create client and send
client = mt.MailtrapClient(token="your-api-key")
client.send(mail)

Remember to replace "your-api-key" and with your actual Mailtrap API token. And you can find the full usage example on our GitHub page

If you want to use templates with Mailtrap, here’s how to create the mail object and send. 

import mailtrap as mt

# create mail object
mail = mt.MailFromTemplate(
    sender=mt.Address(email="mailtrap@example.com", name="Mailtrap Test"),
    to=[mt.Address(email="your@email.com")],
    template_uuid="2f45b0aa-bbed-432f-95e4-e145e1965ba2",
    template_variables={"user_name": "John Doe"},
)

# create client and send
client = mt.MailtrapClient(token="your-api-key")
client.send(mail)

The beauty of Mailtrap’s Python SDK is that it allows for a multitude of customizations and configurations. You can add attachments, utilize CC/BCC, and get the following:  

  1. Simplicity: Using Mailtrap’s Python SDK, you can avoid setting up SMTP configurations and reduce the boilerplate code that’s typically required when sending emails.
  2. Testability: Mailtrap offers a safe environment to test and view your emails before sending them to actual users, avoiding potential mishaps.
  3. Scalability: If you’re building applications that require sending a large volume of emails, using an API is often a better solution than SMTP due to its inherent capability to handle bulk requests.

Tips:

  • Store credentials securely: Never hard-code your API token or credentials. Use environment variables or secret management tools.
  • Error handling: Always incorporate error handling when working with APIs to gracefully manage any unforeseen issues.
  • Monitor usage: Keep an eye on your API usage to ensure you’re not hitting any rate limits or overusing your allowed quota. Mailtrap’s documentation provides detailed information on limits and quotas.

Test HTML email and email sending in a staging environment

Sending HTML emails without proper testing can lead to formatting issues, broken links, and a poor user experience. This section highlights the significance of email testing and provides strategies for thorough testing.

  • Consistency: Ensure that your email appears consistently across different email clients (Gmail, Outlook, Apple Mail, etc.) and devices (desktop, mobile).
  • Mobile responsiveness: A significant portion of email opens happens on mobile devices. Test to make sure your emails are mobile-friendly and display correctly on various screen sizes.
  • Broken links and images: Test for broken links and images to prevent users from encountering missing or inaccessible content.
  • Spam avoidance: Properly formatted emails are less likely to be flagged as spam. Testing helps maintain a good sender reputation.

Mailtrap Email Testing provides a comprehensive solution for testing HTML emails. It allows you to:

  • Preview emails in various email clients.
  • Check how emails render on mobile devices.
  • Verify links and images to avoid broken elements.
  • Ensure email client compatibility.
  • Validate spam scores to improve deliverability.

Mailtrap gives you two options to test your emails, a simple integration with SMTP (we give you access to a fake SMTP), or you can fully automate testing flows with the corresponding API. 

The following sections assume you’re already a Mailtrap Email Testing user. If not, you can sign up here

Important Note: You don’t need to add and verify a domain to use Mailtrap Email Testing. 

SMTP

  1. Select Email Testing and you’ll see that we already created an empty testing inbox for you, labeled My Inbox. 
  1. Click on the inbox, and select Python smtplib under the Integrations tab. We also offer ready-made code snippets for Django and Flask-Mail. 


Benefit – using the lib, you don’t need to copy-paste your credentials. 

  1. Run the code and your test email should appear under My Inbox in no time. 

Important Notes:

  • You can rename your inbox by clicking on the pencil icon under Action
  • For security reasons, we keep your SMTP/POP3 credentials hidden. And we suggest you do the same. Clicking Shows Credentials reveals them. 
  • By default, our exemplary scripts use port 2525. But, depending on your system and environment the port could be blocked by a firewall. If that’s the case, switch to port 587. 

API

Mailtrap testing API can return calls as JSON objects and it uses REST protocol. Also, it’s compatible with most programming languages.

Supported HTTP requests:

  •  POST – create a resource
  •  PATCH – update a resource
  •  GET – get a resource or list of resources
  •  DELETE – delete a resource

And here’s how to get started:

  1. Within Mailtrap select Settings, then API Tokens
  2. Grab your API token, then proceed to send HTTP requests 
  3. Use one of the following methods to send the authenticated request:
  • Send a HTTP header  Api-Token: {api_token}, where {api_token} is your API token. 
  • Send a HTTP header Authorization: Bearer #{token}, where #{token}  is your API token. 

Useful resources:

  1. API – Testing send email with examples Pyhon/Pyhon 3
  2. Our YouTube tutorial on testing in Python

The digital ouroboros 

We hope your journey through Python HTML email landscape has been enlightening. We delved into various methods, from native Python libraries to the simplicity of Mailtrap’s Python SDK. 

And, by now, you should have mastered SMTP, handling multiple recipients, image embedding, and attachments. Beyond that, we also shed a light at the heart of email success: comprehensive testing. 

The keys to successful delivery are in ensuring emails render consistently, embracing mobile responsiveness, and gracefully dancing across email clients. 

With this wisdom in your arsenal, you’re poised not just to send emails but to weave engaging narratives that resonate deeply with your recipients.

Article by Veljko Ristić Content Manager @ Mailtrap

Linguist by trade, digital marketer at heart, I’m a Content Manager who’s been in the online space for 10+ years. From ads to e-books, I’ve covered it all as a writer, editor, project manager, and everything in between. Now, my passion is with email infrastructure with a strong focus on technical content and the cutting-edge in programming logic and flows. But I still like spreading my gospels while blogging purely about marketing.