Sending Emails with Python and receiving your messages29 May 2024 / 20 minutes to read Elena Daehnhardt |
If you click an affiliate link and subsequently make a purchase, I will earn a small commission at no additional cost (you pay nothing extra). This is important for promoting tools I like and supporting my blogging.
I thoroughly check the affiliated products' functionality and use them myself to ensure high-quality content for my readers. Thank you very much for motivating me to write.
Introduction
In this post, I will describe two main email methods using Google and Python. You won’t need to use third-party applications. I use some of these code blocks to send my subscription emails.
I will also share my setup for effortlessly getting your emails on this GitHub static website. This method is efficient, cost-effective, and easily adaptable to my needs.
Getting your messages
As you may know from my post AI-Free Website Design, this blog is hosted on GitHub, and it is a static website. Thus, I can only easily send forms with third-party solutions.
To facilitate form submissions on my static website, I use UseBasin.com for years, and I have just started my affiliation with them.
All you have to do is to generate your HTML form on UseBasin.com website and copy/paste your code into your website. It’s that easy. If you know a bit of HTML, you can customise your forms.
Indeed, you can use other solutions, but I am pleased with UseBasin.com because of its simplicity, quite-well developed spam filters, and, indeed, their integration and messages export features.
So, I got your subscription email list in CSV format and stored it in my mailer directory. Now, I can proceed with sending the emails!
Sending email messages
We will cover the necessary steps, including setting up your Gmail account, using Python’s smtplib
module, and configuring all the essential security settings in Gmail.
Prerequisites
Before we start, ensure you have the following:
- Python installed on your system. Download it from the official website.
- Gmail Account to utilise Google’s SMTP server.
Security Settings
We can now use the Less Secure App Access and Enhanced Security (OAuth2.0).
The main difference between Enhanced Security (OAuth2.0) and Less Secure App Access for sending emails with Python via Gmail boils down to authentication method and security implications:
- Enhanced Security (OAuth2.0) provides robust security features and granular control. Your application doesn’t directly expose your Gmail password, significantly reducing the risk of unauthorised access or hacking. To begin with, you create credentials (client ID and secret) through the Google Cloud Platform. Your application will request an access token from Google using these credentials. Google verifies your identity and grants a temporary access token specific to your application and intended actions (e.g., emails). Next, your application uses the access token to authenticate with Gmail’s API and send emails securely.
- Less Secure App Access is a less secure option and should be avoided in production environments or when security is a priority. Opt for this only for testing purposes or if your application cannot use OAuth2.0. Your application directly enters your Gmail username and password to connect to Gmail’s SMTP server while having full access to your Gmail account based on the credentials you provided.
Please note that after September 30, 2024, you must use Enhanced Security when using Google Workspace. Read more in Google Workspace Updates.
Google is removing the IMAP enable/disable toggle from the personal Gmail settings in the coming weeks. IMAP access will always be enabled over OAuth, and your current connections won’t be affected. No action is needed from your end Google Workspace Updates
Suppose you are curious about the security of using Python’s e-mail libraries. In that case, I suggest reading the comprehensive article Nothing new, still broken, insecure by default since then: Python’s e-mail libraries and certificate verification.
Email parameters and messages
Firstly, we set up the email credentials, recipient, subject, and body.
MAIL_USERNAME = 'your_email@gmail.com' # your_email
password = 'your_password' # is not required for the OAuth2 method
to_email = 'your_email@gmail.com'
subject = 'Test Email'
body = 'This is a test email sent from Python.'
The email.mime
library creates email content in a structured format, allowing for more complex email structures, such as attachments and HTML content.
We use MIMEMultipart
to create a message container and attach the email body using MIMEText
.
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
message = MIMEMultipart()
message['From'] = MAIL_USERNAME
message['To'] = to_email
message['Subject'] = subject
message.attach(MIMEText(body, 'plain'))
Here is the message. ' attach(MIMEText(body, 'plain'))
, which attaches the body of the email as plain text. However, it is quite desirable to send emails in HTML format.
You can further improve the HTML string with inline CSS that can enable a better design, dark/light mode, images and fonts you prefer,
html_string = f"<html><body style='background: black; color: white;'>{body}</body></html>"
body_html = MIMEText(html_string, "html")
message.attach(body_html)
The email client will try to render the last attached (HTML) part first; it will snow the plain text when it fails.
Less Secure App Access
Setting Up Your Gmail Account
To send emails through Gmail’s SMTP server, enable “Less secure app access” in your Gmail account settings. This allows third-party apps to access your account.
To enable “Less Secure Apps” for your Gmail account, you’ll need to disable “Two-Step Verification” first if it is disabled.
To turn on the “Less secure app access”, go to Google Account Security Settings.
Import Necessary Libraries
We import smtplib
for sending emails using the Simple Mail Transfer Protocol (SMTP), ssl
for creating a secure SSL context, MIMEText
and MIMEMultipart
from email.mime.text
and email.mime.multipart
respectively, for creating the email content.
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import ssl
SSL is a security protocol that encrypts communication between a web server and a browser or client, protecting sensitive information such as login credentials and credit card details from unauthorised interception.
Send the Email
Finally, we establish a secure connection with Gmail’s SMTP server using SMTP_SSL
, log in, and send the email.
# Create a secure SSL context
context = ssl.create_default_context()
# Send the email using SMTP over SSL
with smtplib.SMTP_SSL("smtp.gmail.com", 465, context=context) as server:
# Log in to the SMTP server
server.login(MAIL_USERNAME, password)
# Send the email
server.sendmail(MAIL_USERNAME, to_email, message.as_string())
We create a secure SSL context to secure the connection to the SMTP server with ssl.create_default_context(). The SSL context ensures that the connection to the SMTP server is secure, protecting your login credentials and email content from being intercepted.
This function uses SMTP over SSL with smtplib.SMTP_SSL(“smtp.gmail.com”, 465, context=context) is used as the server, maintaining a connection to the Gmail SMTP server on port 465.
The function server.login(MAIL_USERNAME, password)
logs us into the SMTP server using your Gmail address and password.
Finally, server.sendmail(MAIL_USERNAME, to_email, message.as_string())
sends the email from your Gmail address to the recipient’s email address using the created email message.
Please notice that if you have two-factor authentication enabled on your Google account, you’ll need to generate an app-specific password instead of using your regular Gmail password.
The test e-mail went well for me. Let’s go further with OAuth2 usage.
Using OAuth2.0 for secure authentication
OAuth2.0 enhances security by avoiding the need to store and manage passwords.
Prerequisites
When we explored the Less Secure App Access, we already mentioned the required G-mail account, Python installation, and the smtplib
library (included with Python).
For this more secure OAuth2.0-based setup, we have to install the oauth2client
and google-auth
libraries:
pip install google-auth google-auth-oauthlib google-auth-httplib2
Setting Up Your Gmail Account
To send emails through Gmail’s SMTP server using OAuth2.0, follow these steps:
- Create a Project in Google Cloud Console:
- Go to the Google Cloud Console.
- Create a new project.
- Enable the Gmail API for your project.
- Create OAuth2.0 Credentials:
- Go to the “Credentials” page.
- Create OAuth 2.0 Client IDs and download the
.json
credentials file.
Please note that you might need to fill out the OAuth consent screen when you do not have an organisation set up. In that form, you can fill out your app name, user support email, developer contact information, and other relevant fields.
You can choose any permission level that fits your app requirements in the scope screen. For sending e-mails, I have enabled the following:
- Gmail API …/auth/gmail.send Send email on your behalf
You can add more scope elements as needed in your application.
Next, we will have to create an OAuth client ID. I have selected a Desktop app with the name “My blog mailer”. As a result, you will get the message window “OAuth client created
The client ID and secret can always be accessed from Credentials in APIs & Services, where we download our JSON credentials for further use. I have renamed it “client_secret_for_my_blog_mailer.json.”
Import Necessary Libraries
We import necessary libraries, os
for checking the existence of the token file, Request
from google.auth.transport.requests
to refresh credentials, Credentials
from google.oauth2.credentials
to handle the credentials,InstalledAppFlow
from google_auth_oauthlib.flow
to manage the OAuth2 flow.
import os
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
For sending emails, we will use base64
to encode the message in a format suitable for the Gmail API, build
from googleapiclient.discovery
to build the Gmail API service, and HTTPError
from requests
to handle potential HTTP errors during the API request.
import base64
from googleapiclient.discovery import build
from requests import HTTPError
Define OAuth2.0 Scope and Token File
Set the Gmail API scope and specify paths for the token file TOKEN_FILE
and credentials files CREDENTIALS_FILE
(usually downloaded from the Google Cloud Console)
Scopes required for accessing the Gmail API. In this case, the scope is set to allow sending emails.
SCOPES = ['https://www.googleapis.com/auth/gmail.send']
TOKEN_FILE = 'token.json'
CREDENTIALS_FILE = 'client_secret_for_my_blog_mailer.json'
Please note that we still need the ‘token.json’ file; we will get it soon.
Function to Get OAuth2.0 Credentials
The function get_oauth2_credentials()
handles the OAuth2.0 flow, storing and refreshing tokens as needed.
def get_oauth2_credentials():
"""
Retrieves OAuth2 credentials for accessing the Gmail API.
This function checks if valid credentials are available locally. If not,
it initiates the OAuth2 flow to obtain new credentials and saves them for
future use.
Returns:
Credentials: OAuth2 credentials for the Gmail API.
"""
creds = None
# Check if the token file exists
if os.path.exists(TOKEN_FILE):
# Load the credentials from the token file
creds = Credentials.from_authorized_user_file(TOKEN_FILE, SCOPES)
# If no valid credentials are available, initiate the OAuth2 flow
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
# Refresh the credentials if they are expired
creds.refresh(Request())
else:
# If no valid credentials are found, initiate the OAuth2 flow
flow = InstalledAppFlow.from_client_secrets_file(CREDENTIALS_FILE, SCOPES)
creds = flow.run_local_server(port=0)
# Save the new credentials to the token file for future use
with open(TOKEN_FILE, 'w') as token:
token.write(creds.to_json())
return creds
If the token file exists, we load the credentials from the file. Otherwise, we initiate the OAuth2 flow. We also refresh the credentials using the refresh token. The newly refreshed token is saved into the file ‘TOKEN_FILE’ for future usage.
When calling the function above, your default web browser window will open and request email access. When you select your Gmail account, you will get a message: “The authentication flow has completed. You may close this window.”
Send the Email
We can next use these credentials in the function send_email_with_oauth2(). The service = build('gmail', 'v1', credentials=creds)
uses the retrieved credentials to build the Gmail API service for version 1 of the API.
def send_email_with_oauth2():
"""
Sends an email using the Gmail API with OAuth2 authentication.
This function retrieves OAuth2 credentials, builds the Gmail API service,
creates a raw email message, and sends it using the Gmail API.
"""
# Retrieve OAuth2 credentials
creds = get_oauth2_credentials()
# Build the Gmail API service
service = build('gmail', 'v1', credentials=creds)
# Create the raw message object
# The 'message' variable should be defined with the email content
raw_message = {'raw': base64.urlsafe_b64encode(message.as_bytes()).decode()}
try:
# Send the email message
sent_message = service.users().messages().send(userId="me", body=raw_message).execute()
print(f'Message {sent_message} was sent')
except HTTPError as error:
# Handle HTTP errors
print(f'Error: {error}')
sent_message = None
send_email_with_oauth2()
We use base64 for creating the raw email message raw_message = {'raw': base64.urlsafe_b64encode(message.as_bytes()).decode()}
, which encodes the email message in base64 format. The message
variable is an instance of an email message object (e.g., email.mime.text.MIMEText
defined before.
Finally, we send the email in the try block using the Gmail API. When catching the HTTPError
exceptions, we print an error message and set’ sent_message to
None`.
The e-mail was sent well again :)
This approach ensures that the function is self-contained, easy to understand, and handles potential errors gracefully.
Using OAuth2.0 to send emails with Python and Gmail provides a secure way to handle authentication, avoiding the need to manage passwords directly.
For more details, refer to the official Python documentation on smtplib and the Gmail API Overview.
Conclusion
In this post, I have shared the main ideas behind my email messaging setup, how I get your subscription and contact requests with UseBasin.com, and how I send my emails to you with Python and Gmail.
Sending emails using Python with Gmail is straightforward with the smtplib
library. Now, you can automate email sending for various applications, from notifications to bulk email campaigns. We have covered Gmail’s SMTP server with Python’s smtplib
, set up with a simple, less secure password-based method, and a method utilising OAuth2.0 for secure authentication.
Now, you can also start your email pet project and send emails using Python. All the best!
Try the following fantastic AI-powered applications.
I am affiliated with some of them (to support my blogging at no cost to you). I have also tried these apps myself, and I liked them.
B12.io Recently, I have found an AI-powered platform that enables you to create professional websites, pages, posts, and emails with ease. I will also give it a try and soon write a new post about B12.io (I am working on my coding post at the moment :).
UseBasin.com is a comprehensive backend automation platform for handling submissions, processing, filtering, and routing without coding.
Mixo.io generates websites instantly using AI. Builds stunning landing pages without any code or design. Includes a built-in email waiting list and all the tools you need to launch, grow, and test your ideas.
10web.io builds a website with AI. You can also host your wesbite on 10Web Hosting, and optimise it with PageSpeed Booster.
Did you like this post? Please let me know if you have any comments or suggestions.
Python posts that might be interesting for youReferences
5. Google Account Security Settings
About Elena Elena, a PhD in Computer Science, simplifies AI concepts and helps you use machine learning.
|