You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用ServiceAccount与Google API Python发送Gmail遇400错误求助

解决Gmail API服务账号调用的400预检查失败错误

补充说明

接受原答案后发现,我的问题针对免费Gmail账号(此前不知道付费与免费账号存在差异),而原答案适用于付费账号(该答案本身正确)。此答案让我了解到两者差异,并指引我找到适配自身情况的正确方案——使用应用专用密码。

问题详情

尝试通过ServiceAccount调用Google API发送邮件时,遇到如下错误:

An error occurred: <HttpError 400 when requesting https://gmail.googleapis.com/gmail/v1/users/me/drafts?alt=json returned "Precondition check failed.". Details: "[{'message': 'Precondition check failed.', 'domain': 'global', 'reason': 'failedPrecondition'}]">

所用代码

from __future__ import print_function

import os.path

from google.auth.transport.requests import Request
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
from oauth2client.service_account import ServiceAccountCredentials

import base64
from email.message import EmailMessage


# If modifying these scopes, delete the file token.json.
SCOPES = ['https://mail.google.com/']


def main():
    """Shows basic usage of the Gmail API.
    Lists the user's Gmail labels.
    """
    creds = None
    creds = ServiceAccountCredentials.from_json_keyfile_name(
        """path_to_cred_file.json""", SCOPES)

    try:
        # Call the Gmail API
        service = build('gmail', 'v1', credentials=creds)
        message = EmailMessage()
        message.set_content('This is automated draft mail')
        message['To'] = 'somemail@gmail.com'
        message['From'] = 'somemail@gmail.com'
        message['Subject'] = 'Automated draft'

        # encoded message
        encoded_message = base64.urlsafe_b64encode(message.as_bytes()).decode()

        create_message = {
            'message': {
                'raw': encoded_message
            }
        }
        # pylint: disable=E1101
        draft = service.users().drafts().create(userId="me",
                                                body=create_message).execute()
    except HttpError as error:
        # TODO(developer) - Handle errors from gmail API.
        print(f'An error occurred: {error}')


if __name__ == '__main__':
    main()

解决方案

这个错误的核心原因是免费Gmail账号不支持服务账号(ServiceAccount)直接调用Gmail API,服务账号仅对Google Workspace(付费)账号开放,且需要配置域范围委派。免费账号需使用以下两种方案之一:

方案1:切换到OAuth 2.0授权码流程

修改代码,通过用户授权的方式获取API访问权限,替代服务账号:

from __future__ import print_function

import os.path

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

import base64
from email.message import EmailMessage

# 修改权限范围后需删除token.json
SCOPES = ['https://mail.google.com/']

def main():
    creds = None
    # 读取已保存的凭据(首次运行后自动生成)
    if os.path.exists('token.json'):
        from google.oauth2.credentials import Credentials
        creds = Credentials.from_authorized_user_file('token.json', SCOPES)
    # 无有效凭据时触发用户登录授权
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            # 替换为你的OAuth客户端密钥文件路径
            flow = InstalledAppFlow.from_client_secrets_file('credentials.json', SCOPES)
            creds = flow.run_local_server(port=0)
        # 保存凭据供后续使用
        with open('token.json', 'w') as token:
            token.write(creds.to_json())

    try:
        service = build('gmail', 'v1', credentials=creds)
        message = EmailMessage()
        message.set_content('这是自动生成的草稿邮件')
        message['To'] = '目标邮箱@gmail.com'
        message['From'] = '你的免费Gmail账号@gmail.com'
        message['Subject'] = '自动草稿'

        encoded_message = base64.urlsafe_b64encode(message.as_bytes()).decode()

        create_message = {
            'message': {
                'raw': encoded_message
            }
        }
        draft = service.users().drafts().create(userId="me", body=create_message).execute()
        print(f"草稿创建成功,ID: {draft['id']}")
    except HttpError as error:
        print(f'发生错误: {error}')

if __name__ == '__main__':
    main()

注意:需在Google Cloud控制台创建OAuth客户端ID,下载credentials.json文件。

方案2:使用应用专用密码(需启用两步验证)

若你的免费Gmail账号已启用两步验证,可生成应用专用密码,通过SMTP发送邮件:

import smtplib
from email.message import EmailMessage

def send_email():
    msg = EmailMessage()
    msg.set_content('这是测试邮件内容')
    msg['Subject'] = '测试邮件'
    msg['From'] = '你的免费Gmail账号@gmail.com'
    msg['To'] = '目标邮箱@gmail.com'

    # 使用应用专用密码登录SMTP服务器
    with smtplib.SMTP_SSL('smtp.gmail.com', 465) as smtp:
        smtp.login('你的免费Gmail账号@gmail.com', '你的应用专用密码')
        smtp.send_message(msg)
        print("邮件发送成功")

if __name__ == '__main__':
    send_email()

注意:应用专用密码需在Google账号安全设置中生成。

内容的提问来源于stack exchange,提问作者yaodav

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 05:35:17