In this guide, I will be showing you how to create an application that can be used to send email to one or more recipients, which can also be utilized as a basic Newsletter sender for pre-approved email addresses.
Although sending email in Python can be done in just a few lines of code, I extended this application to be more flexible and customizable. We will be storing all of our recipients in a CSV file and creating a text file to use as an email template.
Our Requirements
Luckily, everything that we need to build this application is already a part of Python, so we won't need to install anything new into our environment. We will just need to include a few modules to make it work (CSV, SMTPLib, SSL, sys, time, email.mime.multipart, and email.mime.text).
Let’s Get Started
This project will consist of 3 files to help keep the application flexible and easy to use.
Create a project directory that will contain the following 3 files.
- email_addresses.csv
- email_template.txt
- send_email.py
Your project directory should look similar to this:
Your Project Directory
|___ email_addresses.csv
|___ email_template.txt
|___ send_email.py
Create a file called email_addresses.csv and on each line insert a recipient with the name and email address separated by a comma:John Doe,johndoe@example.com
Jane Doe,janedoe@example.com
Mark Doe,markdoe@example.com
Steve Doe,stevedoe@example.com
Billy Doe,billydoe@example.com
Now create a file called email_template.txt and insert the following example data into it:From: YOUR-EMAIL-ADDRESS
Subject: This is a Test Email
Dear {NAME},
This is a test email message.
Best Regards,
Nerd Behind the Keyboard
Within the above file, change YOUR-EMAIL-ADDRESS to the email address that you want your emails to be sent from. Change the subject to whatever subject that you would like to use for your outgoing emails. The rest of the data is a part of the email's body. I have included a name token {NAME} in the body of the email. This token will be replaced with the name of the recipient from the email_addresses.csv file during iteration.
Let's create our last file called send_email.py and insert the following code into it:
#!/usr/bin/python3 # Import modules that are required to run this application import csv import smtplib import ssl import sys import time # Import the email.mime subclasses from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText def get_email_template(): """ Loads the email template into memory and gathers information to be processed and returns it as a list. """ # Open and read the Email Template into memory. with open("email_template.txt", 'r') as f: # Store each line into a list called 'lines'. lines = f.readlines() # Create a variable to store each line of the body. msg_body = "" # Iterate through each line in the list and count the current # iteration. for count, line in enumerate(lines): if count == 0: # If the current iteration is 0, or the first line in the # file, grab the 'from' email address and remove the word # 'From:' so that it isn't included in the string. msg_from = line.replace("From:", "") elif count == 1: # If the current iteration is 1, or the second line in the # file, grab the 'subject' and remove the word 'Subject:' # so that it isn't included in the string. msg_subject = line.replace("Subject:", "") else: # Otherwise, treat everything else as the body of the # email message and concatenate it with the 'msg_body' # variable. msg_body += line # Remove any leading and trailing whitespace from each string # variable and return it as a list. return [msg_from.strip(), msg_subject.strip(), msg_body.strip()] def send_email(smtp_host, smtp_port, smtp_user, smtp_pass, mime_type="text"): """ Gather information and process data for sending email to one or more email addresses. """ # Call the 'get_email_template' function to gather information from # the email template. email_template = get_email_template() # Open and read the name and email addresses that are stored in CSV # format within the 'email_addresses.csv' file. with open('email_addresses.csv', 'r') as csvfile: # Create a CSV Reader Object. csvReader = csv.reader(csvfile, delimiter=',') # Iterate through each row of the CSV Reader Object. for row in csvReader: # Store the first field of the CSV row as the name and # remove any leading and trailing whitespace. csv_name = row[0].strip() # Store the second field of the CSV row as the email # address and remove any leading and trailing whitespace. csv_email = row[1].strip() # Create a MIMEMultipart class. msg = MIMEMultipart() # Grab the 'From' email address from the email template. msg['From'] = email_template[0] # Format the 'To' email address from the CSV data. msg['To'] = f"{csv_name} <{csv_email}>" # Grab the 'Subject' from the email template. msg['Subject'] = email_template[1] # Grab the body of the email from the email template and # replace {{NAME}} with the name from the CSV data. tmp_msg_body = email_template[2].replace("{NAME}", csv_name) if mime_type == "html": # If 'HTML' was passed as the 'mime_type', attach the # email body as HTML to allow HTML formatting to be # used within the email. msg.attach(MIMEText(tmp_msg_body, "html")) else: # Otherwise, treat the email body as plain text. msg.attach(MIMEText(tmp_msg_body)) # Create a secure default settings context. context = ssl.create_default_context() # Connect to the Outgoing SMTP Mail server to process the email. with smtplib.SMTP_SSL(smtp_host, smtp_port, context=context) as server: try: # Log in on an SMTP server that requires authentication. server.login(smtp_user, smtp_pass) # Send the email to the current email address in the iteration of # the CSV data. server.sendmail(msg['From'], msg['To'], msg.as_string()) # Print an output to show that the message has been sent. print("Email has been sent to", msg['To']) except smtplib.SMTPAuthenticationError as e: # Either the login information was incorrect for the SMTP server # or if you are using Google, you may need to allow Less Secure # Apps access to log into your account. # Visit: https://myaccount.google.com/lesssecureapps print("Unable to authenticate with SMTP Server.") sys.exit(1) # Allow the script to sleep between iterations to help prevent # reaching email sending limits. time.sleep(5) if __name__ == '__main__': # Set the SMTP Mail Server's IP Address or Domain Name. smtp_host = "smtp.gmail.com" # Set the SMTP Mail Server's Port. smtp_port = 465 # Set the Username to authenticate with the SMTP Mail Server. smtp_user = "YOUR-USERNAME@gmail.com" # Set the Password to authenticate with the SMTP Mail Server. smtp_pass = "YOUR-ACCOUNT-PASSWORD" # Set the Mime Type for send a plain text (text) or HTML (html) email. mime_type = "text" # Call the 'send_email' function and pass the SMTP's host, port, # username, password, and mime type. send_email( smtp_host, smtp_port, smtp_user, smtp_pass, mime_type )
In this application, we will be using Gmail as our SMTP server, but you can use any SMTP server that you have access to. In the above code, change the smtp_user and smtp_pass to match your account authentication details for your SMTP server.
Authentication Error
If you use Gmail, you will more than likely receive an authentication error. If your account information is correct and you receive this error, it is the result of not giving Gmail permissions to authenticate from a less secure application. This error can be fixed by turning on access for Less Secure Apps.
Conclusion
Although this is a very basic email sending application that be used to send both text and HTML formatted emails, you can further improve on it by allowing file attachments to be included or adding images to its content. The SMTPLib has a lot to offer in its library along with the email and mime handling package. With a little research and playing around, you could create a powerful email sending masterpiece.