How to Send Emails With Python

Python is a highly versatile programming language.

It has a diverse ecosystem of open-source libraries that make it easy to build common functionality in a project. Sending emails with Python is one example of such functionality.

Sending emails is extremely useful - it allows you to send bulk emails, send confirmation or verification codes to users, or even automate regular emailing tasks.

This tutorial will teach you how to send emails with Python using SMTP (Simple Mail Transfer Protocol).

Table of Contents

You can skip to a specific section of this tutorial on how to send emails with Python using the table of contents below:

Prerequisites

There's a few things you need before you can send emails with Python. Let’s get the prerequisites out of the way before we proceed further:

  • Python: I assume that you already have Python installed. If not, please install the latest stable version from here.
  • A Gmail account: It’s fine to use an existing Gmail account. However, in this tutorial, you'll need to change a Gmail security setting. You'll also be using your username and password in plain text. I recommend you create a separate Gmail account for this tutorial because of this.

Note: It is possible to use your existing account to send emails with Python without changing your security settings. To do this, you need to interact with the Gmail API. That’s a topic for another day.

Whether you create a new account or use an existing one, the first thing you'll need to do is turn ON “Less secure app access”. Click here to go to the relevant page on your Gmail account settings page. Ensure that you are logged in to the correct account if you are logged in to multiple accounts on the same browser.

Now that your Gmail account is set up properly, there's a few Python libraries you'll need to install:

  • The SSL Library

In this tutorial, you'll be using a secure SMTP connection. We'll need the SSL library to do this. Open a shell or command prompt and install it using pip with the following command:

pip install ssl

  • smtplib (part of the standard Python library)

SMTPLib is included as a part of the standard libraries of Python. This means you will not need to install it explicitly, but it's important to know what you'll be working with moving forward.

Online and Offline Email Sending Options

You can test the code in this tutorial using both localhost and Gmail. This allows you to simulate the process as well as to send emails using a real account. Let's explore both of these options one-by-one.

Offline Option - Local SMTP server

Setting up a local SMTP server is a good way to test the functionality of your code. You can send emails and print their content in an interactive shell.

Enter the following command to the terminal to start a local SMTP debugging server.

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

If you want to use a port other than 1025, you will need administrator privileges.

The code in this tutorial is mainly targeted for real-world testing. If you want to test your code using a local SMTP debugging server, this configuration will clear things up for you to adapt the other code to your requirement.

Here's an example of code you could use to simlulate the delivary of emails locally:

import smtplib

smtp_server = 'localhost'

port = 1025

sender = 'from@someemail.com'

receiver = 'sendingto@somemail.com'

message = 'Hi. This is a test.'

with smtplib.SMTP(smtp_server, port) as server:

 server.sendmail(sender, receiver, message)

This will simulate sending an email through your local server.

Online Option - Generic email account (Gmail)

This is a great way to put your code to the test and see it actually deliver to an email inbox. We will see an example of this in the next section.

Secure SMTP Connection

In the previous section, we sent an email through a local SMTP server without proper security or encryption. When you send emails in the real-world, this is not advisable.

You need to make sure that your SMTP connection is secure. There are two protocols that make an SMTP connection secure:

  • SSL (Secure Socket Layer)
  • TLS (Transport Layer Security).

TLS is an improved version of SSL. Although SSL is somewhat older, it is still widely used.

There are also two ports (465, 587) that you will use to initiate the connection.

If port 587 is used, an unencrypted connection is established, and later encrypted. The connection is initiated using server = smtplib.SMTP and later encrypted using server.starttls.

If port 465 is used, then SSL encryption is initiated prior to any communication. The SMTP connection is initiated using server = smtplib.SMTP_SSL

Despite the port used, Gmail will encrypt the connection using TLS. However, default and trusted CA certificates and their validation can be loaded by calling .create_default_context()and creating a secure SSL context.

Sending Emails

Plain Text Emails

We will be using port 465 in this guide. However, the code required for both ports is given below.

Let’s send an email with only a body and no subject. Be mindful to change the sender and receiver addresses, and password accordingly.

Port 465

import smtplib, ssl  
smtp_server = 'smtp.gmail.com'  
port = 465  
sender = 'from@someemail.com'  
password = 'myPassword'  
receiver = 'nick@nickmccullum.com'  
message = 'Hi. This is port 465.'  
  
context = ssl.create_default_context()  
with smtplib.SMTP_SSL(smtp_server, port, context=context) as server:  
server.login(sender, password)  
server.sendmail(sender, receiver, message)

