使用Gmail API创建草稿时遇GOOGLE_APPLICATION_CREDENTIALS未找到错误求助
Gmail API 创建草稿时触发
DefaultCredentialsError 问题解决 我在使用Gmail API创建邮件草稿时,反复触发DefaultCredentialsError错误,提示无法自动确定凭据,需要设置GOOGLE_APPLICATION_CREDENTIALS环境变量或显式创建凭据。我已经下载了对应的JSON凭据文件、按要求创建凭据并添加测试邮箱,且能完成登录授权流程,但加入官方示例的创建草稿代码后依然报错。
报错信息
ERROR: Traceback (most recent call last): File "C:\Users\carlo\PycharmProjects\pythonProject3\quickstart.py", line 61, in gmail_create_draft() File "C:\Users\carlo\PycharmProjects\pythonProject3\quickstart.py", line 25, in gmail_create_draft creds, _ = google.auth.default() File "C:\Users\carlo\PycharmProjects\pythonProject3\venv\lib\site-packages\google\auth_default.py", line 616, in default raise exceptions.DefaultCredentialsError(_HELP_MESSAGE) google.auth.exceptions.DefaultCredentialsError: Could not automatically determine credentials. Please set GOOGLE_APPLICATION_CREDENTIALS or explicitly create credentials and re-run the application. For more information, please see <a href="https://cloud.google.com/docs/authentication/getting-started" rel="nofollow noreferrer">https://cloud.google.com/docs/authentication/getting-started</a> Process finished with exit code 1
完整代码
from __future__ import print_function import os.path import base64 from email.message import EmailMessage import google.auth from google.auth.transport.requests import Request from google.oauth2.credentials import Credentials from google_auth_oauthlib.flow import InstalledAppFlow from googleapiclient.discovery import build from googleapiclient.errors import HttpError # If modifying these scopes, delete the file token.json. SCOPES = ['https://www.googleapis.com/auth/gmail.readonly'] def gmail_create_draft(): """Create and insert a draft email. Print the returned draft's message and id. Returns: Draft object, including draft id and message meta data. Load pre-authorized user credentials from the environment. TODO(developer) - See https://developers.google.com/identity for guides on implementing OAuth2 for the application. """ creds, _ = google.auth.default() try: # create gmail api client service = build('gmail', 'v1', credentials=creds) message = EmailMessage() message.set_content('This is automated draft mail') message['To'] = 'carlosmedina239@gmail.com' message['From'] = 'selenytesting123@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() print(F'Draft id: {draft["id"]}\nDraft message: {draft["message"]}') except HttpError as error: print(F'An error occurred: {error}') draft = None return draft if __name__ == '__main__': gmail_create_draft() def main(): """Shows basic usage of the Gmail API. Lists the user's Gmail labels. """ creds = None # The file token.json stores the user's access and refresh tokens, and is # created automatically when the authorization flow completes for the first # time. if os.path.exists('token.json'): creds = Credentials.from_authorized_user_file('token.json', SCOPES) # 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.json', 'w') as token: token.write(creds.to_json()) # You don't have to care about anything on top of this comment try: # Call the Gmail API service = build('gmail', 'v1', credentials=creds) results = service.users().labels().list(userId='me').execute() labels = results.get('labels', []) if not labels: print('No labels found.') return print('Labels:') for label in labels: print(label['name']) except HttpError as error: # TODO(developer) - Handle errors from gmail API. print(f'An error occurred: {error}') if __name__ == '__main__': main()
问题原因及解决方案
核心问题
- 认证方式不匹配:
gmail_create_draft函数使用google.auth.default()(服务账号认证逻辑),但你的代码中main函数采用的是OAuth2授权码流程(桌面应用适用),两种认证方式不兼容。 - 权限范围不足:当前
SCOPES仅设置了gmail.readonly,创建草稿需要gmail.compose权限,权限不足会导致后续操作失败。
修复步骤
统一认证逻辑:将
gmail_create_draft的认证部分替换为和main一致的OAuth2凭据加载逻辑,复用已有的token.json或重新获取授权:def gmail_create_draft(): """Create and insert a draft email. Print the returned draft's message and id. Returns: Draft object, including draft id and message meta data. """ creds = None # 加载已保存的token.json if os.path.exists('token.json'): 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: 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: # create gmail api client service = build('gmail', 'v1', credentials=creds) message = EmailMessage() message.set_content('This is automated draft mail') message['To'] = 'carlosmedina239@gmail.com' message['From'] = 'selenytesting123@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() print(F'Draft id: {draft["id"]}\nDraft message: {draft["message"]}') except HttpError as error: print(F'An error occurred: {error}') draft = None return draft更新权限范围:修改
SCOPES为包含创建草稿的权限,修改后删除原有token.json并重新运行授权:SCOPES = ['https://www.googleapis.com/auth/gmail.compose']调整入口函数:保留
gmail_create_draft的入口,注释或删除main函数的入口,避免运行冲突。
内容的提问来源于stack exchange,提问作者CarlosM239
相关产品推荐
相关产品推荐

