The Detailed Guide on Sending Emails from your Python App

by Andrew Zapisotskyi
7 minute read

teaser

Hey there! Now you are reading a quick but detailed guide on adding the essential functionality to your web app built with Python: email sending. From this post, you will learn about the capabilities of the native Python modules for email sending and then get the practical steps for creating a message with images and attachments. With plenty of code examples, you will be able to craft and send your own emails using an SMTP server.

Before we start

Just a brief theory and a couple of notes before we move to coding. In Python, there is an email package designed for handling email messages. We will explain how to use its main modules and components. It’s simple but comprehensive so that you don’t need any additional libraries, at least, for a start.

This guide was created and tested with Python version 3.7.2.

How to configure email sending

First of all, we need to import the necessary modules. The main one for sending emails is smtplib. From the very beginning, help(smtplib) is indeed very helpful: it will provide you with the list of all available classes and arguments as well as confirm whether smtplib was properly imported:

1import smtplib
2help(smtplib)

Define SMTP server

Before we can move to the first code sample, we should define an SMTP server. We strongly recommend starting by testing options and only when everything is set up and tested, switch to the production server.

Python provides an smtpd module for testing your emails in the local environment. There is a *DebuggingServer *feature, for discarding your sent messages and printing them to stdout.

Set your SMTP server to localhost:1025

python -m smtpd -n -c DebuggingServer localhost:1025

With the local debugging, you can check whether your code works and detect the possible problems. Nevertheless, you won’t be able to preview your email template and verify whether it works as designed with it. For this purpose, we would advise you to use a dedicated testing tool.

Sending emails via Gmail or another external SMTP server

To send an email via any SMTP server, you have to know the hostname and port as well as get your username and password.

The difference in sending emails via Gmail is that you need to grant access for your applications. You can do it in two ways: allowing less secure apps (2-step verification should be disabled) or using the OAuth2 authorization protocol. The latter is more secure.

The Gmail server credentials are:

  • the server name = smtp.gmail.com
  • port = 465 for SSL/TLS (preferred) or 587 for STARTTLS connection
  • username = your Gmail email address
  • password = your password
1import smtplib, ssl
2port = 465  
3password = input("your password")
4context = ssl.create_default_context()
5with smtplib.SMTP_SSL("smtp.gmail.com", port, context=context) as server:
6    server.login("my@gmail.com", password)

Alternatively, you can try Yagmail, the dedicated Gmail/SMTP, which simplifies email sending with Gmail:

1import yagmail
2yag = yagmail.SMTP()
3contents = [
4    "This is the body, and here is just text http://somedomain/image.png",
5    "You can find an audio file attached.", '/local/path/to/song.mp3'
6]
7yag.send('to@someone.com', 'subject', contents)

Finally, let’s review the whole example. We will use some external SMTP server:

 1import smtplib
 2port = 2525
 3smtp_server = "smtp.yourserver.com"
 4login = "1a2b3c4d5e6f7g" # paste your login 
 5password = "1a2b3c4d5e6f7g" # paste your password 
 6# specify the sender's and receiver's email addresses
 7sender = "my@example.com"
 8# make sure you are not sending test emails to real email addresses 
 9receiver = "your@example.com"
10# type your message: use two newlines (\n) to separate the subject from the message body and use 'f' to  automatically insert variables in the text
11message = f"""\
12Subject: Hi there
13To: {receiver}
14From: {sender}
15This is my first message with Python."""
16#send your message with credentials specified above
17with smtplib.SMTP(smtp_server, port) as server:
18        server.login(login, password)
19        server.sendmail(sender, receiver, message)
20print('Sent')

Sending personalized emails to multiple recipients

Python lets you send multiple emails with dynamic content with almost no extra effort, with the help of loops. Make a database in a **.csv **format and save it to the same folder as your Python script. The most simple example is a table with two columns - name and email address - as follows:

#name,email
John Johnson,john@johnson.com
Peter Peterson,peter@peterson.com

The file will be opened with the script and its rows will be looped over line by line. In this case, the {name} will be replaced with the value from the “name” column:

 1import csv, smtplib
 2port = 2525 
 3smtp_server = "smtp.yourserver.com"
 4login = "1a2b3c4d5e6f7g" # paste your login 
 5password = "1a2b3c4d5e6f7g" # paste your password 
 6message = """Subject: Order confirmation
 7To: {recipient}
 8From: {sender}
 9Hi {name}, thanks for your order! We are processing it now and will contact you soon"""
10sender = "new@example.com"
11
12with smtplib.SMTP(smtp_server, port) as server:
13    server.login(login, password)
14    with open("contacts.csv") as file:
15        reader = csv.reader(file)
16        next(reader)  # it skips the header row
17        for name, email in reader:
18            server.sendmail(
19              sender,
20              email,
21              message.format(name=name, recipient=email, sender=sender)
22            )
23            print(f'Sent to {name}')

As a result, you should receive the following response:

Sent to John Johnson
Sent to Peter Peterson

Let’s add HTML content

We have examined how the email sending works. Now it’s time to create email templates containing images and file attachments.

