Python Gmail API'不是 JSON 可序列化的'

Posted

技术标签:

【中文标题】Python Gmail API\'不是 JSON 可序列化的\'【英文标题】:Python Gmail API 'not JSON serializable'Python Gmail API'不是 JSON 可序列化的' 【发布时间】:2016-12-02 16:38:11 【问题描述】:

我想使用 Gmail API 通过 Python 发送电子邮件。一切都应该没问题,但我仍然收到错误“发生错误:b'Q29udGVudC1UeXBlOiB0ZXh0L3BsYWluOyBjaGFyc2V0PSJ1cy1hc2NpaSIKTUlNRS ...”这是我的代码:

import base64
import httplib2

from email.mime.text import MIMEText

from apiclient.discovery import build
from oauth2client.client import flow_from_clientsecrets
from oauth2client.file import Storage
from oauth2client.tools import run_flow


# Path to the client_secret.json file downloaded from the Developer Console
CLIENT_SECRET_FILE = 'client_secret.json'

# Check https://developers.google.com/gmail/api/auth/scopes for all available scopes
OAUTH_SCOPE = 'https://www.googleapis.com/auth/gmail.compose'

# Location of the credentials storage file
STORAGE = Storage('gmail.storage')

# Start the OAuth flow to retrieve credentials
flow = flow_from_clientsecrets(CLIENT_SECRET_FILE, scope=OAUTH_SCOPE)
http = httplib2.Http()

# Try to retrieve credentials from storage or run the flow to generate them
credentials = STORAGE.get()
if credentials is None or credentials.invalid:
  credentials = run_flow(flow, STORAGE, http=http)

# Authorize the httplib2.Http object with our credentials
http = credentials.authorize(http)

# Build the Gmail service from discovery
gmail_service = build('gmail', 'v1', http=http)

# create a message to send
message = MIMEText("Message")
message['to'] = "myemail@gmail.com"
message['from'] = "python.api123@gmail.com"
message['subject'] = "Subject"
body = 'raw': base64.b64encode(message.as_bytes())

# send it
try:
  message = (gmail_service.users().messages().send(userId="me",     body=body).execute())
  print('Message Id: %s' % message['id'])
  print(message)
except Exception as error:
  print('An error occurred: %s' % error)

【问题讨论】:

*错误是“fhkakjfwjkfbmdn... is not JSON serializable 【参考方案1】:

我也遇到了同样的问题,我假设您使用的是 Python3,我在另一篇文章中发现了这个问题,建议执行以下操作:

raw = base64.urlsafe_b64encode(message.as_bytes())
raw = raw.decode()
body = 'raw': raw

查看: https://github.com/google/google-api-python-client/issues/93

【讨论】:

也为我工作 哇,你为我节省了更多的绝望时间。 感谢@Robert,为我工作【参考方案2】:

如果你在 Python3 中运行,b64encode() 将返回字节字符串

您必须对其进行解码以获取任何会对该数据执行 json.dumps() 的操作

b64_encoded_message = base64.b64encode(message.as_bytes())
if isinstance(b64_encoded_message, bytes):
    b64_encoded_message = bytes_message.decode('utf-8')
body = 'raw': b64_encoded_message

【讨论】:

【参考方案3】:

在过去的一天里,我一直在努力阅读(过时的)Gmail API 文档和 ***,希望以下内容对其他 Python 3.8 人员有所帮助。如果对您有帮助,请投票!

import os
import base64
import pickle
from pathlib import Path
from email.mime.text import MIMEText
import googleapiclient.discovery
import google_auth_oauthlib.flow
import google.auth.transport.requests

def retry_credential_request(self, force = False):
    """ Deletes token.pickle file and re-runs the original request function """
    print("⚠ Insufficient permission, probably due to changing scopes.")
    i = input("Type [D] to delete token and retry: ") if force == False else 'd'
    if i.lower() == "d":
        os.remove("token.pickle")
        print("Deleted token.pickle")
        self()

def get_google_api_credentials(scopes):
    """ Returns credentials for given Google API scope(s) """
    credentials = 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 Path('token.pickle').is_file():
        with open('token.pickle', 'rb') as token:
            credentials = pickle.load(token)
    # If there are no (valid) credentials available, let the user log in.
    if not credentials or not credentials.valid:
        if credentials and credentials.expired and credentials.refresh_token:
            credentials.refresh(google.auth.transport.requests.Request())
        else:
            flow = google_auth_oauthlib.flow.InstalledAppFlow.from_client_secrets_file('credentials-windows.json', scopes)
            credentials = flow.run_local_server(port=0)
        # Save the credentials for the next run
        with open('token.pickle', 'wb') as token:
            pickle.dump(credentials, token)
    return credentials

def send_gmail(sender, to, subject, message_text):
    """Send a simple email using Gmail API"""
    scopes = ['https://www.googleapis.com/auth/gmail.compose']
    gmail_api = googleapiclient.discovery.build('gmail', 'v1', credentials=get_google_api_credentials(scopes))
    message = MIMEText(message_text)
    message['to'] = to
    message['from'] = sender
    message['subject'] = subject
    raw = base64.urlsafe_b64encode(message.as_bytes()).decode()
    try:
        request=gmail_api.users().messages().send(userId = "me", body = 'raw': raw).execute()
    except googleapiclient.errors.HttpError as E:
        print(E)
        drive_api = retry_credential_request(send_gmail)
        return
    return request

【讨论】:

您先生是救生员。我错误地使用了 decode() 方法。你有我的赞成票。 我很高兴 - 感谢您抽出时间告诉我@Gergely :)【参考方案4】:

我假设您已从 Google Gmail API 帮助中获取此代码。 (如果有人感兴趣-https://developers.google.com/gmail/api/quickstart/python)

我遇到了同样的问题,不得不多次修改代码。

你的问题可以通过改变来解决:

body = 'raw': base64.b64encode(message.as_bytes())

raw = base64.urlsafe_b64encode(message.as_bytes())
raw = raw.decode()
body = 'raw': raw

我尝试并修复了在运行上面链接中提供的示例代码时遇到的大多数问题,我消除了大部分问题,如果有人需要,这里是对我有用的代码:

(附注:我使用的是 Python 3.8)

from __future__ import print_function
import pickle
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from email.mime.text import MIMEText
import base64

reciever = input("Please whom you want to send the mail to - ")
subject = input("Please write your subject - ")
msg = input("Please enter the main body of your mail - ")

SCOPES = ['https://www.googleapis.com/auth/gmail.modify']
creds = None
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)
message = MIMEText(msg)
message['to'] = reciever
message['from'] = "ayush.abhishek.bhatt@gmail.com"
message['subject'] = subject
raw = base64.urlsafe_b64encode(message.as_bytes())
raw = raw.decode()
body = 'raw' : raw
message = (service.users().messages().send(userId='me', body=body).execute())

您只需导入此代码、运行它并输入所需的任何内容。这是完全安全的,因为它来自谷歌本身。

如果这对你有帮助,我会很荣幸。

【讨论】:

以上是关于Python Gmail API'不是 JSON 可序列化的'的主要内容,如果未能解决你的问题,请参考以下文章

Java 是不是有任何用于 Gmail 聊天的 API?

Gmail推送通知Python API

如何在 python 中向 Gmail-API 发送批处理请求?

作为发件人,使用 API 或标头,是不是可以检测电子邮件是不是使用 Gmail 的“计划发送”发送?

处理来自 API 的 JSON 中的语法错误

为啥 Facebook、Twitter 和 GMail 将其所有数据以 JSON 而不是 HTML 的形式呈现给浏览器?