Gmail API发送测试邮件出现AttributeError与NameError错误求助
报错原因定位
你遇到的两个报错根源如下:
File "c:\Development\foodSaver\emailAPI.py", line 20, in send_message
message = (service.users().messages().send(userId=user_id, body=message).execute())
AttributeError: 'str' object has no attribute 'users'
这个错误是因为send_message函数要求第一个入参是初始化完成的Gmail API服务实例,但你传入的是字符串'Gmail',字符串自然没有users方法。
处理上述异常时发生另一个异常:
Traceback (most recent call last): File
"c:\Development\foodSaver\emailAPI.py", line 28, in
send_message('Gmail', 'Person','yes') File "c:\Development\foodSaver\emailAPI.py", line 23, in send_message
except errors.HttpError as error: NameError: name 'errors' is not defined
这个错误是因为你没有导入Google API客户端的errors模块,代码中引用的errors属于未定义变量。
除此之外你还存在几个核心问题:
- 没有加载Credentials.json生成授权凭证的逻辑,无法通过Gmail API的身份校验
- 调用
create_message生成的消息对象没有保存就直接丢弃,调用send_message时传入了无意义的'yes'作为消息参数 create_message中base64编码后返回的是bytes类型,需要转成字符串才能被API识别
修复步骤
- 先安装所需依赖包
pip install google-api-python-client google-auth-httplib2 google-auth-oauthlib
- 使用修正后的完整代码,注意将代码中发件人、收件人等参数替换为你自己的真实值
from email import encoders from email.mime.base import MIMEBase from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText import base64 import os from googleapiclient.discovery import build from googleapiclient import errors from google_auth_oauthlib.flow import InstalledAppFlow from google.auth.transport.requests import Request from google.oauth2.credentials import Credentials # 如果修改授权范围,需要删除本地已生成的token.json文件 SCOPES = ['https://www.googleapis.com/auth/gmail.send'] # 初始化Gmail服务实例 def get_gmail_service(): creds = None # 本地保存的授权token,第一次运行会自动生成 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()) return build('gmail', 'v1', credentials=creds) # 构造gmail消息 def create_message(sender, to, subject, message_text): message = MIMEText(message_text) message['to'] = to message['from'] = sender message['subject'] = subject raw_message = base64.urlsafe_b64encode(message.as_string().encode("utf-8")) # 把bytes转成字符串 return {'raw': raw_message.decode("utf-8")} # 发送gmail消息 def send_message(service, user_id, message): try: message = service.users().messages().send(userId=user_id, body=message).execute() print('Message Id: %s' % message['id']) return message except errors.HttpError as error: print('An error occurred: %s' % error) if __name__ == '__main__': # 先获取Gmail服务实例 service = get_gmail_service() # 生成消息对象 message = create_message('abittar@nyit.edu','abittar@nyit.edu','This is a test email.','This is the test body message.') # 发送邮件,userId填'me'就代表当前授权的账号 send_message(service, 'me', message)
- 确认你的
credentials.json文件放在项目根目录下,第一次运行代码会自动打开浏览器让你登录谷歌账号授权,授权完成后就会自动发送邮件。
内容的提问来源于stack exchange,提问作者abittar2022

