You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

排查过程与尝试

我尝试调整多种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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 17:05:18