26
votes

I keep getting the following error when I execute my code:

An error occurred: <HttpError 403 when requesting https://www.googleapis.com/gmail/v1/users/me/messages/send?alt=json returned "Insufficient Permission">

This is my code:

import httplib2
import os
from httplib2 import Http

from apiclient import discovery
import oauth2client
from oauth2client import client
from oauth2client import tools

try:
    import argparse
    flags = argparse.ArgumentParser(parents=[tools.argparser]).parse_args()
except ImportError:
    flags = None

#SCOPES = 'https://www.googleapis.com/'
SCOPES = 'https://www.googleapis.com/auth/gmail.compose'
CLIENT_SECRET_FILE = 'client_secret.json'
APPLICATION_NAME = 'Gmail API Quickstart'

def get_credentials():
    """Gets valid user credentials from storage.

    If nothing has been stored, or if the stored credentials are invalid,
    the OAuth2 flow is completed to obtain the new credentials.

    Returns:
        Credentials, the obtained credential.
    """
    home_dir = os.path.expanduser('~')
    credential_dir = os.path.join(home_dir, '.credentials')
    if not os.path.exists(credential_dir):
        os.makedirs(credential_dir)
    credential_path = os.path.join(credential_dir,
                                   'gmail-quickstart.json')

    store = oauth2client.file.Storage(credential_path)
    credentials = store.get()
    if not credentials or credentials.invalid:
        flow = client.flow_from_clientsecrets(CLIENT_SECRET_FILE, SCOPES)
        flow.user_agent = APPLICATION_NAME
        if flags:
            credentials = tools.run_flow(flow, store, flags)
        else: # Needed only for compatability with Python 2.6
            credentials = tools.run(flow, store)
        print 'Storing credentials to ' + credential_path
    return credentials

def CreateMessage(sender, to, subject, message_text):
  """Create a message for an email.

  Args:
    sender: Email address of the sender.
    to: Email address of the receiver.
    subject: The subject of the email message.
    message_text: The text of the email message.

  Returns:
    An object containing a base64 encoded email object.
  """
  message = MIMEText(message_text)
  message['to'] = to
  message['from'] = sender
  message['subject'] = subject
  return {'raw': base64.b64encode(message.as_string())}

testMessage = CreateMessage('ENTER SENDERS EMAIL ADDRESS', 'ENTER RECEIVERRS EMAIL ADDRESS', 'ENTER SUBJECT', 'ENTER EMAIL BODY')

def SendMessage(service, user_id, message):
  """Send an email message.

  Args:
    service: Authorized Gmail API service instance.
    user_id: User's email address. The special value "me"
    can be used to indicate the authenticated user.
    message: Message to be sent.

  Returns:
    Sent Message.
  """
  try:
    message = (service.users().messages().send(userId=user_id, body=message)
               .execute())
    print 'Message Id: %s' % message['id']
    return message
  except errors.HttpError, error:
    print 'An error occurred: %s' % error


testSend = SendMessage(service, 'me', testMessage)

I keep reading that I need to edit a credentials file, but I can't seem to find it. I have windows 7 installed. Does anyone know what I need to do in order to get past this error? I'm a total noob at this so please excuse me if I seem a bit nooby about this. Thanks!

6

6 Answers

22
votes

Even though the accepted answer is 100% correct. I think it's worth pointing out that why that's the case.

When you authorize a gmail service client, you can specify several different scopes: All, compose, labels, etc...

These are all listed here: https://developers.google.com/gmail/api/auth/scopes

The scope mentioned in the answer provides complete gmail access.

16
votes

Solved it by changing the SCOPES line to:

SCOPES = 'https://mail.google.com/'

Email sending works perfectly

11
votes

Gmail API has these scopes: gmail api scopes

For sending emails, https://www.googleapis.com/auth/gmail.send is needed or full access https://mail.google.com/.

The scopes taken from here.

9
votes

If you run the official "gmail-python-quickstart" before, please delete the file "gmail-quickstart.json" in your system. Rerun your program again so that you can set the priviledge as you want.

2
votes

If you used google's official example, there should be a folder in ~/.credentials/ directory which is old, remove everything inside that directory and re-run your code. then you have to add new permissions and then everything is OK!

2
votes

In Addition to the answers from:

  1. ccy
  2. apadana
  3. ragnampiza

and as a furtherance of ccy's answer...


Solution 1...

... a hack fix

If you're using the original gmail-python-quickstart code, make sure to also update the following:

  1. CLIENT_SECRET_FILE = '/path/to/your/secret_client.json'
  2. Force get_credentials() to use the failed credentials logic path...
if True:
    flow = client.flow_from_clientsecrets(CLIENT_SECRET_FILE, SCOPES)
    flow.user_agent = APPLICATION_NAME
    if flags:
        credentials = tools.run_flow(flow, store, flags)
    else: # Needed only for compatibility with Python 2.6
        credentials = tools.run(flow, store)
    print('Storing credentials to ' + credential_path)

to force True so that the logic operation will definitely work the client.flow operations:

if True:
    flow = client.flow_from_clientsecrets(CLIENT_SECRET_FILE, SCOPES)
    flow.user_agent = APPLICATION_NAME
    if flags:
        credentials = tools.run_flow(flow, store, flags)
    else: # Needed only for compatibility with Python 2.6
        credentials = tools.run(flow, store)
    print('Storing credentials to ' + credential_path)

This is a hacky fix, but will get you up and going in short time.

The Problem...

  • The problem with this approach is that it forces the flow code, which opens up the authentication window browser and requires that the end user accept the security protocol before sending the email.
  • This obviously breaks the concept of automated email generation and sending.

Solution 2...

...a stable, more automated solution

I found that doing the following works:

  1. Copy the downloaded the secret-client-####.html.json file to the directory defined in the first block of code from the get_credentials() method. Basically, copy it to your user/.credentials directory
  2. Delete the current gmail-python-quickstart.json
  3. Rename your downloaded file to gmail-python-quickstart.json

Run your code, and then it should work fine.

Benefits...

  • The authentication page does not show up
  • The email is sent automatically