Python实现兼容主流邮件客户端的标准邮件转发方法
Python实现兼容主流客户端的标准邮件转发
核心需求
需要基于Python实现邮件转发功能,兼容Evolution、MacOS X Mail、雅虎邮箱等主流邮件客户端,满足以下要求:
- 转发时支持附加自定义文本,说明转发原因
- 收件方收到转发邮件后,可直接查看完整原始邮件内容
注:直接替换原邮件FROM、TO头的简易转发方案无法满足上述兼容性要求。
初始实现版本
最初编写的转发消息构造函数如下:
def make_fwd_msg(orig, from_, to_, orig_text=None, references=True): """Return the message [container] with the description of the forward and the ORIG message""" msg = MIMEMultipart('mixed') msg['SUBJECT'] = 'Fwd: {}'.format(orig['SUBJECT']) if references: msg['REFERENCES'] = orig['MESSAGE-ID'] msg['FROM'] = from_ msg['TO'] = to_ if orig_text: msg.attach(MIMEText(orig_text, 'plain')) alt = MIMEMultipart('alternative') alt.attach(orig) msg.attach(alt) return msg
测试环境
- 操作系统:Debian GNU/Linux 11 (bullseye)
- Python版本:3.9.2
基于上述函数编写的完整测试代码如下,支持选择雅虎或Gmail SMTP服务发送测试邮件:
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import os import email import smtplib import argparse from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText class SMTPYahoo(smtplib.SMTP_SSL): PORT = 465 HOST = 'smtp.mail.yahoo.com' def __init__(self, *args, **kwds): super().__init__(*args, host=self.HOST, port=self.PORT, **kwds) self.user = os.getenv('USER_NAME_EMAIL') self.login(self.user + '@yahoo.com', os.getenv('YAHOO_APP_PWD')) class SMTPGmail(smtplib.SMTP_SSL): PORT = 465 HOST = 'smtp.gmail.com' def __init__(self, *args, **kwds): super().__init__(*args, host=self.HOST, port=self.PORT, **kwds) self.user = os.getenv('USER_NAME_EMAIL') self.login(self.user + '@gmail.com', os.getenv('GMAIL_APP_PWD')) parser = argparse.ArgumentParser(description="""\ Forward message using Yahoo or Gmail mail server""") parser.add_argument('--smtp-server', choices=('yahoo', 'gmail'), type=str, default='yahoo', help="Choose smtp server") parser.add_argument('message_file', type=str, help="A file with the message to forward") parser.add_argument('--verbose', '-v', action='count', default=0) def make_fwd_msg(orig, from_, to_, orig_text=None, references=True): """Return the message [container] with the description of the forward and the ORIG message""" msg = MIMEMultipart('mixed') msg['SUBJECT'] = 'Fwd: {}'.format(orig['SUBJECT']) if references: msg['REFERENCES'] = orig['MESSAGE-ID'] msg['FROM'] = from_ msg['TO'] = to_ if orig_text: msg.attach(MIMEText(orig_text, 'plain')) alt = MIMEMultipart('alternative') alt.attach(orig) msg.attach(alt) return msg if __name__ == '__main__': args = parser.parse_args() if 0 < args.verbose: print(args) smtp_server = (SMTPYahoo if args.smtp_server == 'yahoo' else SMTPGmail)() from_ = smtp_server.user to_ = from_.split('@')[0] + ('@gmail.com' if args.smtp_server == 'yahoo' else '@yahoo.com') with open(args.message_file, 'rb') as fp: orig = email.message_from_bytes(fp.read()) msg = make_fwd_msg(orig, from_, to_, orig_text='<Original text goes here>') try: with smtp_server as s: if 2 < args.verbose: s.set_debuglevel(1) answer = input(f'from_={from_}, to_={to_} send [Y/n]? ') if answer in ('', 'y', 'Y'): s.send_message(msg) except (Exception, smtplib.SMTPDataError) as e: print(e)
在目标客户端开展兼容性测试时发现,不同客户端对该版本生成的转发邮件解析逻辑存在差异,无法保证所有客户端都能正确识别转发结构、正常展示原始邮件,因此需要调整实现对齐RFC标准规范。
优化后合规实现
调整后的实现使用Python 3.6+标准库提供的EmailMessage类构建邮件,将原始邮件以标准message/rfc822类型作为附件挂载,符合RFC规定的转发邮件格式,可被所有主流客户端正确识别。优化后的make_fwd_msg函数如下:
from email.message import EmailMessage def make_fwd_msg(orig, from_, to_, orig_text=None, references=True): """Return the message [container] with the description of the forward and the ORIG message""" msg = EmailMessage() msg['SUBJECT'] = 'Fwd: {}'.format(orig['SUBJECT']) if references: msg['REFERENCES'] = orig['MESSAGE-ID'] msg['FROM'] = from_ msg['TO'] = to_ if orig_text: msg.set_content(orig_text) msg.add_attachment(orig.as_bytes(), maintype='message', subtype='rfc822') return msg
内容的提问来源于stack exchange,提问作者Vladimir Zolotykh
相关产品推荐
相关产品推荐

