Gmail API无法读取SMTP协议发送的邮件问题咨询
问题描述
通过Python脚本使用SMTP协议发送内容为This is an email test的邮件,在Gmail网页端收件箱中可见,但使用Gmail API读取时无法获取到该邮件;而通过Gmail网页发送相同内容的邮件,API可以正常读取并输出正文。
发送邮件的Python代码
def send_email(subject, body): global host, app_password msg = MIMEText(body) msg['Subject'] = subject msg['From'] = host msg['To'] = host with smtplib.SMTP_SSL('smtp.gmail.com', 465) as smtp_server: smtp_server.login(host, app_password) smtp_server.sendmail(host, host, msg.as_string())
读取邮件的Python代码
def get_messages(): # Verify Credentials and Token creds = None if os.path.exists('token.pickle'): with open('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('C:\\my\\path\\to\\credentials\\credentials.json', SCOPES) creds = flow.run_local_server(port=0) with open('token.pickle', 'wb') as token: pickle.dump(creds, token) # Connect to the Gmail API service = build('gmail', 'v1', credentials=creds) result = service.users().messages().list(userId='me').execute() messages = result.get('messages') # Loop through emails try: for msg in messages: txt = service.users().messages().get(userId='me', id=msg['id']).execute() payload = txt['payload'] headers = payload['headers'] # Extract values from data for d in headers: if d['name'] == 'Subject': subject = d['value'] if d['name'] == 'From': sender = d['value'] parts = payload.get('parts')[0] data = parts['body']['data'] data = data.replace("-","+").replace("_","/") decoded_data = base64.b64decode(data) soup = BeautifulSoup(decoded_data, "lxml") body = soup.body() # Output if sender=='Bote <'+host+'>': print(subject) if subject==code: print(body[4:-5]) if back==True: return except: pass
问题原因分析
- 发送者头匹配不匹配:SMTP发送的邮件
From头仅为纯邮箱地址(即host变量的值),但读取代码中硬编码判断sender=='Bote <'+host+'>'——只有网页发送的邮件才会附带Bote这个昵称,因此SMTP发送的邮件直接被过滤,无法进入输出逻辑。 - 邮件结构处理逻辑缺陷:SMTP发送的纯文本邮件(
MIMEText构造),Gmail API返回的payload结构中没有parts字段,正文数据直接存储在payload['body']中。但读取代码强行调用payload.get('parts')[0],会触发索引错误,而宽泛的try-except直接跳过了该邮件的处理,没有任何提示。 - 异常捕获过于宽泛:代码使用
try:... except: pass捕获所有异常,导致结构不匹配、变量未定义等错误都被隐藏,无法定位具体问题。
修复方案
修正发送者判断逻辑
放弃硬编码昵称,改为匹配邮箱地址本身,示例:# 提取sender中的邮箱地址,兼容带昵称和纯邮箱的格式 import re sender_email = re.search(r'<(.+?)>', sender).group(1) if '<' in sender else sender if sender_email == host: print(subject) if subject == code: print(body.get_text()) # 改用get_text()获取正文或者简化判断:
if host in sender: # 后续输出逻辑兼容不同邮件结构
处理正文时先判断是否存在parts字段,兼容纯文本和多部件邮件:# 读取邮件正文数据 if 'parts' in payload: data = payload['parts'][0]['body']['data'] else: data = payload['body']['data'] data = data.replace("-","+").replace("_","/") decoded_data = base64.b64decode(data) soup = BeautifulSoup(decoded_data, "lxml") body = soup.get_text() # 用get_text()替代body(),更稳定获取纯文本内容优化异常处理
仅捕获特定异常或打印错误信息,方便调试:try: # 原有邮件处理逻辑 except Exception as e: print(f"处理邮件ID {msg['id']} 时出错: {str(e)}")可选:指定收件箱标签
调用messages().list()时明确指定读取收件箱邮件,避免遗漏:result = service.users().messages().list(userId='me', labelIds=['INBOX']).execute()
内容的提问来源于stack exchange,提问作者Markas M
相关产品推荐
相关产品推荐

