How to Send Emails in Python with Gmail

On January 26, 2024
9min read
Denys Kontorskyy Technical Content Writer @Mailtrap
How to send emails in Python with Gmail

In this tutorial, using code examples, we’ll cover how to use different modules in Python to construct and send various types of email messages, review existing authentication methods, and more. As an example, we’ll be using both the Gmail SMTP server and API.

If you’d like to find out about other methods of sending emails in Python, check out our comprehensive guide.

How to send an email with Python via Gmail SMTP?

To send an email with Python via Gmail SMTP, you must use the smtplib module and the email module. The smtplib essentially provides functions for connecting and sending emails using a Simple Mail Transfer Protocol (SMTP) server.

As for the email module, it provides classes for constructing and parsing email messages (To, From, Subject, etc.)  and allows encoding and decoding emails with the MIME (Multipurpose Internet Mail Extensions) standard.

Let’s break down the actual steps that need to be done and take a look at the below code example.

  1. Import the required libraries: smtplib and MIMEText, from the email.
  2. Create the email message using the MIMEText object, and set the desired values in the Subject, Body, Sender, and Recipients, and Password fields.
  3. Establish the SMTP connection to Gmail’s server over a secure SSL connection using the SMTP_SSL function.
  4. Call the sendmail method of the SMTP object, and specify the sender’s and recipient’s email addresses and the email message as arguments.
import smtplib
from email.mime.text import MIMEText

subject = "Email Subject"
body = "This is the body of the text message"
sender = "sender@gmail.com"
recipients = ["recipient1@gmail.com", "recipient2@gmail.com"]
password = "password"


def send_email(subject, body, sender, recipients, password):
    msg = MIMEText(body)
    msg['Subject'] = subject
    msg['From'] = sender
    msg['To'] = ', '.join(recipients)
    with smtplib.SMTP_SSL('smtp.gmail.com', 465) as smtp_server:
       smtp_server.login(sender, password)
       smtp_server.sendmail(sender, recipients, msg.as_string())
    print("Message sent!")


send_email(subject, body, sender, recipients, password)

Prior to May 30, 2022, it was possible to connect to Gmail’s SMTP server using your regular Gmail password if “2-step verification” was activated.

For a higher security standard, Google now requires you to use an “App Password“. This is a 16-digit passcode that is generated in your Google account and allows less secure apps or devices that don’t support 2-step verification to sign in to your Gmail Account.

Alternatively, there is OAuth 2.0 Gmail authentication mode, but in this case, you’ll need to use the Gmail API sending method in your Python script. 

How to send an email with Python via Gmail API?

The Gmail API is a RESTful API that allows your application to send and receive emails using Google’s mail servers. On top of that, it gives you the ability to retrieve and manage messages and use Gmail features such as labels, threads, etc. 

Let’s analyze each step of sending an email with Python via Gmail API using OAuth2 authentication. 

  1. Set up a Google Cloud Platform project, click on the hamburger menu, and select view all products. Under the management section, select APIs and services
  1.  Next, select Library and type “Gmail API” in the search bar, and click on the Gmail API card.
  1. Finally, select the enable the Gmail API button. 
  1. Now, you’ll need to download the client secrets file for your project. Start by selecting create credentials. In this section, select the Gmail API as your preferred API and user data as the type of data you will be accessing.
  1. To get the OAuth client ID, select your application type as a Desktop App, set the application name, and select create. Next, download and store the credentials in your local file system.

After downloading the secret file, you should have the file in this format:

{
    "installed": {
        "client_id": "463220703866-un8ijck75igunsbh4nhclm74edprhj5p.apps.googleusercontent.com",
        "project_id": "geocaching-366015",
        "auth_uri": "https://accounts.google.com/o/oauth2/auth",
        "token_uri": "https://oauth2.googleapis.com/token",
        "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
        "client_secret": "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",
        "redirect_uris": [
            "http://localhost"
        ]
    }
}

Before beginning with the code, you will need to install the google-auth, google-auth-oauthlib, google-auth-httplib2, and google-api-python-client libraries by using the command:

pip install google-auth google-auth-oauthlib google-auth-httplib2 google-api-python-client

After successfully installling the libraries, you will create a variable called SCOPES which will hold a list of strings that specifies the permissions that an app has when it accesses a user’s data.

At this point, create another variable called flow which will use the InstalledAppFlow class to create an OAuth 2.0 flow for an installed app and specifies the OAuth 2.0 scopes that the app needs in the SCOPES variable. The code then starts the OAuth 2.0 flow by calling the run_local_server method and specifying a port number, which starts a local web server to handle the authorization flow and return the OAuth 2.0 credentials when the flow is complete.

