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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 17:18:20