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

已建立Gmail API连接但无法发送邮件的问题解决

修复Gmail API发送邮件的两个错误

错误1:Invalid value at 'message' (raw), Starting an object on a scalar field

问题原因

你的GoogleMailClient.send_email方法内部已经会把传入参数包装成{'raw': message_body},但调用时你传入的是已经包含raw键的字典,导致最终提交给API的请求体变成了:

{'raw': {'raw': '你的base64编码内容'}}

Gmail API要求raw字段是字符串类型,而非嵌套对象,因此触发400错误。

修复方案

调用send_email时,直接传入base64编码后的字符串,而非字典:

# 去掉构建message字典的步骤,直接传message_base64
gmail_client.send_email(message_base64)

错误2:'GoogleMailClient' object has no attribute 'users'

问题原因

GoogleMailClient类并未暴露users方法,你错误地直接调用gmail_client.users(),正确的API调用逻辑已经封装在类的send_email方法中,类内部通过self.service调用Gmail API的users().messages().send接口。

修复方案

直接使用类中已定义的send_email方法,不要跳过封装直接调用底层API。

完整修复后的代码示例

# 导入必要模块
import email
import base64
import os
import pickle
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request

# 修正缩进后的GoogleMailClient类(原代码方法未缩进属于语法错误)
class GoogleMailClient:
    def __init__(self):
        self.SCOPES = ['https://www.googleapis.com/auth/gmail.modify'] 
        self.creds = self.get_credentials()
        self.service = self.build_gmail_service()

    def get_credentials(self):
        creds = None
        if os.path.exists('gmail_token.pickle'):
            with open('gmail_token.pickle', 'rb') as token:
                creds = pickle.load(token)

        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', self.SCOPES)
                creds = flow.run_local_server(port=0)

            with open('gmail_token.pickle', 'wb') as token:
                pickle.dump(creds, token)

        return creds

    def build_gmail_service(self):
        return build('gmail', 'v1', credentials=self.creds)

    def send_email(self, message_body):
        message = {'raw': message_body}
        self.service.users().messages().send(userId='me', body=message).execute()

    def list_messages(self):
        results = self.service.users().messages().list(userId='me').execute()
        messages = results.get('messages', [])
        return messages

    def get_message(self, message_id):
        message = self.service.users().messages().get(userId='me', id=message_id).execute()
        return message

    def mark_as_read(self, message_id):
        self.service.users().messages().modify(userId='me', id=message_id, body={'removeLabelIds': ['UNREAD']}).execute()

    def delete_message(self, message_id):
        self.service.users().messages().delete(userId='me', id=message_id).execute()

gmail_client = GoogleMailClient()

# 正确的邮件发送代码
subject = "Your Subject Here"
body = "Hey, this is your message body."

# 创建邮件对象(必须添加From字段,否则API可能拒绝)
message = email.message.EmailMessage()
message['from'] = "你的Gmail邮箱地址"
message['to'] = "XXX@hotmail.com"
message['subject'] = subject
message.set_content(body)

# 转换并编码邮件内容
message_as_string = message.as_string()
message_bytes = message_as_string.encode("utf-8")
message_base64 = base64.urlsafe_b64encode(message_bytes).decode("utf-8")

# 发送邮件
try:
    gmail_client.send_email(message_base64)
    print("邮件发送成功!")
except Exception as e:
    print(f"发送失败: {e}")

额外注意事项

  1. 类方法缩进:原代码中get_credentials等方法未缩进在类内部,属于语法错误,必须修正。
  2. From字段必填:发送邮件时必须指定From字段,否则Gmail API可能拒绝请求。
  3. 权限范围:当前使用的gmail.modify权限已包含发送能力,若仍有问题,可尝试替换为https://www.googleapis.com/auth/gmail.send或全权限https://mail.google.com/。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 11:02:09