Accessing email of multiple GMail users in one web application

1.8k views Asked by At

I am trying to modify GMail messages of multiple users using the Google API Client with the GMail API on top of Google App Engine.

Flow outline: The user sends a request to the webApp adding a message into a queue. In this request, the Gmail account is checked for the existence of the given message. This message is then later to be processed via a cron job (without the user making another request).

I followed the example on how to use the API in the documentation and have the following two methods:

private static GoogleClientSecrets getClientCredential() throws IOException {
    return GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(Utils.class.getResourceAsStream("/client_secret.json")));
}

public static GoogleAuthorizationCodeFlow newFlow(final String userId) throws IOException {
    return new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT, JSON_FACTORY,
            getClientCredential(), Collections.singleton(GmailScopes.GMAIL_MODIFY))
            .setDataStoreFactory(DATA_STORE_FACTORY)
            .setAccessType("offline")
            .setApprovalPrompt("force")
            .addRefreshListener(
                    new DataStoreCredentialRefreshListener(userId, DATA_STORE_FACTORY))
            .build();
}

public static Gmail loadGmailClient(final String userId) throws IOException {
    final Credential credential = newFlow(userId).loadCredential(userId);
    return new Gmail.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential)
            .setApplicationName(APP_NAME)
            .build();
}

which should basically give me offline access to the users' mailbox, allowing me to process the given message later on in the cron.

as long as userId is "me" everything seems to work fine. However in the cron job phase that is supposed to modify without the user actually making a request to the WebApp, so I can't use "me" but have to use the users ID. Therefore I started using UserServiceFactory.getUserService().getCurrentUser().getUserId() as userId in the request phase and store this ID together with the cron job data.

When doing this, I keep on getting errors like

com.google.api.client.googleapis.json.GoogleJsonResponseException: 403
{
  "code" : 403,
  "errors" : [ {
    "domain" : "global",
    "message" : "Delegation denied for [email protected]",
    "reason" : "forbidden"
  } ],
  "message" : "Delegation denied for [email protected]"
}

I am not sure what part is incorrect, the "delegation" obviously seems as if something is wrong with the credentials, however delegation seems to be something else entirely related to Google Apps? Is anyone able to point me into the right direction?

1

There are 1 answers

0
Joscha On BEST ANSWER

So the right way to do this, is to load the credentials using the userId, e.g.

final Gmail gmail = loadGmailClient('someuserIdFromAGMailUser');

but when querying to use "me", so the GMail API uses the credentials from the given user, but only to query/modify his/her own data:

final Message message = gmail.users().messages().get("me", mailId).execute();

It seems as if a user does not have delegation to his/her own account, so using the userId in both cases comes up with the delegation denied error.