In this Python tutorial, we will learn how to send an email with attachments using Google Gmail API service.

Using Gmail API, we can Read and send messages, manage drafts and attachments, search threads and messages, work with labels, setup push notifications, and manage Gmail settings, all in one place.

Step 1. Enable Gmail API service

  1. Log in to your Google Cloud Platform,
  2. Select your project
  3. Enable Gmail API service

If this is your first time working with Google API service, to learn how to create your first Google Project.

Step 2. Install Python Library

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



Send an email

Before we are starting writing the script, few things to consider.

1. Maximum file size is 35MB
2. Accepted Media MIME type is message/rfc822
3. The special value “me” can be used to indicate the authenticated user.

References

  • Gmail Scopes (https://developers.google.com/gmail/api/auth/scopes)
  • Email Mime (https://docs.python.org/3/library/email.mime.html)

Buy Me a Coffee? Your support is much appreciated!
PayPal Me: https://www.paypal.me/jiejenn/5
Venmo: @Jie-Jenn



Source Code:

from Google import Create_Service
import os
import base64
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
import mimetypes
 
CLIENT_SECRET_FILE = '<Client Secret File'
API_NAME = 'gmail',
API_VERSION = 'v1'
SCOPES = ['https://mail.google.com/']
 
service = Create_Service(CLIENT_SECRET_FILE, API_NAME, API_VERSION, SCOPES)
 
file_attachments = ['<Attachment 1>', '<Attachment 2>', '<Attachment n>']
 
emailMsg = 'Three files attached'
 
# create email message
mimeMessage = MIMEMultipart()
mimeMessage['to'] = 'email1@EmailDomain.com; email2@EmailDomain.com'
mimeMessage['subject'] = 'You got files'
mimeMessage.attach(MIMEText(emailMsg, 'plain'))
 
# Attach files
for attachment in file_attachments:
    content_type, encoding = mimetypes.guess_type(attachment)
    main_type, sub_type = content_type.split('/', 1)
    file_name = os.path.basename(attachment)
 
    f = open(attachment, 'rb')
 
    myFile = MIMEBase(main_type, sub_type)
    myFile.set_payload(f.read())
    myFile.add_header('Content-Disposition', 'attachment', filename=file_name)
    encoders.encode_base64(myFile)
 
    f.close()
 
    mimeMessage.attach(myFile)
 
raw_string = base64.urlsafe_b64encode(mimeMessage.as_bytes()).decode()
 
message = service.users().messages().send(
    userId='me',
    body={'raw': raw_string}).execute()
 
print(message)



Google.py

import pickle
import os
from google_auth_oauthlib.flow import Flow, InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.http import MediaFileUpload, MediaIoBaseDownload
from google.auth.transport.requests import Request


def Create_Service(client_secret_file, api_name, api_version, *scopes):
    print(client_secret_file, api_name, api_version, scopes, sep='-')
    CLIENT_SECRET_FILE = client_secret_file
    API_SERVICE_NAME = api_name
    API_VERSION = api_version
    SCOPES = [scope for scope in scopes[0]]
    print(SCOPES)

    cred = None

    pickle_file = f'token_{API_SERVICE_NAME}_{API_VERSION}.pickle'
    # print(pickle_file)

    if os.path.exists(pickle_file):
        with open(pickle_file, 'rb') as token:
            cred = pickle.load(token)

    if not cred or not cred.valid:
        if cred and cred.expired and cred.refresh_token:
            cred.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file(CLIENT_SECRET_FILE, SCOPES)
            cred = flow.run_local_server()

        with open(pickle_file, 'wb') as token:
            pickle.dump(cred, token)

    try:
        service = build(API_SERVICE_NAME, API_VERSION, credentials=cred)
        print(API_SERVICE_NAME, 'service created successfully')
        return service
    except Exception as e:
        print('Unable to connect.')
        print(e)
        return None

def convert_to_RFC_datetime(year=1900, month=1, day=1, hour=0, minute=0):
    dt = datetime.datetime(year, month, day, hour, minute, 0).isoformat() + 'Z'
    return dt