Send emails with Python and Gmail
Hi Everyone!. In this post, I want to share with you a little guide that will show you how to send emails using Python and Gmail.
Requirements
- Python (I use Python 3.8.2)
- Pip (I use Pip 20.1.1)
Setup Project
To create our project we are going to use virtualenv, to create an isolated python environment for this project. However, you can also use pyenv or venv.
So, first, we have to install venv
.
pip3 install virtualenv
Now, we have to create the project folder and set up the virtualenv.
# Creating a project folder
mkdir emails-example
cd emails-example
# Creating the virtual environment
virtualenv env
# Activate the virtual environment
source env/bin/activate
# Create our main file
touch main.py
NOTE: To exit the environment you just have to write deactivate
.
Setup dotenv
Before starting to write code, we need to install the package python-dotenv
, to manage environment variables, where we will put our Gmail credentials. We’ll use .env
files to easily configure the project and to avoid sharing sensitive info in our code.
pip install -U python-dotenv
Ok, now we should test if we can use the package. Create a file called .env
.
touch .env
Create a test variable in our .env
file.
TEST="my test variable"
Import the dotenv
package and load the variables.
# main.py
# Import section ....
import os
from dotenv import load_dotenv
# Loading ENV variables
load_dotenv()
# Obtain our TEST variable
print(os.getenv('TEST'))
Run the script.
python main.py
# my test variable
Send basic emails
NOTE: Before start writing code, you have to allow external apps in your Gmail account.
First, we must import the python smtplib client, which will help us to send our emails.
# main.py
# Import section ....
from smtplib import SMTP, SMTPException # Import SMTP module
# ....
We will create some environment variables that we need to configure our SMTP client.
# .env
SENDER="YOUR GMAIL EMAIL"
PASSWORD="YOUR GMAIL PASSWORD"
RECEIVERS="A LIST OF EMAILS TO SEND THE MESSAGE, SEPARATED USING ','"
HOST="smtp.gmail.com"
PORT="587"
Now, we can set some constants using the environment variables defined before.
# main.py
# Constants section ....
# GMAIL account sender
SENDER = os.getenv('SENDER')
PASSWORD = os.getenv('PASSWORD')
# Accounts receivers
RECEIVERS = os.getenv('RECEIVERS').split(',')
# SMTP server options
HOST = os.getenv('HOST')
PORT = os.getenv('PORT')
# ....
# SMTP object
SMTP_OBJECT = SMTP(host=HOST, port=PORT)
Ok, We will create a base function to reuse in the other functions and avoid code duplication.
# main.py
# Methods section ....
# Base function
def send_email(message=""):
"""
Send an email using the credentials defined before
Parameters
----------
message : str
content to send in the message
"""
try:
SMTP_OBJECT.ehlo()
SMTP_OBJECT.starttls()
SMTP_OBJECT.login(SENDER, PASSWORD)
SMTP_OBJECT.sendmail(SENDER, RECEIVERS, message)
SMTP_OBJECT.quit()
print("Successfully sent email")
except SMTPException:
print ("Error: unable to send email")
- ehlo() Open a transmision using the command
EHLO
. Usually this method is called automatically when use sendmail() function. We also can use the function ehlo_or_helo_if_needed() for this purpose. - starttls() Uses the TLS protocol in the connection.
- login() Login on the SMTP server.
- sendmail() Sends our email.
- quit() Terminate the session and close the connection.
Once we have the base function we can create our basic_mail
function.
# main.py
# Methods section ....
def basic_email(message = ""):
"""
Basic email with plain text message
"""
send_email(message)
Our main
function will be the following.
# main.py
# Import section ....
import sys
# Main section ...
if __name__ == "__main__":
# Message to send
message = """
this message is sent from python for testing purposes
"""
if len(sys.argv)> 1 :
if sys.argv[1] == '--help':
print('Info: ')
print('--help List the options to send an email')
print('--basic Sends a plain text email')
print('--txt Send an email from a text file content')
print('--attach Send an email with an attachment')
elif sys.argv[1] == '--basic':
print("Sending a plain text email")
basic_email(message)
else:
print("Please give the type of message to send.")
print("For help execute `python main.py --help`")
We can test our function by executing the following command in our terminal.
python main.py --basic
# Sending a plain text email
# Successfully sent email
Send email from TXT file
Here, we will send a message from a .txt
file. First, we have to import some useful functions.
# main.py
# Import section ....
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
import email.encoders
- MIMEBase This is the base class for all the MIME-specific subclasses.
- MIMEMultipart To send messages divided in multiple messages. Usually used for attachments.
- MIMEText To work with plain files files.
Now, We can create our function to send emails attaching a text file.
# main.py
# Methods section ....
def send_from_txt():
"""
Send an email reading the content message from a txt file
"""
message = MIMEMultipart('alternative')
message['Subject'] = 'TXT file content'
message['From'] = SENDER
body = "Email message body"
content = MIMEText(body, 'plain')
message.attach(content)
# process text file
file_open = open('text.txt', 'rb')
file_content = MIMEText(_text=file_open.read(), _charset='utf-8')
file_open.close()
message.attach(file_content)
# Send email
send_email(message.as_string())
Add the option to our main function.
# main.py
# Main section ...
if __name__ == "__main__":
# ....
if len(sys.argv)> 1 :
# if ....
elif sys.argv[1] == '--txt':
print("Sending an email from a text file content")
send_from_txt()
else:
# ....
Create a .txt
file with a message.
# Creating file
touch text.txt
# Edit the file
nano text.txt
# Put the following message
Message from a TXT file
We can test our function by executing the following command in our terminal.
python main.py --txt
# Sending an email from a text file content
# Successfully sent email
Attaching files
Finally, we will send an email with a PDF attachment.
# main.py
# Methods section ....
def send_attachment():
"""
Send an email with an attachment
"""
message = MIMEMultipart('alternative')
message['Subject'] = 'Attachment'
message['From'] = SENDER
attachment = MIMEBase('application', 'octet-stream')
attachment.set_payload(open('file.pdf', 'rb').read())
attachment.add_header('Content-Disposition', 'attachment; filename="file.pdf"')
email.encoders.encode_base64(attachment)
message.attach(attachment)
# Send email
send_email(message.as_string())
Add the option to our main function.
# main.py
# Main section ...
if __name__ == "__main__":
# ....
if len(sys.argv)> 1 :
# if ....
elif sys.argv[1] == '--attach':
print("Sending an email with an attachment")
send_attachment()
else:
# ....
We can test our function by executing the following command in our terminal.
python main.py --attach
# Sending an email with an attachment
# Successfully sent email
NOTE: To test this method we have to put in our project folder a file called file.pdf
.
Final Words
Thanks for reading this post and don’t forget to turn off the Less secure app access configuration.
You can find the code of this guide here.