Python如何在电子邮件中添加多张内嵌图片并搭配对应文本
Python 邮件批量内嵌图片+配套差异化文本实现方案
你现有的单张内嵌图片逻辑可以直接扩展,核心是把单图场景下「生成唯一Content-ID、拼接HTML片段、挂载关联资源」三个步骤放到循环中批量处理即可,不需要修改底层邮件构造逻辑。
核心注意事项
- 每张图片必须分配全局唯一的Content-ID(CID),禁止复用同一个CID,否则所有图片引用都会指向最后一个挂载的资源
- 不要提前写死HTML正文,先遍历素材列表动态拼接每一段「文本+图片」的HTML片段,最后统一组装为完整HTML正文
- 整个邮件只需要调用一次
add_alternative挂载HTML正文,所有图片都作为关联资源挂载到该HTML对应的payload下,不要在循环中重复挂载HTML正文
完整可运行示例代码
from email.message import EmailMessage from email.utils import make_msgid import mimetypes import os # 1. 初始化邮件基础信息 msg = EmailMessage() msg['Subject'] = '未来10天天气预报' msg['From'] = '气象通知 <weather@example.com>' msg['To'] = '用户 <user@example.org>' # 2. 配置纯文本兜底正文 msg.set_content('您的邮箱客户端不支持HTML内容,请升级客户端查看完整天气预报。') # -------------------------- # 3. 准备素材:图片+对应文本的配对列表 # 实际使用时可替换为遍历指定文件夹自动生成的逻辑 # 示例为天气预报场景,每组对应1天的天气描述+天气图标 image_text_pairs = [ {"img_path": "./weather_img/day1.png", "desc": "10月1日:晴,气温16~26℃,东北风2级,适宜外出"}, {"img_path": "./weather_img/day2.png", "desc": "10月2日:多云,气温17~27℃,东风2级,紫外线较强"}, {"img_path": "./weather_img/day3.png", "desc": "10月3日:小雨,气温14~22℃,北风3级,外出请带伞"}, # 可按需追加任意多组图片+文本配对 ] # 如果需要自动遍历文件夹,可参考以下逻辑替换上述列表: # img_dir = "./weather_img/" # desc_list = ["按顺序排列的对应文本1", "按顺序排列的对应文本2", ...] # image_text_pairs = [] # for idx, img_name in enumerate(sorted(os.listdir(img_dir))): # if img_name.lower().endswith(('.png', '.jpg', '.jpeg', '.gif')): # image_text_pairs.append({ # "img_path": os.path.join(img_dir, img_name), # "desc": desc_list[idx] # }) # -------------------------- # 4. 动态拼接HTML正文,收集待挂载的图片资源 html_segments = ["<html><body style='font-family: sans-serif;'>"] to_attach_images = [] for item in image_text_pairs: # 为当前图片生成唯一CID img_cid = make_msgid(domain='example.com') # 拼接当前段落:文本在上,图片在下 html_segments.append( f'<div style="margin: 16px 0; padding-bottom: 12px; border-bottom: 1px solid #eee;">' f'<p style="font-size: 16px; margin: 0 0 8px 0;">{item["desc"]}</p>' f'<img src="cid:{img_cid[1:-1]}" style="max-width: 600px; border-radius: 4px;">' f'</div>' ) # 读取图片二进制数据、识别MIME类型,暂存待挂载 mime_type = mimetypes.guess_type(item["img_path"])[0] maintype, subtype = mime_type.split('/') with open(item["img_path"], 'rb') as f: img_bytes = f.read() to_attach_images.append( (img_bytes, maintype, subtype, img_cid) ) html_segments.append("</body></html>") full_html_content = "\n".join(html_segments) # 5. 挂载HTML正文 msg.add_alternative(full_html_content, subtype='html') # 6. 批量挂载所有内嵌图片 for img_data, maintype, subtype, cid in to_attach_images: msg.get_payload()[1].add_related( img_data, maintype=maintype, subtype=subtype, cid=cid ) # 后续可直接通过smtplib发送邮件,或写入本地eml文件 # with open("weather_forecast.eml", "wb") as f: # f.write(msg.as_bytes())
常见问题排查
- 如果收件方看不到图片:检查CID引用时是否去掉了前后的尖括号(即代码中
cid[1:-1]的处理是否保留),尖括号是CID的标识符,不能直接写到img的src属性里 - 如果所有图片都显示成最后一张:检查是否在循环中重复生成了同一个CID,或CID和图片的对应关系写错
- 如果图片作为附件显示而不是内嵌:检查是否把图片add_related到了正确的payload(即HTML正文对应的payload,索引为1的子节点),不要直接调用
add_attachment方法
内容的提问来源于stack exchange,提问作者zar30
相关产品推荐
相关产品推荐