Next, build the Gmail service by calling the build function from the googleapiclient.discovery module, passing ‘gmail‘ in the service name and ‘v1‘ version as arguments, and taking the credentials you called earlier.

Now construct the email message by creating a MIMEText object, and setting the ‘to‘ and ‘subject‘ fields to the desired values. Additionally, encode the email message as a base64-encoded string. 

Finally, you can send the email by calling the send method of the messages resource and passing it in the create_message dictionary as the request body.

This is what the Python code looks like when all these steps are put together:

import base64
from email.mime.text import MIMEText
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from requests import HTTPError

SCOPES = [
        "https://www.googleapis.com/auth/gmail.send"
    ]
flow = InstalledAppFlow.from_client_secrets_file('credentials.json', SCOPES)
creds = flow.run_local_server(port=0)

service = build('gmail', 'v1', credentials=creds)
message = MIMEText('This is the body of the email')
message['to'] = 'recipient@gmail.com'
message['subject'] = 'Email Subject'
create_message = {'raw': base64.urlsafe_b64encode(message.as_bytes()).decode()}

try:
    message = (service.users().messages().send(userId="me", body=create_message).execute())
    print(F'sent message to {message} Message Id: {message["id"]}')
except HTTPError as error:
    print(F'An error occurred: {error}')
    message = None

That’s it! Just like that, with a few lines of code, you can add a quick email-sending functionality to the app you’re building, and of course, don’t forget to validate email addresses gathered from your users.

Gmail API limitations

Using the Gmail API is a convenient and reliable option for the automation of your email sending, but it has some limitations.

  • Daily send limit and maximum email size limit 

To ensure a single user or application does not consume too many resources, the API limits the number of emails you can send daily and has a maximum email size limit. For accurate numbers regarding these limitations, check out Google’s documentation.

  • Limited support for features

The API may not support all features available through the Gmail web interface, such as the ability to schedule emails to be sent at a later time or to use certain types of formatting or attachments.

  • OAuth scopes control access to user data 

When you authenticate your application, you must request the appropriate OAuth scopes to access the data you need. The user must then grant your application access to their data. Without the appropriate OAuth scopes, your requests to access user data will be denied and result in an error.

How to send an HTML email?

Just like you would with a regular email message, to send an HTML email using the Gmail SMTP server in Python, use the MIMEText class from the email package. After that, use html_message object instead of the plain text msg object and paste the HTML content into the body of the email.

Here is a full code example:

import smtplib
from email.mime.text import MIMEText

sender_email = "sender@gmail.com"
sender_password = "password"
recipient_email = "recipient@gmail.com"
subject = "Hello from Python"
body = """
<html>
  <body>
    <p>This is an <b>HTML</b> email sent from Python using the Gmail SMTP server.</p>
  </body>
</html>
"""
html_message = MIMEText(body, 'html')
html_message['Subject'] = subject
html_message['From'] = sender_email
html_message['To'] = recipient_email
with smtplib.SMTP_SSL('smtp.gmail.com', 465) as server:
   server.login(sender_email, sender_password)
   server.sendmail(sender_email, recipient_email, html_message.as_string())

If you would like to send an email using an HTML template instead of having the HTML in the body, you can use the Template class from the jinja2 package, a fast, expressive, and extensible templating engine. To install it, run the following line of code:

pip install jinja2

Here is the script for all of the steps needed:

import smtplib
from email.mime.text import MIMEText
from jinja2 import Template

sender_email = "sender@gmail.com"
sender_password = "password"
recipient_email = "recipient@gmail.com"
with open('template.html', 'r') as f:
    template = Template(f.read())
context = {
    'subject': 'Hello from Python',
    'body': 'This is an email sent from Python using an HTML template and the Gmail SMTP server.'
}
html = template.render(context)
html_message = MIMEText(context['body'], 'html')
html_message['Subject'] = context['subject']
html_message['From'] = sender_email
html_message['To'] = recipient_email
with smtplib.SMTP_SSL('smtp.gmail.com', 465) as server:
   server.login(sender_email, sender_password)
   server.sendmail(sender_email, recipient_email, html_message.as_string())

If you’d like to learn more about sending dynamic content from your Python application, we recommend checking out our article about Mail Merge

How to send an email with an image in the body?

So first, you’ll need to use the MIMEMultipart class from the email package since it’s the class that allows you to create and send emails with multiple parts. Of course, you’ll need the MIMEText class as shown in previous examples, and to do the actual attaching of the image to the message as a separate part, use the MIMEImage class.

import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage


