Python调用Gmail API发送内嵌图片邮件时附件显示异常求助
问题:Gmail API发送内嵌图片时收件箱误显示为附件
最近遇到一个棘手问题:用Python调用Gmail API发送带有内嵌图片(主要是页脚或社交媒体图标)的邮件时,出现异常表现:收件箱列表中这些内嵌图片会被标记为附件,但打开邮件后看不到附件,图片本身能正常内嵌显示。主流邮件服务商都存在这个问题,只是表现略有不同。
初始实现代码与MIME层级
我使用Python标准MIME库及EmailMessage对象,初始代码如下:
html_text = MIMEText(message_str, 'html') html_part = MIMEMultipart('related') html_part.attach(html_text) for attachment in attachments: mime_attachment = MIMEImage(base64.b64decode(attachment.get('data')), _subtype=attachment.get('type')) mime_attachment.add_header('Content-ID', f'<{attachment.get("name")}>') mime_attachment.add_header('Content-Disposition', 'inline', filename=f'{attachment.get("name")}') mime_attachment.add_header('Content-Transfer-Encoding', 'base64') html_part.attach(mime_attachment) root_message = EmailMessage() root_message.make_mixed() root_message.attach(html_part)
对应的MIME层级结构:
- multipart/mixed
- multipart/related
- text/html
- image/png
- multipart/related
排查过程与尝试
我尝试调整多种MIME类型和层级,生成MIME消息后转字节、base64编码再通过Gmail API发送。Gmail显示的原始消息中MIME类型正确,图片部分的头信息如下:
--00000000000064aaa005efdc1b1b Content-Type: image/png; name="9a57c8bb80784228ae77975a659f83c6.png" Content-Disposition: inline; filename="9a57c8bb80784228ae77975a659f83c6.png" Content-Transfer-Encoding: base64 Content-ID: <9a57c8bb80784228ae77975a659f83c6> X-Attachment-Id: cb9a6d0733ed31c7_0.0.2
我试过调整MIME层级、使用EmailMessage.add_attachment方法,但问题始终存在:有时收件箱不显示附件,但打开邮件后图片被包含在message/rfc822类型的base64编码附件中。
限制条件:无法使用外部托管图片,也不能将图片转为base64直接嵌入HTML,且该功能此前正常运行。
重构后的代码
我重构了代码,手动创建MIMEPart payload、尝试add_attachment,并测试了mixed/alternative/related的各种组合,仍未解决问题。更新后的代码如下:
# 创建存放HTML和图片的容器(alternative部分和图片在此) related_part = MIMEMultipart('related') # 创建存放HTML和纯文本的容器 alternative_part = MIMEMultipart('alternative') # 创建MIMEText对象存储HTML内容 html_text = MIMEText(message_str, 'html') alternative_part.attach(html_text) # 将alternative部分加入related,层级结构: # * multipart/related # * multipart/alternative # * html/text related_part.attach(alternative_part) # 添加内嵌图片,最终层级: # * multipart/related # * multipart/alternative # * html/text # * image/png for attachment in attachments: mime_attachment = MIMEImage(base64.b64decode(attachment.get('data')), _subtype=attachment.get('type')) mime_attachment.add_header('Content-ID', f'<{attachment.get("name")}>') mime_attachment.add_header('Content-Disposition', 'inline') #filename=f'{attachment.get("name")}.{attachment.get("type")}') mime_attachment.add_header('Content-Transfer-Encoding', 'base64') related_part.attach(mime_attachment) # 创建根EmailMessage root_message = EmailMessage(EmailPolicy(utf8=True)) root_message.make_mixed() # 将related部分加入根消息,层级: # * multipart/mixed # * multipart/related # * multipart/alternative # * html/text # * image/png root_message.attach(related_part) root_message['To'] = f"{recipient_name} <{recipient_email}>" root_message['From'] = f"{self.sender_name} <{self.sender_email}>" root_message['Subject'] = subject_str return { 'raw': base64.urlsafe_b64encode(root_message.as_bytes()).decode() }
通过Google API客户端发送的代码:
service.users().messages().send(userId="me", body=mail_data).execute()
我已将该问题上报至Google问题追踪器。
内容的提问来源于stack exchange,提问作者Bram van Ulden
相关产品推荐
相关产品推荐

