Search code examples
pythongoogle-apigmail-apigoogle-workspacegoogle-api-python-client

"Requested entity was not found." When admin attempts to patch another users signature


I'm trying to set a user's signature via Python through the Gmail API. When doing it with my own admin user it works fine but when trying it with a different email address I'm getting this error:

googleapiclient.errors.HttpError: <HttpError 404 when requesting https://gmail.googleapis.com/gmail/v1/users/me/settings/sendAs/test_email@example.com?alt=json returned "Requested entity was not found.". Details: "[{'message': 'Requested entity was not found.', 'domain': 'global', 'reason': 'notFound'}]">

This is my Python code:

def main():
SCOPES = 'https://www.googleapis.com/auth/gmail.settings.basic'
# Check if token.pickle exists
if os.path.exists(client_token_pickle):
    creds = Credentials.from_authorized_user_file(client_token_pickle, SCOPES)

# If there are no (valid) credentials available, let the user log in.
if not creds or not creds.valid:
    if creds and creds.expired and creds.refresh_token:
        creds.refresh(Request())
    else:
        flow = InstalledAppFlow.from_client_secrets_file(client_oauth_file, scopes)
        creds = flow.run_local_server(port=8080)
    # Save the credentials for the next run
    with open(client_token_pickle, "w") as token:
        token.write(creds.to_json())

service = build('gmail', 'v1', credentials=creds)

signature = {'signature': 'lalala'}
service.users().settings().sendAs().patch(userId='me',sendAsEmail="test_email@smava.de", body=signature).execute()

With GAM it works fine so it should be possible somehow, but how? Thanks a lot for any input!


Solution

  • Requested entity was not found.

    Means that the entity you are trying to preform an action on does not exist for the currently authenticated user.

    When doing it with my own admin user it works fine but when trying it with a different email address I'm getting this error

    When you authorize that code you are authorizing it as a specific user. You can only make changes for that user.

    Even if the user is admin of a workspace domain they cant change someone else's data. You need to either authorize the code as that user or use a service account and delegate to that user.

    deligation to user

    For a service account to work it needs to be granted domain wide delegation this will enable it to preform actions on behalf of users on the domain.

    In the example directly from the documentation linked above

    from googleapiclient.discovery import build
    from oauth2client.service_account import ServiceAccountCredentials
    
    # Email of the Service Account
    SERVICE_ACCOUNT_EMAIL = '<some-id>@developer.gserviceaccount.com'
    
    # Path to the Service Account's Private Key file
    SERVICE_ACCOUNT_PKCS12_FILE_PATH = '/path/to/<public_key_fingerprint>-privatekey.p12'
    
    def create_directory_service(user_email):
        """Build and returns an Admin SDK Directory service object authorized with the service accounts
        that act on behalf of the given user.
    
        Args:
          user_email: The email of the user. Needs permissions to access the Admin APIs.
        Returns:
          Admin SDK directory service object.
        """
    
        credentials = ServiceAccountCredentials.from_p12_keyfile(
            SERVICE_ACCOUNT_EMAIL,
            SERVICE_ACCOUNT_PKCS12_FILE_PATH,
            'notasecret',
            scopes=['https://www.googleapis.com/auth/admin.directory.user'])
    
        credentials = credentials.create_delegated(user_email)
    
        return build('admin', 'directory_v1', credentials=credentials)
    

    You can see how they use

    credentials = credentials.create_delegated(user_email)
    

    To tell the service account which user it is to delegate to.

    Note the standard sample is for use with the admin directory api. you will need to alter it to work with gmail api. But not that much should need to be changed.