Search code examples
pythongmail-apigoogle-api-clientgoogle-oauthservice-accounts

Can't authenticate Google service account to Gmail


I have a GSuite email address example@gmail.com and I created a Google service account example-sa@iam.gserviceaccount.com.

My goal is to send emails from this SA as if it was the email but I'm not able to authenticate the SA.

I could however login the service account Google Drive with this code:

from google.oauth2 import service_account
from googleapiclient import discovery

SCOPES = ['https://www.googleapis.com/auth/drive']
SERVICE_ACCOUNT_FILE = 'sa-credentials.json'
creds = service_account.Credentials.from_service_account_file(SERVICE_ACCOUNT_FILE, scopes=SCOPES)
service = discovery.build('drive', 'v3', credentials=creds, cache_discovery=False)

# code

However, when I try to do the same for gmail I get an error:

from google.oauth2 import service_account
from googleapiclient import discovery

SCOPES = ['https://mail.google.com/']
SERVICE_ACCOUNT_FILE = 'sa-credentials.json'
creds = service_account.Credentials.from_service_account_file(SERVICE_ACCOUNT_FILE, scopes=SCOPES)
service = discovery.build('gmail', 'v1', credentials=creds, cache_discovery=False)

profile = service.users().getProfile(userId='me').execute()

The error:

    raise HttpError(resp, content, uri=self.uri)
googleapiclient.errors.HttpError: <HttpError 400 when requesting https://www.googleapis.com/gmail/v1/users/me/profile?alt=json returned "Bad Request">

If I click on the URL provided in the error message I get:

{
 "error": {
  "errors": [
   {
    "domain": "global",
    "reason": "required",
    "message": "Login Required",
    "locationType": "header",
    "location": "Authorization"
   }
  ],
  "code": 401,
  "message": "Login Required"
 }
}

Solution

  • See this similar question: GMail API - Can I send email using the Service Account?

    No. The Gmail API is for Gmail users and service accounts are just for doing auth to a real Gmail account, they don't have their own Gmail account, etc.

    In other words, the service account doesn't appear to be a Gmail mailbox that you can access.

    You need to use the service account to access some other mailbox, and to do that, you need to do one of two things:

    1. Use a Oauth2 flow to get the owner of the mailbox you wish to use to grant access (see: https://developers.google.com/gmail/api/auth/web-server)

    OR

    1. If you control / own the Gsuite domain, grant domain-wide authority for that domain to your service account. See: https://developers.google.com/admin-sdk/directory/v1/guides/delegation