Augustin Pan
Augustin Pan

Reputation: 147

Use Google API to send emails in Python script

I would like to use Google API to send emails. I copied the code from

https://developers.google.com/gmail/api/quickstart/

https://developers.google.com/gmail/api/guides/sending

However, I can only read the labels of my email, but I am not allowed to send emails. Here is the error it returned:

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

This is my code

from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from google.auth.transport.requests import Request

SCOPES = [
    'https://www.googleapis.com/auth/userinfo.email',
    'https://www.googleapis.com/auth/userinfo.profile',
    # Add other requested scopes.
    'https://www.googleapis.com/auth/gmail.send'
]

def create_message(sender, to, subject, message_text):
    message = MIMEText(message_text)
    message['to'] = to
    message['from'] = sender
    message['subject'] = subject
    return {'raw': message.as_string()}

def send_message(service, user_id, message):
    """
    Sends an email message.
    Arguments:
    service: an authorized Gmail API service instance.
    user_id: User's email address. To indicate the authenticated user, the special value "me" can be used.
    message: Message to be sent.
    """
    message = (service.users().messages().send(userId=user_id, body=message)
               .execute())
    print('Message Id: %s' % message['id'])
    return message

def main():
    creds = None
    # The file token.pickle stores the user's access and refresh tokens, and is
    # created automatically when the authorization flow completes for the first
    # time.
    if os.path.exists('token.pickle'):
        with open('token.pickle', 'rb') as token:
            creds = pickle.load(token)
    # 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(
                'credentials.json', SCOPES)
            creds = flow.run_local_server(port=0)
        # Save the credentials for the next run
        with open('token.pickle', 'wb') as token:
            pickle.dump(creds, token)
    service = build('gmail', 'v1', credentials=creds)
    # Call the Gmail API
    user_id = "me"
    results = service.users().labels().list(userId=user_id).execute()
    labels = results.get('labels', [])
    print("labels: ", labels)
    message = create_message(user_id, "[email protected]", "credit", "API test only!")
    message = send_message(service, user_id, message)
    print(message)

if __name__ == '__main__':
    main()

Upvotes: 0

Views: 1302

Answers (1)

Robert
Robert

Reputation: 11

Did you remove the “token.pickle” file after adding the line in SCOPES (l9) to get the send authorization? You have to redo the authorization procedure, else you still have read access only.

Upvotes: 1

Related Questions