sender_email = "sender@gmail.com"
sender_password = "password"
recipient_email = "recipient@gmail.com"
subject = "Hello from Python"
body = "with image"

with open('two.jpg', 'rb') as f:
    image_part = MIMEImage(f.read())
message = MIMEMultipart()
message['Subject'] = subject
message['From'] = sender_email
message['To'] = recipient_email
html_part = MIMEText(body)
message.attach(html_part)
message.attach(image_part)
with smtplib.SMTP_SSL('smtp.gmail.com', 465) as server:
   server.login(sender_email, sender_password)
   server.sendmail(sender_email, recipient_email, message.as_string())

Sending an email with an attachment

Now that you know how to send a regular email and HTML email with Python using Gmail SMTP, let’s unpack how you can add attachments other than an image to the message body. 

As with previous examples, first, you need to import the necessary libraries. In this case, you’ll also need the MIMEBase that allows you to represent an attachment file and encoders, which is used to encode the attachment in base64 format.

Here’s the complete script including comments that will help you understand how to send an email with attachments:

import smtplib
from email import encoders
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

sender_email = "sender@gmail.com"
sender_password = "password"
recipient_email = "recipient@gmail.com"
subject = "Hello from Python"
body = "with attachment"


with open("attachment.txt", "rb") as attachment:
    # Add the attachment to the message
    part = MIMEBase("application", "octet-stream")
    part.set_payload(attachment.read())
encoders.encode_base64(part)
part.add_header(
    "Content-Disposition",
    f"attachment; filename= 'attachment.txt'",
)

message = MIMEMultipart()
message['Subject'] = subject
message['From'] = sender_email
message['To'] = recipient_email
html_part = MIMEText(body)
message.attach(html_part)
message.attach(part)

with smtplib.SMTP_SSL('smtp.gmail.com', 465) as server:
   server.login(sender_email, sender_password)
   server.sendmail(sender_email, recipient_email, message.as_string())

Is there an alternative?

The shorter answer is yes. 

There are plenty of alternatives to using Gmail’s SMTP server to send emails. You can use any other email provider of your choice. It’s important to ensure that their server infrastructure meets your requirements and needs. 

Another option is to use a third-party email service provider with an API that allows sending emails from your own application using their servers. Additionally, before implementing email sending functionality in your app, it’s important to test it. 

This is where the Mailtrap Email Delivery Platform comes in handy.

The platform offers Email Sending, which is used to deliver emails while giving you more control over your email infrastructure, and Email Testing, a tool that allows for inspecting and debugging those emails before they are sent.

If you’d like to use Mailtrap Email Sending with your Python app, you can easily do so with our official Python client. After verifying your domain name, just fetch your API token from Settings → API Tokens and save it for later.

Copying Mailtrap API token

Install the package with pip install mailtrap command (make sure the version is 2.0.0 or higher) and build a simple email with the following script:

import mailtrap as mt

# create mail object
mail = mt.Mail(
    sender=mt.Address(email="mailtrap@example.com", name="Mailtrap Test"),
    to=[mt.Address(email="your@email.com")],
    subject="You are awesome!",
    text="Congrats on sending your first email with Mailtrap Email Sending!",
)

# create client and send
client = mt.MailtrapClient(token="your-api-key")
client.send(mail)

Don’t forget to swap your-api-key with your actual API token. You’ll find the script for more complex emails on GitHub.

You can also select the SMTP method and copy the relevant configurations from the app. 

Mailtrap Email Sending SMTP credentials

Testing the effectiveness of your emails is crucial to ensure they are delivered successfully and adequately formatted. Email Testing is an Email Sandbox that offers a range of features to help you do just that. By capturing SMTP traffic, Email Testing allows you to analyze email content for a spam score, validate HTML/CSS, review raw data, and much more, thus ensuring that your emails are properly formatted and delivered successfully.

HTML check results in Mailtrap Email Testing


The tool can easily be integrated with your Python app in just a few clicks. All there is to do is to copy the SMTP credentials or the code snippet generated by the app and paste them into your code. 

Mailtrap Email Testing SMTP credentials

We hope this helps you in developing email sending functionality in your app! Just remember, before you start building it, make sure to research what Python framework to go with, as each one has its own set of features and benefits:

Article by Denys Kontorskyy Technical Content Writer @Mailtrap

I am an experienced Technical Content Writer specializing in email infrastructure, offering insights on sending, testing, and optimizing emails. I also have a strong interest in product marketing, creating engaging content that drives audience engagement and supports business growth. With a focus on delivering effective campaigns and staying updated with industry trends, I bring a strategic approach to my writing that aims to achieve measurable results.