Error 400 when sending a message using python

2020-07-17 04:57发布

问题:

I am trying to send an email using Gmail API. I have successfully authenticated and have a client_secret.json file on my machine. I have been able to get a list of labels using the quickstart example on the Gmail API website

I have reset my scope successfully to

SCOPES = 'https://mail.google.com'

allowing full access to my gmail account.

I have a python script, compiled from here and here. See below. When executing the script I get the following error message:

An error occurred: https://www.googleapis.com/gmail/v1/users/me/messages/send?alt=json returned "'raw' RFC822 payload message string or uploading message via /upload/* URL required">

Any thoughts on what I am doing wrong and how to fix it?

from __future__ import print_function
import argparse
import time
from time import strftime, localtime
import os

import base64
import os
import httplib2
from httplib2 import Http

from apiclient import errors
from apiclient import discovery

import oauth2client
from oauth2client import file, client, tools

SCOPES = 'https://mail.google.com'
CLIENT_SECRET_FILE = 'client_secret.json'
store = file.Storage('storage.json')
credentials = store.get()
if not credentials or credentials.invalid:
    flags = argparse.ArgumentParser(parents=[tools.argparser]).parse_args()
    flow = client.flow_from_clientsecrets('client_secret.json', SCOPES)
    credentials = tools.run_flow(flow, store, flags)

def get_credentials():
    """Gets valid user credentials from storage.

    If nothing has been stored, or if the stored credentials are invalid,
    the OAuth2 flow is completed to obtain the new credentials.

    Returns:
        Credentials, the obtained credential.
    """
    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-python-quickstart.json')

    store = oauth2client.file.Storage(credential_path)
    credentials = store.get()
    if 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)
        print('Storing credentials to ' + credential_path)
    return credentials


def send_message(service, user_id, message):
  """Send an email message.

  Args:
    service: Authorized Gmail API service instance.
    user_id: User's email address. The special value "me"
    can be used to indicate the authenticated user.
    message: Message to be sent.

  Returns:
    Sent Message.
  """
  try:
      message = (service.users().messages().send(userId=user_id, body=message)
                 .execute())
      print ('Message Id: %s' % message['id'])
      return message
  except errors.HttpError, error:
      print ('An error occurred: %s' % error)


def main():
    credentials = get_credentials()
    http = credentials.authorize(httplib2.Http())
    service = discovery.build('gmail', 'v1', http=http)
    send_message(service, 'me','test message')


main()

回答1:

A message has to be created like it is outlined in the Sending Email guide:

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

def main():
  credentials = get_credentials()
  http = credentials.authorize(httplib2.Http())
  service = discovery.build('gmail', 'v1', http=http)
  message = create_message(
    'sender@gmail.com', 'receiver@gmail.com', 'Subject', 'Message text'
  )
  send_message(service, 'me', message)