Integrating GPT with Gmail API for draft emails


I have been building Python code that integrates GPT API with Gmail API so that content is extracted from an unread email and is sent to GPT to produce an email response based on the content.

I am facing two issues - 1) the number of tokens for sending and receiving the message seems to be much higher than expected e.g. a one-line email equating to 2000 tokens.

  1. Whilst I have managed to get the response from GPT to print in the terminal, it does not appear as an email in the drafts folder.

import os
import base64
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
import openai

Set up your Gmail API credentials

SCOPES = [‘Can’t include links - but modify included here’]

def get_gmail_credentials():
creds = None
if os.path.exists(‘token.json’):
creds = Credentials.from_authorized_user_file(‘token.json’, SCOPES)

if not creds or not creds.valid:
    if creds and creds.expired and creds.refresh_token:
        flow = InstalledAppFlow.from_client_secrets_file('credentials.json', SCOPES)
        creds = flow.run_local_server(port=0)
    with open('token.json', 'w') as token:

return creds

Initialize the Gmail service

def initialize_gmail_service():
creds = get_gmail_credentials()
return build(‘gmail’, ‘v1’, credentials=creds)

Function to get the entire email message

def get_email_message(service, message_id):
message = service.users().messages().get(userId=‘me’, id=message_id, format=‘raw’).execute()
message_raw = base64.urlsafe_b64decode(message[‘raw’].encode(‘UTF-8’)).decode(‘UTF-8’)
return message_raw
except Exception as e:
print(f"An error occurred: {str(e)}")
return None

Your OpenAI settings

openai.api_key = ‘YOUR OPEN AI KEY’ # Replace with your OpenAI API key
chatgpt_model = ‘gpt-3.5-turbo’ # Choose an appropriate model

Your conversation with OpenAI

messages = [
{“role”: “system”, “content”: “You are composing a response to an email.”},
{“role”: “user”, “content”: “Compose an email response based on the content of the unread message:”},

Get the list of unread emails

Function to get unread emails

def get_unread_emails(service):
query = “is:unread is:inbox”
response = service.users().messages().list(userId=‘me’, q=query).execute()
messages =

if 'messages' in response:

while 'nextPageToken' in response:
    page_token = response['nextPageToken']
    response = service.users().messages().list(userId='me', q=query, pageToken=page_token).execute()
    if 'messages' in response:

return messages

def main():
service = initialize_gmail_service()
unread_emails = get_unread_emails(service)

if unread_emails:
    # Choose the first unread email (you can modify the selection logic as needed)
    first_unread_email = unread_emails[0]
    message_id = first_unread_email['id']

    # Fetch the entire email message
    email_message = get_email_message(service, message_id)

    if email_message:
        # Include the email message in the conversation with OpenAI
        messages.append({"role": "assistant", "content": email_message})
        # Use OpenAI to generate a response
        response = openai.ChatCompletion.create(
            max_tokens=1000  # Adjust the max tokens as needed

        # Extract the response from OpenAI
        response_content = response['choices'][0]['message']['content']

        # You can use the response_content to send an email or take other actions
        print("OpenAI's response based on the email content:")
        print("Failed to retrieve the email message.")
    print("No unread emails found in the inbox.")

if name == “main”:

Hi and welcome to the developer forum!

One of the main reasons you might be seeing a high token count for a one-line email could be due to the raw format of the email content you’re extracting. Email headers, metadata, MIME boundaries, etc. can bloat the content significantly.

Try doing:

def get_email_message(service, message_id):
        message = service.users().messages().get(userId='me', id=message_id).execute()
        # Extracting only the body part
        parts = message['payload']['parts']
        for part in parts:
            if part['mimeType'] == 'text/plain':
                body_data = part['body']['data']
                email_body = base64.urlsafe_b64decode(body_data.encode('UTF-8')).decode('UTF-8')
                return email_body
    except Exception as e:
        print(f"An error occurred: {str(e)}")
        return None

You’re not creating a draft of the outgoing email so it’s not being sent, try adding something like

def save_as_draft(service, subject, body):
    message = base64.urlsafe_b64encode((f"Subject: {subject}\n\n{body}").encode("utf-8")).decode("utf-8")
    draft = {"message": {"raw": message}}
        result = service.users().drafts().create(userId='me', body=draft).execute()
        print(f"Draft saved with ID: {result['id']}")
    except Exception as e:
        print(f"An error occurred: {str(e)}")

In the main function, after generating a response, save it as a draft:

print("OpenAI's response based on the email content:")

# Save the response as a draft
save_as_draft(service, "Automated Response", response_content)

Thanks so much. This is working now. I realised the issue with the draft after posting, but the advise about tokens is super helpful. It is working!