0

All

I tried Gmail API with service account. I implemented code following:

package mywork.gmail.api;

import java.io.File;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.gmail.Gmail;
import com.google.api.services.gmail.GmailScopes;
import com.google.api.services.gmail.model.ListMessagesResponse;
import com.google.api.services.gmail.model.Message;

public class GmailApi {
    /** Email of the Service Account */
    private static final String SERVICE_ACCOUNT_EMAIL = "******@developer.gserviceaccount.com";

    /** Path to the Service Account's Private Key file */
    private static final String SERVICE_ACCOUNT_PKCS12_FILE_PATH = "src/main/resources/*******-privatekey.p12";

    public static void main(String[] args) throws Exception {
        GmailApi app = new GmailApi();

        String userId = "****@example.com";
        String labelId = "INBOX";

        app.listMessage(userId, labelId);
    }

    public void listMessage(String userId, String labelId) throws Exception {
        Gmail service = initService(userId);

        ListMessagesResponse response = service.users().messages().list(userId)
                .setLabelIds(Arrays.asList(labelId)).execute();

        List<Message> messages = new ArrayList<Message>();
        while (response.getMessages() != null) {
            messages.addAll(response.getMessages());
            if (response.getNextPageToken() != null) {
                String pageToken = response.getNextPageToken();
                response = service.users().messages().list(userId)
                        .setPageToken(pageToken).execute();
            } else {
                break;
            }
        }

        for (Message message : messages) {
            System.out.println(message.toPrettyString());
        }
    }

    private Gmail initService(String userId) throws GeneralSecurityException,
            IOException {

        HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
        JacksonFactory jsonFactory = JacksonFactory.getDefaultInstance();
        GoogleCredential credential = new GoogleCredential.Builder()
                .setTransport(httpTransport)
                .setJsonFactory(jsonFactory)
                .setServiceAccountId(SERVICE_ACCOUNT_EMAIL)
                .setServiceAccountScopes(Arrays.asList(GmailScopes.MAIL_GOOGLE_COM))
                .setServiceAccountUser(userId)
                .setServiceAccountPrivateKeyFromP12File(new File(SERVICE_ACCOUNT_PKCS12_FILE_PATH))
                .build();

        Gmail service = new Gmail.Builder(httpTransport, jsonFactory, credential)
                .setApplicationName("Gmail API sample").build();

        return service;
    }
}

but that code return 403 error:

Exception in thread "main" com.google.api.client.auth.oauth2.TokenResponseException: 403 Forbidden
    {
      "error" : "access_denied",
      "error_description" : "Requested client not authorized."
    }

Of course, I enabled Gmail API via Google Developer Console and set permissions(include Gmail scope) via Admin console.

What is wrong?

Thanks!

Jay Lee
  • 13,415
  • 3
  • 28
  • 59
Shoji Nakata
  • 1
  • 1
  • 2

1 Answers1

2

If your application accesses user data, the service account that you created needs to be granted access to the Google Apps domain’s user data that you want to access.

The following steps must be performed by an administrator of the Google Apps domain: Go to your Google Apps domain’s Admin console.

Select Security from the list of controls. If you don't see Security listed, select More controls from the gray bar at the bottom of the page, then select Security from the list of controls.

Select Advanced settings from the list of options.

Select Manage third party OAuth Client access in the Authentication section.

In the Client name field enter the service account's Client ID.

In the One or More API Scopes field enter the list of scopes that your application should be granted access to. For example if you need domain-wide access to the Google Drive API and the Google Calendar API enter: https://www.googleapis.com/auth/drive, https://www.googleapis.com/auth/calendar

Click Authorize.

Also, please check whether you have included all the scopes in your code which your application is trying to access.

Let me know if you still see the issue.

SGC
  • 1,025
  • 1
  • 6
  • 6
  • Thank you for your reply.I was granted access permission to my Google Apps Domain and I confirmed the scope include Gmail scope, but that application returned 403 error. However, I tried to access Google Calendar and Google drive via same credential(except but scope setting), then I could access normaly.Why...? – Shoji Nakata Nov 21 '14 at 00:11
  • If your application access drive, then the scope should be included. Otherwise it thrown this error – SGC Nov 21 '14 at 00:12
  • Can someone put screenshots here? There're a lot of design changes after 9 years – sedub01 Jul 25 '23 at 12:05