Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python Gmail API 'not JSON serializable'

I want to send an Email through Python using the Gmail API. Everythingshould be fine, but I still get the error "An error occurred: b'Q29udGVudC1UeXBlOiB0ZXh0L3BsYWluOyBjaGFyc2V0PSJ1cy1hc2NpaSIKTUlNRS..." Here is my code:

import base64
import httplib2

from email.mime.text import MIMEText

from apiclient.discovery import build
from oauth2client.client import flow_from_clientsecrets
from oauth2client.file import Storage
from oauth2client.tools import run_flow


# Path to the client_secret.json file downloaded from the Developer Console
CLIENT_SECRET_FILE = 'client_secret.json'

# Check https://developers.google.com/gmail/api/auth/scopes for all available scopes
OAUTH_SCOPE = 'https://www.googleapis.com/auth/gmail.compose'

# Location of the credentials storage file
STORAGE = Storage('gmail.storage')

# Start the OAuth flow to retrieve credentials
flow = flow_from_clientsecrets(CLIENT_SECRET_FILE, scope=OAUTH_SCOPE)
http = httplib2.Http()

# Try to retrieve credentials from storage or run the flow to generate them
credentials = STORAGE.get()
if credentials is None or credentials.invalid:
  credentials = run_flow(flow, STORAGE, http=http)

# Authorize the httplib2.Http object with our credentials
http = credentials.authorize(http)

# Build the Gmail service from discovery
gmail_service = build('gmail', 'v1', http=http)

# create a message to send
message = MIMEText("Message")
message['to'] = "[email protected]"
message['from'] = "[email protected]"
message['subject'] = "Subject"
body = {'raw': base64.b64encode(message.as_bytes())}

# send it
try:
  message = (gmail_service.users().messages().send(userId="me",     body=body).execute())
  print('Message Id: %s' % message['id'])
  print(message)
except Exception as error:
  print('An error occurred: %s' % error)
like image 501
Stormbreaker Avatar asked Jul 28 '16 10:07

Stormbreaker


People also ask

Is Python set JSON serializable?

If you try to convert the Set to json, you will get this error: TypeError: Object of type set is not JSON serializable. This is because the inbuilt Python json module can only handle primitives data types with a direct JSON equivalent and not complex data types like Set.

Is not JSON serializable error in Python?

The Python "TypeError: Object of type set is not JSON serializable" occurs when we try to convert a set object to a JSON string. To solve the error, convert the set to a list before serializing it to JSON, e.g. json. dumps(list(my_set)) . Here is an example of how the error occurs.


Video Answer


2 Answers

I had this same issue, I assume you are using Python3 I found this on another post and the suggestion was to do the following:

raw = base64.urlsafe_b64encode(message.as_bytes())
raw = raw.decode()
body = {'raw': raw}

Check out: https://github.com/google/google-api-python-client/issues/93

like image 159
Robert Walters Avatar answered Oct 06 '22 00:10

Robert Walters


I've been struggling through the (out of date) Gmail API docs and stackoverflow for the past day and hope the following will be of help to other Python 3.8 people. Please up-vote if it helps you!

import os
import base64
import pickle
from pathlib import Path
from email.mime.text import MIMEText
import googleapiclient.discovery
import google_auth_oauthlib.flow
import google.auth.transport.requests

def retry_credential_request(self, force = False):
    """ Deletes token.pickle file and re-runs the original request function """
    print("⚠ Insufficient permission, probably due to changing scopes.")
    i = input("Type [D] to delete token and retry: ") if force == False else 'd'
    if i.lower() == "d":
        os.remove("token.pickle")
        print("Deleted token.pickle")
        self()

def get_google_api_credentials(scopes):
    """ Returns credentials for given Google API scope(s) """
    credentials = None
    # The file token.pickle stores the user's access and refresh tokens, and is
    # created automatically when the authorization flow completes for the first
    # time.
    if Path('token.pickle').is_file():
        with open('token.pickle', 'rb') as token:
            credentials = pickle.load(token)
    # If there are no (valid) credentials available, let the user log in.
    if not credentials or not credentials.valid:
        if credentials and credentials.expired and credentials.refresh_token:
            credentials.refresh(google.auth.transport.requests.Request())
        else:
            flow = google_auth_oauthlib.flow.InstalledAppFlow.from_client_secrets_file('credentials-windows.json', scopes)
            credentials = flow.run_local_server(port=0)
        # Save the credentials for the next run
        with open('token.pickle', 'wb') as token:
            pickle.dump(credentials, token)
    return credentials

def send_gmail(sender, to, subject, message_text):
    """Send a simple email using Gmail API"""
    scopes = ['https://www.googleapis.com/auth/gmail.compose']
    gmail_api = googleapiclient.discovery.build('gmail', 'v1', credentials=get_google_api_credentials(scopes))
    message = MIMEText(message_text)
    message['to'] = to
    message['from'] = sender
    message['subject'] = subject
    raw = base64.urlsafe_b64encode(message.as_bytes()).decode()
    try:
        request=gmail_api.users().messages().send(userId = "me", body = {'raw': raw}).execute()
    except googleapiclient.errors.HttpError as E:
        print(E)
        drive_api = retry_credential_request(send_gmail)
        return
    return request

like image 41
Peter F Avatar answered Oct 05 '22 23:10

Peter F