使用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授权码流程:
- 在Google Cloud控制台创建OAuth 2.0客户端ID(类型选择桌面应用)。
- 使用
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
相关产品推荐
相关产品推荐

