python发送邮件及邮件渲染

最近,公司给了我一个需求,将邮件的渲染方式进行优化,主要的话,其实就是改变邮件中图片的展示方式.

之前,公司的邮件是以html的形式发送的,即邮件中的背景图片是通过超链接来实现的,这样就存在一个问题:

如果以后图片的地址发生了改变,那么想再次查看邮件就变得非常不愉快,因为样式都变了.

所以,图片不能再以超链接的形式进行访问,而是需要将图片当做资源进行发送.

老大给我的提示是将整个邮件转换成eml进行发送.

eml是什么?eml是邮件的通用格式,如果我们去查看邮件的源代码,就可以发现,里面的格式并不是我们属性的html,而是经过编码之后的内容,这就是eml格式.

谷歌一番之后,发现找不到html to eml,只有 eml to html ,可能还是我找的方法有问题

一番挣扎之后,决定退而求其次,只考虑将图片当做资源进行发送.

在这之前,我觉得首先要对邮件格式进行一定的了解

https://www.cnblogs.com/wuyoucao/archive/2017/05/19/6880202.html
https://www.cnblogs.com/zhangxinqi/p/9113859.html

整个邮件体就是 MIMEMultipart(),其他所有的内容都通过attach()包含进里面.

发送图片的话,则需要通过MIMEImage().

首先说一下,就我所知,图片的渲染方式,除了通过超链接,还有两种

1.image data url
将图片进行base64编码,将图片编码后的内容直接插入到src中

for filename in os.listdir(static_files_path):
                fp = open(static_files_path + filename, 'rb')
                # 编码
                imageBinary = base64.b64encode(fp.read())
                index = filename.rindex(".")
                # 将编码后的内容放到字典中,再嵌入到html模板
                template_params[filename[:index]] = str(imageBinary)[2:-1]
 邮件渲染
 #通过 data:image/png;base64 解析
 <img src="https://img-blog.csdnimg.cn/2022010700234272350.png" >
 类似
 <img src="https://img-blog.csdnimg.cn/2022010700234224046.png">

我本来就是这样做的,因为我发现用另一种方法,thunderbird样式会发生错乱,但是老大说,如果图片过大,很有可能会被拦截,邮件展示的话,其实只要兼容大部分网页邮件客户端就行了.
我只好换成下面的方式

  1. cid
    这种方式其实和eml是一样的,给图片资源一个id,然后子在src中通过id去寻找资源,将其渲染出来
            for filename in os.listdir(static_files_path):
                fp = open(static_files_path + filename, 'rb')
                msgImage = MIMEImage(fp.read())
                index = filename.rindex(".")
                #为图片资源分配一个 cid,名字随意,只有模板中能对应起来就行
                msgImage.add_header('Content-ID', filename[:index])
                #内嵌资源 Content-Disposition 应该为online,附件则为 attachment
                msgImage.add_header('Content-Disposition', 'inline')
                template_params[filename[:index]] = filename[:index]
                # 将图片加入邮件体
                msg.attach(msgImage)


      邮件渲染
      #通过 cid 寻找
      <img src="cid:{{ email_header }}" >

这种方式,像thunderbird这种邮件客户端是不兼容的,图片会以附件形式存在.

以下,附上邮件发送的部分代码,但是是根据公司需求的,仅供我以后查看,同学们如果需要也可以参考一下,可能不是很详细


def get_msg(text=None, files=None, static_files_path=None, text_type='plain',
            template=None, template_params=None):
    """
    :param text: 邮件内容(text)
    :param files: 邮件附件(list)
    :param static_files_path: 内嵌图片所在文件夹路径
    :param text_type: 邮件内容的类型,plain为文本类型,hmtl为网页类型
    :param template: 邮件模板地址,使用django template作为模板引擎
    :param template_params:
    :return: 邮件模板的参数(dict)
    """
    template_params = template_params or {}
    try:
        if not isinstance(template_params, dict):
            raise AssertionError('mail tempalte_params must be dict')
        msg = MIMEMultipart()
        if static_files_path:
            for filename in os.listdir(static_files_path):
                fp = open(static_files_path + filename, 'rb')
                msgImage = MIMEImage(fp.read())
                index = filename.rindex(".")
                msgImage.add_header('Content-ID', filename[:index])
                msgImage.add_header('Content-Disposition', 'inline')
                template_params[filename[:index]] = filename[:index]
                msg.attach(msgImage)
        if template:
            mail_template = get_template(template)
            text = mail_template.render(template_params)
        msg.attach(MIMEText(text, text_type))
        for f in files or []:
            with open(f, "rb") as fil:
                part = MIMEApplication(
                    fil.read(),
                    Name=basename(f)
                )
            # After the file is closed
            part['Content-Disposition'] = 'attachment; filename="%s"' % basename(f)
            msg.attach(part)
        return msg
    except Exception as e:
        raise e


def send_mail(send_from, send_to, subject, msg, server_option=None):
    """
    https://stackoverflow.com/questions/3362600/how-to-send-email-attachments#answer-3363254
    :param send_from: 发件人
    :param send_to: 收件人(list)
    :param subject: 邮件主题
    :param msg: 邮件内容对象(MIMEMultipart)
    :param server_option: smtp server配置
        server_option = {
            'host': '127.0.0.1',
            'port': 465,
            'user': 'user',
            'pass': 'pass',
            'ssl': True
        }
    :return:
    """
    server = None
    server_option = server_option or {}
    host = server_option.get('host', '127.0.0.1')
    port = server_option.get('port', '25')
    try:
        if not isinstance(msg, MIMEMultipart):
            raise AssertionError('mail send_to must be MIMEMultipart')
        if not isinstance(send_to, list):
            raise AssertionError('mail send_to must be list')

        msg['From'] = str(send_from)
        msg['To'] = COMMASPACE.join(send_to)
        msg['Date'] = formatdate(localtime=True)
        msg['Subject'] = subject
        if server_option.get('ssl', True):
            server = smtplib.SMTP_SSL(host=host, port=port)
        else:
            server = smtplib.SMTP(host=host, port=port)
        if server_option.get('user'):
            server.login(server_option.get('user'), server_option.get('pass'))
        server.sendmail(send_from, send_to, msg.as_string())
    except Exception as e:
        raise e
    finally:
        if server:
            server.close()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值