In Python, this can be done with the email.mime module, which handles the MIME message type. Write a text version apart from the HTML one, and then merge them with the MIMEMultipart(“alternative”) instance.

 1import smtplib
 2from email.mime.text import MIMEText 
 3from email.mime.multipart import MIMEMultipart 
 4port = 2525 
 5smtp_server = "smtp.yourserver.com" 
 6login = "1a2b3c4d5e6f7g" # paste your login 
 7password = "1a2b3c4d5e6f7g" # paste your password 
 8sender_email = "sender@example.com" 
 9receiver_email = "new@example.com" 
10message = MIMEMultipart("alternative") 
11message["Subject"] = "multipart test" 
12message["From"] = sender_email 
13message["To"] = receiver_email 
14
15# write the plain text part 
16text = """\ Hi, Check out the new post on our blog blog: How to Send Emails with Python? https://blog.example.com/send-email-python/ Feel free to let us know what content would be useful for you!""" 
17
18# write the HTML part 
19html = """\ <html> <body> <p>Hi,\n Check out the new post on our blog blog: </p> <p><a href="https://blog.example.com/send-email-python/">How to Send Emails with Python?</p> <p> Feel free to <strong>let us</strong> know what content would be useful for you!</p> </body> </html> """
20
21# convert both parts to MIMEText objects and add them to the MIMEMultipart message 
22part1 = MIMEText(text, "plain") 
23part2 = MIMEText(html, "html") 
24message.attach(part1)
25message.attach(part2) 
26
27# send your email with smtplib.SMTP("smtp.yourserver.com", 2525) as server: server.login(login, password) 
28server.sendmail( sender_email, receiver_email, message.as_string() ) 
29print('Sent')

How to attach files in Python

In Python, email attachments are treated as the MIME objects. But first, you need to encode them with the base64 module.

You can attach images, text and audio, as well as applications. Each of the file types should be defined by the corresponding email class - for example, *email.mime.image.MIMEImage or email.mime.audio.MIMEAudio. *For details, follow this section of the Python documentation.

Example of attaching a PDF file:

 1import smtplib
 2# import the corresponding modules
 3from email import encoders
 4from email.mime.base import MIMEBase
 5from email.mime.multipart import MIMEMultipart
 6from email.mime.text import MIMEText
 7
 8port = 2525 
 9smtp_server = "smtp.yourserver.com"
10login = "1a2b3c4d5e6f7g" # paste your login 
11password = "1a2b3c4d5e6f7g" # paste your password 
12subject = "An example of boarding pass"
13sender_email = "sender@example.com"
14receiver_email = "new@example.com"
15
16message = MIMEMultipart()
17message["From"] = sender_email
18message["To"] = receiver_email
19message["Subject"] = subject
20
21# Add body to email
22body = "This is an example of how you can send a boarding pass in attachment with Python"
23message.attach(MIMEText(body, "plain"))
24filename = "yourBP.pdf"
25
26# Open PDF file in binary mode
27# We assume that the file is in the directory where you run your Python script from
28with open(filename, "rb") as attachment:
29    # The content type "application/octet-stream" means that a MIME attachment is a binary file
30    part = MIMEBase("application", "octet-stream")
31    part.set_payload(attachment.read())
32
33    # Encode to base64
34    encoders.encode_base64(part)
35
36    # Add header 
37    part.add_header(
38        "Content-Disposition",
39        f"attachment; filename= {filename}",
40    )
41
42    # Add attachment to your message and convert it to string
43    message.attach(part)
44    text = message.as_string()
45
46    # send your email
47    with smtplib.SMTP("smtp.yourserver.com", 2525) as server:
48        server.login(login, password)
49        server.sendmail(
50            sender_email, receiver_email, text
51        )
52
53    print('Sent')

Call the message.attach() method several times for adding several attachments

Embed an image

There are three common ways to include an image in an email message: base64 image (inline embedding), CID attachment (embedded as a MIME object), and linked image.

In the example below we will experiment with inline embedding.

For this purpose, we will use the base64 module:

 1# import the necessary components first
 2import smtplib
 3from email.mime.text import MIMEText
 4from email.mime.multipart import MIMEMultipart
 5import base64
 6
 7port = 2525
 8smtp_server = "smtp.yourserver.com"
 9login = "1a2b3c4d5e6f7g" # paste your login 
10password = "1a2b3c4d5e6f7g" # paste your password 
11sender_email = "sender@example.com"
12receiver_email = "new@example.com"
13message = MIMEMultipart("alternative")
14message["Subject"] = "inline embedding"
15message["From"] = sender_email
16message["To"] = receiver_email
17
18# The image file is in the same directory that you run your Python script from
19encoded = base64.b64encode(open("illustration.jpg", "rb").read()).decode()
20html = f"""\
21<html>
22 <body>
23   <img src="data:image/jpg;base64,{encoded}">
24 </body>
25</html>
26"""
27
28part = MIMEText(html, "html")
29message.attach(part)
30
31# send your email
32with smtplib.SMTP("smtp.yourserver.com", 2525) as server:
33    server.login(login, password)
34    server.sendmail(
35       sender_email, receiver_email, message.as_string()
36   )
37print('Sent')

That’s it!

Useful resources for sending emails with Python

Python offers a wide set of capabilities for email sending. In this article, we went through the main steps. To go further, you can refer to the Python documentation and also try additional libraries such as Flask Mail or Marrow Mailer.

Here you will find a really awesome list of Python resources sorted by their functionality.

This article was originally published on Mailtrap’s blog: Sending emails with Python.


Did you find this article helpful?


Buy me a coffee! Buy me a coffee!