Port 587

import smtplib, ssl  
smtp_server = 'smtp.gmail.com'  
port = 587  
sender = 'from@someemail.com'  
password = 'myPassword'  
receiver = 'nick@nickmccullum.com'  
message = 'Hi. This is port 587.'  
context = ssl.create_default_context()  
  
try:  
server = smtplib.SMTP(smtp_server,port)  
server.starttls(context=context)  
  
server.login(sender, password)  
server.sendmail(sender, receiver, message)  
except Exception as exep:  
print(exep)  
finally:  
server.quit()

Adding a Subject to the Email

We can add a subject by changing the message to have a ‘Subject:’ and having two newline characters. (\n).

Change the message variable (as shown below) and try resending the email. Please note the triple quotes instead of a single quote.

message = """Subject: Hi there

  
This message is sent from Python.""

If you want to use single quotes instead, use the following code:

message = 'Subject: Hi \n\n This message is sent from Python. '

Styling the Email

In the last section of this tutorial, we sent emails with a subject line and a simple body. This is usually not enough to solve real-world email-related problems. You'll need to style your text, add hyperlinks, and include images.

We'll use Python's built-in email module for this. The code is rather long, so let’s go through it one step at a time.

First, let's import our libraries and define the variables.

import smtplib, ssl  
from email.mime.text import MIMEText  
from email.mime.multipart import MIMEMultipart  
smtp_server = 'smtp.gmail.com'  
  
port = 465  
sender = 'from@someemail.com'  
password = 'myPassword'  
receiver = 'sendingto@somemail.com'

The next thiing you'll need to do is define a MIMEMultipart object. You'll convert this into a string later and send this as the email message.

message = MIMEMultipart('alternative')  
message['Subject'] = 'MIME Test'  
message['From'] = sender  
message['To'] = receiver

Next you'll create plain-text and HTML versions of the email you want to send.

email_plain = """\  
Hey there,  
Take care  
Bye!"""

  
email_html = """\  
<html>  
<body>  
<p>Hey there,<br>Take care<br>Bye!</p>  
</body>  
</html>  
"""

Next you'll transform these plain-text and HTML emails into MIMETEXT objects and attach them to the message.

mimetext_plain = MIMEText(email_plain, "plain")  
mimetext_html = MIMEText(email_html, "html")  
message.attach(mimetext_plain)  
message.attach(mimetext_html)

Now you can send the email!

context = ssl.create_default_context()  
  
with smtplib.SMTP_SSL(smtp_server, port, context=context) as server:  
server.login(sender, password)  
server.sendmail(sender, receiver, message.as_string())

This code gets the jbo done. However, it requires us to write lots of boilerplate code.

We can greatly reduce the number of lines required to send an email if we use the email_to library. It simplifies the entire email delivery and styling process by combining smtplib and MIMEText into one library.

We'll try this approach now. First, install the email-to library using the following command in your terminal:

pip install email-to

The Python code to send an email with the email_to library is below.

import email_to  
smtp_server = 'smtp.gmail.com'  
port = 587  
sender = 'from@someemail.com'  
password = 'myPassword'  
receiver = 'sendingto@somemail.com'  
server = email_to.EmailServer(smtp_server, port, sender, password)  
server.quick_email(receiver, 'Testing New Library',  
['# My Title', 'My description'],  
style='h1 {color: red}')

Notice the port number 587 instead of 465. This is what is used by the email_to library by default.

This library also supports building the body of your email line by line. Here's an example:

import email_to
smtp_server = 'smtp.gmail.com'
port = 587
sender = 'from@someemail.com'
password = 'myPassword'
receiver = 'nick@nickmccullum.com'
server = email_to.EmailServer(smtp_server, port, sender, password)
message = server.message()
message.add('# Here is the shopping list')
message.add('- Milk')
message.add('- Espresso')
message.add('- Sugar')
message.style = 'h1 { color: red}'
message.send(receiver, 'My Shopping List')

As you can see, you can use the message.add() method to add lines to your email body.

Adding Attachments to the Email

Sending attachments is an important part of sending emails.

We need to encode the files to be sent via email since we are working with a stream of textual data.

The easiest way to do it is to use encoders.encode_base64().

Let's see this principle in action. Note that while we'll be using an image in this tutorial, you can use similar logic to send other file types (like PDFs). With that said, Gmail does refuse certain file extensions like .exe.

First, let's build our code to the extent where we've specified our variables definitions and instantiated the email body with a simple message.

import smtplib, ssl  
from email.mime.base import MIMEBase  
from email.mime.multipart import MIMEMultipart  
from email.mime.text import MIMEText  
from email import encoders  
smtp_server = 'smtp.gmail.com'  
port = 465  
sender = 'from@someemail.com'  
password = 'myPassword'  
receiver = 'sendingto@somemail.com'  
  
file_name = 'uploadThis.jpg'  
message = MIMEMultipart('alternative')  
message['Subject'] = 'Sending File'  
message['From'] = sender  
message['To'] = receiver  
message.attach(MIMEText('Sending an attachment', 'plain'))

Now let's open the file, encode it, and add a header.

with open(file_name, 'rb') as attachment:  
file_part = MIMEBase('application', 'octet-stream')  
file_part.set_payload(attachment.read())  
  
encoders.encode_base64(file_part)  
file_part.add_header(  
'Content-Disposition',  
  
'attachment; filename='+ str(file_name)  
)

The attach method can be use to attach the attachment to our email:

message.attach(file_part)

Now we're ready to send the email!

context = ssl.create_default_context()  
with smtplib.SMTP_SSL(smtp_server, port, context=context) as server:  
server.login(sender, password)  
server.sendmail(sender, receiver, message.as_string())

Sending Multiple Emails

Sending multiple emails is another important real-world problem.

If you know how to import a text file (preferably a CSV), you can loop through it to gather email addresses and use the principles from this tutorial to send multiple emails with Python.

Let's see this principle in action. For this tutorial, we will send a simple email with a personalized greeting that says "Hi Name”.

First, create a CSV file with emails and any other content you want to add to the email. You can use MS Excel or any other spreadsheet software to do this. Open your spreadsheet software, create a table with two columns 'Name’, and ‘Email' and save it as a CSV.

This is how it will look like in a text editor:

name,email

John,[john@example.com](mailto:johnsmith@example.com)

Sherlock,[sherlock@example.com](mailto:sherlock@example.com)

Dave,[dave@example.com](mailto:dave@example.com)

Next you'll want to write all the common components of your code:

import smtplib, ssl  
import csv  
smtp_server = 'smtp.gmail.com'  
port = 465  
sender = 'from@someemail.com'  
password = 'myPassword'  
  
context = ssl.create_default_context()

Now you'll want to loop through the CSV and read the names and emails.

with open('myemails.csv') as f:  
 reader = csv.reader(f)  
 next(reader)  

for row in reader:

Within the loop, add the logic to actually send the emails:

with open('myemails.csv') as f:  
 reader = csv.reader(f)  
 next(reader)  
  
for row in reader:  
 message = 'Hi ' + row[0]  
 with smtplib.SMTP_SSL(smtp_server, port, context=context) as server:  
  server.login(sender, password)  
  server.sendmail(sender, row[1], message)

Here the full code.

import smtplib, ssl  
import csv  
smtp_server = 'smtp.gmail.com'  
port = 465  
sender = 'from@someemail.com'  
password = 'myPassword'  
context = ssl.create_default_context()  
with smtplib.SMTP_SSL(smtp_server, port, context=context) as server:  
 with open('myemails.csv') as f:  
  reader = csv.reader(f)  
  next(reader)  
 for row in reader:  
  message = 'Hi ' + row[0]  
  server.login(sender, password)  
  server.sendmail(sender, row[1], message)

Other Email Libraries

There are many other libraries that make is easy to send emails with Python. You've already learned about one of them. Here are a few others:

Bulk Emails

Bulk email services can be used to send a massive amount of emails for different purposes like marketing and promotional tasks. There are many bulk email service providers. Although they are not free, some of them offer trial versions without you having to purchase their complete service.

Here are a few bulk email providers along with the usage that is available on their free plan:

Final Thoughts

Python is a great way to automate email sending tasks or even sending automatically generated emails to customers.

The standard library required to send an email is smtplib, but there are many other libraries that allow additional styling, adding images, and adding attachments. Emails you send through Python can be transmitted through protocols like SSL and TLS ensuring that your email's content is encrypted.

Disclaimer: This article is purely for educational purposes. If anyone uses it with malicious intent (spamming), I am not be liable for any losses or damages in connection with the use of this tutorial. Please use this information for good!

If you enjoyed this article, be sure to join my Developer Monthly newsletter, where I send out the latest news from the world of Python and JavaScript:


Written on July 2nd, 2020