0
votes

I'm using Gmail Api to send email in python but it looks like it doesn't work with Python 3.4.

Here is the code:

msg = MIMEText(html, 'html')
SCOPES = ['https://www.googleapis.com/auth/gmail.send']
username = '[email protected]'
CLIENT_SECRET_FILE = '/client_secret.json'  
credentials = ServiceAccountCredentials.from_json_keyfile_name(CLIENT_SECRET_FILE, SCOPES) 
try: 
     http_auth = credentials.authorize(Http()) 
     service = discovery.build('gmail', 'v1', http=http_auth) 
     gmailMsg = {'raw': base64.urlsafe_b64encode(msg.as_string().encode('utf-8')).decode('utf-8')} 
     message = (service.users().messages().send(userId = username, body = gmailMsg).execute())

Error:

<HttpError 400 when requesting https://www.googleapis.com/gmail/v1/users/me/messages/send?alt=json returned "Bad Request">

For the record, the credential I created for my project is a service account for non-ui platform (server-server). I thought that maybe the gmailMsg object wasn't encoded correctly. But when I used it in Google Apis Explorer, guess what: it worked. The only difference I can see is in Python, the JSON uses single quotation marks while in Google APIs Explorer, it foreced me to use double quotation marks.

Anyone has any recommendation?

P/S: I've tried following encoding options:

base64.urlsafe_b64encode(msg.as_string().encode('utf-8')).decode('utf-8')
base64.urlsafe_b64encode(msg.as_string().encode('utf-8')).decode('ascii')
base64.urlsafe_b64encode(msg.as_string().encode('ascii')).decode('ascii')
base64.urlsafe_b64encode(msg.as_bytes()).decode('utf-8')
base64.urlsafe_b64encode(msg.as_bytes()).decode('ascii')
base64.urlsafe_b64encode(msg.as_bytes()).decode()

Edit: Interestingly, i tried to use the Label Api which doesn't require body. But I got the same error. The only changes are:

SCOPES = ['https://www.googleapis.com/auth/gmail.labels']
message = (service.users().labels().list(userId = username).execute())
1

1 Answers

2
votes

It turns out that to use Gmail API I must use OAuth credential instead of Service account. In order to use Gmail API in a non UI system, you can initiate the authentication then copy the credential saved by the oauth api. Following is the code:

home_dir = os.path.expanduser('~')
credential_dir = os.path.join(home_dir, '.credentials')
if not os.path.exists(credential_dir):
    os.makedirs(credential_dir)
credential_path = os.path.join(credential_dir,
                               'gmail-api.json')

store = Storage(credential_path)
credentials = store.get()
f not credentials or credentials.invalid:
    flow = client.flow_from_clientsecrets(CLIENT_SECRET_FILE, SCOPES)
    flow.user_agent = APPLICATION_NAME
    if flags:
        credentials = tools.run_flow(flow, store, flags)
    else: # Needed only for compatibility with Python 2.6
        credentials = tools.run(flow, store)

Then you can use the gmail-api.json file to deploy on a non UI system to consume Gmail Api