Reputation: 211
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)
Upvotes: 21
Views: 9450
Reputation: 193
I am assuming that you have taken this code from the Google Gmail API help. (If anyone is interested - https://developers.google.com/gmail/api/quickstart/python)
I was facing the same problem and had to modify the code many times.
Your problem can be solved by changing:
body = {'raw': base64.b64encode(message.as_bytes())}
with
raw = base64.urlsafe_b64encode(message.as_bytes())
raw = raw.decode()
body = {'raw': raw}
I tried and fixed most problems that I faced while running the sample code provided in the link above, and I eliminated most of them and, if anyone needs, here is the code that worked for me:
(P.S. I am using Python 3.8)
from __future__ import print_function
import pickle
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from email.mime.text import MIMEText
import base64
reciever = input("Please whom you want to send the mail to - ")
subject = input("Please write your subject - ")
msg = input("Please enter the main body of your mail - ")
SCOPES = ['https://www.googleapis.com/auth/gmail.modify']
creds = None
if os.path.exists('token.pickle'):
with open('token.pickle', 'rb') as token:
creds = pickle.load(token)
# If there are no (valid) credentials available, let the user log in.
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
'credentials.json', SCOPES)
creds = flow.run_local_server(port=0)
# Save the credentials for the next run
with open('token.pickle', 'wb') as token:
pickle.dump(creds, token)
service = build('gmail', 'v1', credentials=creds)
message = MIMEText(msg)
message['to'] = reciever
message['from'] = "[email protected]"
message['subject'] = subject
raw = base64.urlsafe_b64encode(message.as_bytes())
raw = raw.decode()
body = {'raw' : raw}
message = (service.users().messages().send(userId='me', body=body).execute())
You only have to import this code, run it, and input whatever is needed. This is completely safe as this is from google itself.
If this helps you, I will fell honoured.
Upvotes: 0
Reputation: 823
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
Upvotes: 9
Reputation: 412
If you are running in Python3, b64encode() will return byte string
You would have to decode it for anything that will do a json.dumps() on that data
b64_encoded_message = base64.b64encode(message.as_bytes())
if isinstance(b64_encoded_message, bytes):
b64_encoded_message = bytes_message.decode('utf-8')
body = {'raw': b64_encoded_message}
Upvotes: 1
Reputation: 1397
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
Upvotes: 39