Did you know you can send emails using Python? Not only that, you can send files attached too!
And instead of using the black-text-white-background plain text most people use, you can send your emails as HTML files, to add some flavour to your emails, like this one:
In just a few minutes, you will learn how to create an SMTP server to send emails using Python to a list of clients, students, friends…
In this lesson you’ll learn how to:
- Send one email to one person
- Add information such as your name, the receiver name or a subject to make it more human-like
- Send one email to multiple people
- Make a beautiful email using HTML
- Attach files to the emails we sent
Setting up everything
We are going to send emails using a Gmail account. Before anything, create a gmail account (or use your own) and enable the “Less secure app access” in your account. You can do it here: https://myaccount.google.com/u/0/security?hl=en&pli=1
After that, you are set! Create an environment with Python (I use pipenv, so pipenv shell) and you are ready to go!
Simple, one to one email sender
Let’s start by creating a simple script that sends one text email to other people from your account (I use
Create a python file, for example email_server.py, and write:
import smtplib, ssl # User configuration sender_email = YOUR_EMAIL receiver_email = RECEIVER_EMAIL password = input('Please, type your password:\n') # Email text email_body = ''' This is a test email sent by Python. Isn't that cool? '''
smtp is a Python module we will use to create an SMTP (Simple Mail Transfer Protocol) session object that will send any email we want. ssl module provides access to TLS (Transport Layer Security) to help us making it more secure.
Then, we’ll add some variables such as the sender and receiver email, a prompt to the user to enter the email password and a body to the email. Replace the values in uppercase with yours. For testing purposes, I use the same email.
After having our configuration, let’s write the function that will send the emails:
print("Sending the email...") try: # Creating a SMTP session | use 587 with TLS, 465 SSL and 25 server = smtplib.SMTP('smtp.gmail.com', 587) # Encrypts the email context = ssl.create_default_context() server.starttls(context=context) # We log in into our Google account server.login(sender_email, password) # Sending email from sender, to receiver with the email body server.sendmail(sender_email, receiver_email, email_body) print('Email sent!') except Exception as e: print(f'Oh no! Something bad happened!\n {e}') finally: print('Closing the server...') server.quit()
This function will:
- Create a
smtplib .SMTP instance. We usegmail so we send it using the host smtp.gmail.com and the port 587. You can use other providers (such ashotmail ) by using their host and port. - Encrypt the email using the
starttl s method. - Log into our Google email account
- Send the email using the sender email, to the receiver email, and the message is just a plain text.
- Use a try, except to catch all the errors and
finallyi close the SMTP instance.
Run the code now and you’ll receive your email!
But we are not here to send just an email. We can do that ourselves!
Let’s send now multiple emails to a list.
Sending emails to a list of people
To send multiple emails, we only need to perform a few tweaks here and there. Let’s also make our emails more personal adding a subject to the email and information about the sender:
First, let’s write more human-like emails:
import smtplib, ssl from email.mime.text import MIMEText # New line from email.utils import formataddr # New line # User configuration sender_email = YOUR_EMAIL sender_name = YOUR NAME # New line password = input('Please, type your password:\n') receiver_email = RECEIVER_EMAIL receiver_name = RECEIVER_NAME # New line
Add the lines with the ‘# New line’ comment. We are importing the MIMEText( Multi-Purpose Internet Mail Extensions ) to configure our emails and a
After the first print but before the try, add this configuration:
# Configurating user's info msg = MIMEText(email_body, 'plain') msg['To'] = formataddr((receiver_name, receiver_email)) msg['From'] = formataddr((sender_name, sender_email)) msg['Subject'] = 'Hello, my friend ' + receiver_name
Now, we create a MIMEText instance with email_body as plain text, we set our ‘To’ text to the receiver name and email, the ‘From’ text to our name and email and the subject to ‘Hello, my friend NAME’.
Finally, modify the sender.sendmail method to:
server.sendmail(sender_email, receiver_email, msg.as_string())
Send the email again:
Nice, now has less spammy vibes. Let’s send that 100% normal, not-fake, email to a list of people:
# receiver_email = RECEIVER_EMAIL # receiver_name = RECEIVER_NAME receiver_emails = [RECEIVER_EMAIL_1, RECEIVER_EMAIL_2, RECEIVER_EMAIL_3] receiver_names = [RECEIVER_NAME_1, RECEIVER_NAME_2, RECEIVER_NAME_3]
As we are going to iterate over the receiver emails and names, precede the code bellow the receiver_names variable with this for-loop and tab the code so it belongs to the loop:
for receiver_email, receiver_name in zip(receiver_emails, receiver_names): print("Sending the email...") # Configurating user's info msg = MIMEText(email_body, 'plain') ...
This should be your code right now:
import smtplib import ssl from email.mime.text import MIMEText # New line from email.utils import formataddr # New line # User configuration sender_email = YOUR_EMAIL sender_name = YOUR NAME password = input('Please, type your password:\n') receiver_emails = [RECEIVER_EMAIL_1, RECEIVER_EMAIL_2, RECEIVER_EMAIL_3] receiver_names = [RECEIVER_NAME_1, RECEIVER_NAME_2, RECEIVER_NAME_3] # Email text email_body = ''' This is a test email sent by Python. Isn't that cool? ''' for receiver_email, receiver_name in zip(receiver_emails, receiver_names): print("Sending the email...") # Configurating user's info msg = MIMEText(email_body, 'plain') msg['To'] = formataddr((receiver_name, receiver_email)) msg['From'] = formataddr((sender_name, sender_email)) msg['Subject'] = 'Hello, my friend ' + receiver_name try: # Creating a SMTP session | use 587 with TLS, 465 SSL and 25 server = smtplib.SMTP('smtp.gmail.com', 587) # Encrypts the email context = ssl.create_default_context() server.starttls(context=context) # We log in into our Google account server.login(sender_email, password) # Sending email from sender, to receiver with the email body server.sendmail(sender_email, receiver_email, msg.as_string()) print('Email sent!') except Exception as e: print(f'Oh no! Something bad happened!\n {e}') finally: print('Closing the server...') server.quit()
Run the code and your email will be send to 3 different email address!
Here we are sending an email to 3 different people, but you can send it to hundreds of your students, followers, blog readers, etc! And…
…they will get an ugly email.
I promised you sending beautiful emails with Python that can draw people to whatever you want. So let’s go!
Sending beautiful emails with HTML
It’s pretty simple. Now we are sending a string as a email_body, right?
Instead of that, we are going to send a string that contains HTML code.
First, let’s create our HTML file. Use a code editor such as VS Code or Atom, or create it with an online editor such as https://html5-editor.net/.
Save it into an HTML file (mine is email.html).
Now, place email_body with this:
# Email body email_html = open('email.html') email_body = email_html.read()
Replace the old line with the new one:
# msg = MIMEText(email_body, 'plain') # Old line msg = MIMEText(email_body, 'html') # New line
Run the code and this is the result:
Pretty cool, right?
But what if we want to send also invoices, pdfs, excel files, videos, or some other file?
Add files to your emails – The mandatory cat.gif example
To add files, instead of sending one object, the HTML, we are going to send multiple parts. One being the HTML, other the gif. To do so, add this:
import smtplib, ssl from email.mime.text import MIMEText from email.utils import formataddr from email.mime.multipart import MIMEMultipart # New line from email.mime.base import MIMEBase # New line from email import encoders # New line .... # Email body email_html = open('email.html') email_body = email_html.read() filename = 'cat.gif' # New line
Remember to add a file called ‘cat.gif’ to the folder or replace it with one of your own.
Replace the msg = MIMEText(email_body, ‘html’) creation with this:
msg = MIMEMultipart() msg['To'] = formataddr((receiver_name, receiver_email)) msg['From'] = formataddr((sender_name, sender_email)) msg['Subject'] = 'Hello, my friend ' + receiver_name msg.attach(MIMEText(email_body, 'html'))
This will create the first part of the body, the one with the HTML, now let’s add the attachment:
try: # Open PDF file in binary mode with open(filename, "rb") as attachment: part = MIMEBase("application", "octet-stream") part.set_payload(attachment.read()) # Encode file in ASCII characters to send by email encoders.encode_base64(part) # Add header as key/value pair to attachment part part.add_header( "Content-Disposition", f"attachment; filename= {filename}", ) msg.attach(part) except Exception as e: print(f'Oh no! We didn\'t found the attachment!\n{e}')
This will:
- Load the file attached
- Encode it
- Add it to the header as attachment
- Add the part to the MIMEMultipart
- Throw and error if the file isn’t found.
Check your code with mine:
import smtplib import ssl from email.mime.text import MIMEText from email.utils import formataddr from email.mime.multipart import MIMEMultipart # New line from email.mime.base import MIMEBase # New line from email import encoders # New line # User configuration sender_email = YOUR_EMAIL sender_name = YOUR_NAME password = input('Please, type your password:\n') receiver_emails = [RECEIVER_EMAIL_1, RECEIVER_EMAIL_2, RECEIVER_EMAIL_3] receiver_names = [RECEIVER_NAME_1, RECEIVER_NAME_2, RECEIVER_NAME_3] # Email body email_html = open('email.html') email_body = email_html.read() filename = 'cat.gif' for receiver_email, receiver_name in zip(receiver_emails, receiver_names): print("Sending the email...") # Configurating user's info msg = MIMEMultipart() msg['To'] = formataddr((receiver_name, receiver_email)) msg['From'] = formataddr((sender_name, sender_email)) msg['Subject'] = 'Hello, my friend ' + receiver_name msg.attach(MIMEText(email_body, 'html')) try: # Open PDF file in binary mode with open(filename, "rb") as attachment: part = MIMEBase("application", "octet-stream") part.set_payload(attachment.read()) # Encode file in ASCII characters to send by email encoders.encode_base64(part) # Add header as key/value pair to attachment part part.add_header( "Content-Disposition", f"attachment; filename= {filename}", ) msg.attach(part) except Exception as e: print(f'Oh no! We didn\'t found the attachment!\n{e}') break try: # Creating a SMTP session | use 587 with TLS, 465 SSL and 25 server = smtplib.SMTP('smtp.gmail.com', 587) # Encrypts the email context = ssl.create_default_context() server.starttls(context=context) # We log in into our Google account server.login(sender_email, password) # Sending email from sender, to receiver with the email body server.sendmail(sender_email, receiver_email, msg.as_string()) print('Email sent!') except Exception as e: print(f'Oh no! Something bad happened!\n{e}') break finally: print('Closing the server...') server.quit()
Run the code… and now the attachment is in the email!
Conclusion
Writing code that lets you send an email to your email list, with attachment files and way more attractive than the boring plain black-text-white-background formula, is easy.
While this is a one-file script, you can easily incorporate it to an actual Python framework (Flask, Django….) web app, another program you are actually using or improve the current one to perform more functions.
Creating and sending emails never has been so easy with Python!