I am trying to use the Gmail API with the Python Google Client library.
I have created a Service Account credential through the Google Developer Console.
I am then attempting to use those credentials like sO:
from oauth2client.client import SignedJwtAssertionCredentials
client_email = '<sanitised>@developer.gserviceaccount.com'
with open("foobar-<sanitised>.p12") as f:
private_key = f.read()
credentials = SignedJwtAssertionCredentials(client_email, private_key, 'https://www.googleapis.com/auth/gmail.readonly')
from httplib2 import Http
http_auth = credentials.authorize(Http())
from apiclient.discovery import build
gmail_server = build('gmail', 'v1', http=http_auth)
However, when I try to use the actual Gmail API, I get an HTTP 500 error:
In [13]: threads = gmail_server.users().threads().list(userId='me').execute()
---------------------------------------------------------------------------
HttpError Traceback (most recent call last)
<ipython-input-13-a74134635cc3> in <module>()
----> 1 threads = gmail_server.users().threads().list(userId='me').execute()
/Users/victorhooi/.virtualenvs/kenny/lib/python2.7/site-packages/oauth2client/util.pyc in positional_wrapper(*args, **kwargs)
133 else: # IGNORE
134 pass
--> 135 return wrapped(*args, **kwargs)
136 return positional_wrapper
137
/Users/victorhooi/.virtualenvs/kenny/lib/python2.7/site-packages/googleapiclient/http.pyc in execute(self, http, num_retries)
721 callback(resp)
722 if resp.status >= 300:
--> 723 raise HttpError(resp, content, uri=self.uri)
724 return self.postproc(resp, content)
725
HttpError: <HttpError 500 when requesting https://www.googleapis.com/gmail/v1/users/me/threads?alt=json returned "Backend Error">
A user mentioned here that apparently the "Service Accounts" do not support using the GMail API:
https://stackoverflow.com/a/24645874/139137
Is anybody able to confirm if this is the case, or if it's documented by Google anywhere?
My assumption was that since the Service Account credentials were created through a user's Google Developer Console, it would just be associated with that user, and should work fine?
EDIT:
I should also mentioned I did try explicitly adding my client to the "Managing Client API Access" page in the Google Apps Admin Console:
However, I am still getting the HTTP 500 Backend Error.
Also, the help links on that page go to a OAuth 1.0 specific page - I have a suspicion that this page is only for OAuth 1.0, although it's not explicitly mentioned there.
EDIT 2
Also, I should mentioned that I tried using the Google API Explorer at:
https://developers.google.com/apis-explorer/#p/gmail/v1/gmail.users.messages.list?userId=me&_h=1&
using OAuth 2.0 and the interactive user flow, and it works fine (i.e. it lists emails).
EDIT 3
I tried adding the sub
argument as suggested by Jay Lee.
On my own Google Apps domain, it does actually work:
from oauth2client.client import SignedJwtAssertionCredentials
client_email = '<sanitised>@developer.gserviceaccount.com'
with open('foo-bar-<sanitised>.p12') as f:
private_key = f.read()
credentials = SignedJwtAssertionCredentials(client_email, private_key, 'https://www.googleapis.com/auth/gmail.readonly', sub='victorhooi@example.com')
from httplib2 import Http
http_auth = credentials.authorize(Http())
from apiclient.discovery import build
gmail_server = build('gmail', 'v1', http=http_auth)
threads = gmail_server.users().threads().list(userId='me').execute()
And then threads gives me:
In [12]: threads
Out[12]:
{u'nextPageToken': u'00058094761552980977',
u'resultSizeEstimate': 178,
u'threads': [{u'historyId': u'8942',
u'id': u'14abc26f1893823b',
u'snippet': u''},
{u'historyId': u'8822', u'id': u'14a4ffc2724e9384', u'snippet': u''},
{u'historyId': u'8769', u'id': u'14a36a9c6f552af3', u'snippet': u''},
{u'historyId': u'8716', u'id': u'14a31822f19bb161', u'snippet': u''},
{u'historyId': u'8671', u'id': u'14a2bee13eb87c07', u'snippet': u''},
However, when I try using the sub argument on my corporate Google Apps domain, when I get to the following line:
gmail_server = build('gmail', 'v1', http=http_auth)
This gives me the error:
AccessTokenRefreshError: access_denied: Requested client not authorized.
I'm fairly certain that client does exist in the Google Developer's console, and the Gmail API is enabled. I'm just not sure why the sub
argument triggers that error.
And then, if I try the same code using a different account on the corporate Google Apps domain, that hasn't been Delegated, I get:
AccessTokenRefreshError: unauthorized_client: Unauthorized client or scope in request.