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

使用Python通过Google API下载Gmail附件遇401认证错误求助

Gmail API 401认证错误问题分析与解决

问题根源

你遇到的401错误主要由三个原因导致:

  • 服务账号缺少域范围委派权限:服务账号本身没有独立的Gmail邮箱,若要访问普通用户的邮箱,必须在Google Workspace(原G Suite)后台为其配置域范围委派,授予它模拟指定用户访问Gmail的权限。如果是个人Google账号,服务账号无法直接访问,需改用OAuth 2.0授权码流程。
  • 代码语法错误:加载凭证时,scopes参数的写法有误,应该是scopes=[...]而不是scopes[...],这会导致凭证未能正确加载所需的API权限。
  • userId参数错误:使用服务账号时,不能用userId='me',必须指定要访问的目标用户邮箱地址,因为服务账号是模拟该用户进行操作。

修正后的代码(适用于Google Workspace账号)

import base64
from datetime import datetime, timedelta
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
from google.oauth2.service_account import Credentials

# 要访问的目标用户邮箱
target_user_email = "your-target-email@domain.com"
# 服务账号凭证路径
service_account_file = "token.json"
# API权限范围
scopes = ["https://www.googleapis.com/auth/gmail.readonly"]

# 加载服务账号凭证并指定模拟用户
creds = Credentials.from_service_account_file(
    service_account_file,
    scopes=scopes,
    subject=target_user_email
)

# 创建Gmail API服务
service = build('gmail', 'v1', credentials=creds)

# 计算12小时前的时间(Gmail API需要RFC3339格式)
now = datetime.utcnow()
time_threshold = now - timedelta(hours=12)
formatted_time_threshold = time_threshold.strftime('%Y-%m-%dT%H:%M:%SZ')

# 目标发件人邮箱
sender_email = 'mail@domain.com'

# 构建查询语句
query = f'from:{sender_email} after:{formatted_time_threshold}'
print(query)

try:
    # 获取匹配的邮件列表
    response = service.users().messages().list(q=query, userId=target_user_email).execute()
    messages = response.get('messages', [])
    
    # 遍历邮件下载附件
    for msg in messages:
        message = service.users().messages().get(userId=target_user_email, id=msg['id']).execute()
        payload = message['payload']

        # 检查是否有附件
        if 'parts' in payload:
            for part in payload['parts']:
                if part.get('filename'):
                    filename = part['filename']
                    # 处理附件数据(大附件需单独调用接口获取)
                    if 'data' in part['body']:
                        data = part['body']['data']
                        file_data = base64.urlsafe_b64decode(data.encode('UTF-8'))
                    else:
                        attachment_id = part['body']['attachmentId']
                        attachment = service.users().messages().attachments().get(
                            userId=target_user_email, messageId=msg['id'], id=attachment_id
                        ).execute()
                        data = attachment['data']
                        file_data = base64.urlsafe_b64decode(data.encode('UTF-8'))
                    
                    # 保存附件到本地
                    with open(filename, 'wb') as f:
                        f.write(file_data)
                    print(f'已保存附件: {filename}')
except HttpError as error:
    print(f'发生错误: {error}')

额外配置步骤(Google Workspace用户)

  • 登录Google Workspace管理后台,找到IAM与管理员 > 服务账号,定位你的服务账号。
  • 点击编辑 > 域范围委派,添加https://www.googleapis.com/auth/gmail.readonly到已授权的API范围。
  • 确保服务账号已被授予访问目标用户邮箱的权限(可在用户账号的权限设置中添加服务账号邮箱)。

替代方案(个人Google账号)

如果是个人Google账号,无法使用服务账号的域范围委派,需改用OAuth 2.0授权码流程:

  1. 在Google Cloud控制台创建OAuth 2.0客户端ID(类型选择桌面应用)。
  2. 使用google-auth-oauthlib库获取用户授权,核心代码示例:
from google_auth_oauthlib.flow import InstalledAppFlow

# 权限范围
SCOPES = ['https://www.googleapis.com/auth/gmail.readonly']

# 加载OAuth客户端凭证(从控制台下载的client_secret.json)
flow = InstalledAppFlow.from_client_secrets_file(
    'client_secret.json', SCOPES)
creds = flow.run_local_server(port=0)

# 后续API调用与之前一致,userId可使用'me'

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 00:42:41