如何用smtplib和imaplib实现保留原始内容的邮件回复
实现带原始内容的邮件回复(基于smtplib/imaplib)
第一步:读取目标邮件(以Gmail/Exchange为例)
用imaplib连接邮箱服务器,获取邮件原始字节数据后,通过email模块解析为可操作的邮件对象。
import imaplib from email.parser import BytesParser from email.policy import default def fetch_email(imap_host, imap_user, imap_pass, email_id): # 连接IMAP服务器 with imaplib.IMAP4_SSL(imap_host) as imap: imap.login(imap_user, imap_pass) imap.select('INBOX') # 可替换为其他邮箱文件夹 # 获取邮件原始内容 _, data = imap.fetch(email_id, '(RFC822)') raw_email = data[0][1] # 解析为EmailMessage对象 msg = BytesParser(policy=default).parsebytes(raw_email) return msg
- Gmail的IMAP地址为
imap.gmail.com,Exchange/Outlook为outlook.office365.com - Gmail开启两步验证后,需使用应用专用密码登录,不能用普通密码
第二步:构建带原始内容的回复邮件
核心是关联原始邮件的标识头,同时拼接新HTML内容与引用格式的原始邮件内容。
from email.message import EmailMessage import re def build_reply(original_msg, new_html_content, sender_email): reply_msg = EmailMessage(policy=default) # 处理回复主题 original_subject = original_msg['Subject'] or '' reply_msg['Subject'] = f'Re: {original_subject}' if not original_subject.startswith('Re: ') else original_subject # 设置收件人、发件人 reply_msg['To'] = original_msg['From'] reply_msg['From'] = sender_email # 关联原始邮件(确保邮件客户端识别为回复) original_msg_id = original_msg['Message-ID'] if original_msg_id: reply_msg['In-Reply-To'] = original_msg_id reply_msg['References'] = f"{original_msg['References'] or ''} {original_msg_id}".strip() # 提取原始邮件的纯文本内容(优先取plain text,无则转换HTML为文本) def get_original_text(msg): if msg.is_multipart(): for part in msg.walk(): if part.get_content_type() == 'text/plain': return part.get_content() # 无纯文本时,简单去除HTML标签提取文本 for part in msg.walk(): if part.get_content_type() == 'text/html': return re.sub(r'<[^>]+>', '', part.get_content()) else: return re.sub(r'<[^>]+>', '', msg.get_content()) if msg.get_content_type() != 'text/plain' else msg.get_content() # 将原始内容转为Gmail风格的引用格式 quoted_original = '\n'.join([f'> {line}' for line in get_original_text(original_msg).splitlines()]) # 拼接最终HTML内容:新内容 + 分割线 + 引用的原始邮件 final_html = f""" {new_html_content} <hr> <div style="color:#666;"> <p>---------- 原始邮件 ----------</p> <pre style="white-space:pre-wrap;">{quoted_original}</pre> </div> """ reply_msg.set_content(final_html, subtype='html') return reply_msg
第三步:发送回复邮件
通过smtplib连接SMTP服务器,发送构建好的回复邮件。
import smtplib def send_reply(smtp_host, smtp_port, smtp_user, smtp_pass, reply_msg): # 针对Exchange/Outlook的587端口(STARTTLS),需替换为SMTP+starttls with smtplib.SMTP_SSL(smtp_host, smtp_port) as smtp: smtp.login(smtp_user, smtp_pass) smtp.send_message(reply_msg)
- Exchange/Outlook的SMTP端口为587,需修改发送代码:
with smtplib.SMTP(smtp_host, smtp_port) as smtp: smtp.starttls() smtp.login(smtp_user, smtp_pass) smtp.send_message(reply_msg)
完整使用示例
# 配置信息(替换为你的实际内容) USER_EMAIL = 'your-email@example.com' USER_PASS = 'your-password-or-app-password' # Gmail配置 IMAP_HOST = 'imap.gmail.com' SMTP_HOST = 'smtp.gmail.com' SMTP_PORT = 465 # Exchange/Outlook配置 # IMAP_HOST = 'outlook.office365.com' # SMTP_HOST = 'smtp.office365.com' # SMTP_PORT = 587 # 要回复的邮件ID(可通过imap.search获取,示例为已知ID) EMAIL_ID = '12345' # 自定义HTML回复内容 new_html = """ <h3>您好!</h3> <p>这是我的HTML格式回复,可以添加 <strong>加粗文本</strong> 或 <span style="color:blue">彩色文字</span>。</p> """ # 执行流程 original_msg = fetch_email(IMAP_HOST, USER_EMAIL, USER_PASS, EMAIL_ID) reply_msg = build_reply(original_msg, new_html, USER_EMAIL) send_reply(SMTP_HOST, SMTP_PORT, USER_EMAIL, USER_PASS, reply_msg)
注意事项
- 若需保留原始邮件的HTML格式而非转为纯文本引用,可直接提取原始HTML内容并添加引用样式,但可能存在样式冲突,需自行调整
- 可通过
imap.search(None, 'SUBJECT "目标主题"')等条件筛选邮件ID,无需手动指定 - 企业Exchange可能需管理员开启IMAP/SMTP服务权限
内容的提问来源于stack exchange,提问作者黃郁暉
相关产品推荐
相关产品推荐

