django学习-32.发送满足【邮件正文值为一个html页面+有多个附件】的单个邮件

目录结构

1.写这篇博客的目的

2.完整操作流程

2.1.第一步:在【settings.py】里新增邮箱配置信息

2.2.第二步:在【helloworld/hello/views.py】里新增视图函数

2.3.第三步:在【helloworld/helloworld/urls.py】里新增url匹配规则

2.4.第四步:重启服务

2.5.第五步:任一浏览器上输入url地址【http://192.168.1.81:8000/send_email_004/】进行访问后,查看结果

3.相关知识点

3.1.类EmailMultiAlternatives里的方法【__init__】的源码简单分析

3.2.类EmailMultiAlternatives里的方法【attach_file】的源码简单分析

3.3.类EmailMultiAlternatives里的方法【attach】的源码简单分析

3.4.每个应用的资源存放位置

 

 

 

1.写这篇博客的目的

主要记录如何通过django来实现这个功能:发送满足【邮件正文值为一个html页面+有多个附件】的单个邮件;

发送满足【邮件正文值为一个html页面+有多个附件】的单个邮件,可以使用类EmailMultiAlternative;

类EmailMultiAlternative提供了三个方法:attach_file()、attach_alternative()、send(),这三个方法的主要作用分别是:

  • attach_file()的主要作用:把指定的一个文件当做邮件附件;
  • attach_alternative()的主要作用:使邮件正文为一个指定的html页面;
  • send()的主要作用:执行发送邮件的动作;

 

完整操作流程可以看接下来的内容;

 

2.完整操作流程

2.1.第一步:在【settings.py】里新增邮箱配置信息

# 下面的代码都是我个人新增的,不是djano框架默认生成的;
# 1.1.配置qq邮箱信息
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'  # 值必须为这个
EMAIL_USE_SSL = True                         # SSL加密方式,值必须为True
EMAIL_HOST = 'smtp.qq.com'                   # 发送邮件的qq邮箱的SMTP服务器
EMAIL_PORT = 465                             # QQ邮箱对应的SMTP服务器端口
EMAIL_HOST_USER = '[email protected]'         # 发件人
EMAIL_HOST_PASSWORD = 'dwvvnvjerwcvswp'      # qq授权码(不能使用qq密码只能使用qq授权码)
EMAIL_FROM = '洪景盛<[email protected]>'       # 邮件显示的发件人

2.2.第二步:在【helloworld/hello/views.py】里新增视图函数

def send_email_004(request):
    '''发送【邮件正文值为一个html页面+有多个邮件附件】的单个邮件'''

    email = EmailMultiAlternatives(
                                    subject    = "这是邮件的邮件标题(发送【邮件正文值为一个html页面+有多个邮件附件】的单个邮件)",
                                    body       = "这是邮件的正文",
                                    from_email = "[email protected]",     # 发件人
                                    to         = ["[email protected]","[email protected]"],# 收件人邮箱可以是任意的不限个数的邮箱
                                    )

    root_route= os.path.dirname(os.path.realpath(__file__))  # 应用【hello】的根目录
    # print(root_route)

    # 邮件附件里的第一个附件为:一个html页面【这是html页面噢.html】
    route_1 = os.path.join(root_route,"public","html","test","这是html页面噢.html")
    email.attach_file(path=route_1)


    # 邮件附件里的第二个附件为:一个pdf【202101持续测试白皮书v1.0-Lite.pdf】
    route_2 = os.path.join(root_route,"public","pdf","test","202101持续测试白皮书v1.0-Lite.pdf")
    email.attach_file(path=route_2)

    # 邮件附件里的第三个附件为:一个图片【1.jpg】
    route_3 = os.path.join(root_route,"public","picture","test","1.jpg")
    email.attach_file(path=route_3)

    # 邮件附件里的第四个附件为:一个txt【这是txt文档哦.txt】
    route_4 = os.path.join(root_route,"public","txt","test","这是txt文档哦.txt")
    email.attach_file(path=route_4)

    # 邮件附件里的第五个附件为:一个视频【从21楼拍的海边风景视频.mp4】
    route_5 = os.path.join(root_route,"public","video","test","从21楼拍的海边风景视频.mp4")
    email.attach_file(path=route_5)

    # 邮件附件里的第六个附件为:一个word【这是word文档噢.docx】
    route_6 = os.path.join(root_route,"public","word","test","这是word文档噢.docx")
    email.attach_file(path=route_6)

    # 邮件附件里的第七个附件为:一个图片【2.jpg】
    # route_7 = os.path.join(root_route,"public","picture","test","2.jpg")
    # img_data = open(route_7,"rb")
    # email.attach(filename="2.jpg",content=img_data.read(),mimetype="image/jpg")

    # attach方法使用起来比较复杂,attach_file方法使用起来很方便,所以后续都只使用attach_file方法;

    html_content = '''
                    <!DOCTYPE HTML>
                    <html>
                    <head>
                        <meta charset="UTF-8">
                        <title>带图片的邮件</title>
                    </head>
                    <body>
                    这是第一张图片,点击图片后可跳转到我的博客首页<br>
                    <a href="https://www.cnblogs.com/xiamen-momo/" target="_blank">
                        <p>
                        <img src="http://www.w3school.com.cn/i/eg_chinarose.jpg" height="100" width="200" />
                        </p>
                    </a>
                    <p>
                    这是第二张图片,点击后不会触发任何跳转效果<br>
                    <img src="http://www.w3school.com.cn/i/eg_chinarose.jpg" height=200 width=400 />
                    </p>
                    </body>
                    </html>
                '''

    email.attach_alternative(content=html_content,mimetype="text/html")  
# 1.当使用了
attach_alternative方法,EmailMultiAlternatives类里的初始化入参body的值就不会生效了,即邮件正文为指定的一个html页面;
# 2.当没使用attach_alternative方法,EmailMultiAlternatives类里的初始化入参body的值就会生效了,即邮件正文为指定的body值(body值的数据类型是字符串);
    email.send() 

return HttpResponse("【邮件正文值为一个html页面+有多个邮件附件】的单个邮件,发送成功啦!")

2.3.第三步:在【helloworld/helloworld/urls.py】里新增url匹配规则

url(r"^send_email_004/$",views.send_email_004),

2.4.第四步:重启服务

2.5.第五步:任一浏览器上输入url地址【http://192.168.1.81:8000/send_email_004/】进行访问后,查看结果

 

3.相关知识点

3.1.类EmailMultiAlternatives里的方法【__init__】的源码简单分析

class EmailMultiAlternatives(EmailMessage):
    """
    A version of EmailMessage that makes it easy to send multipart/alternative
    messages. For example, including text and HTML versions of the text is
    made easier.
    """
    alternative_subtype = 'alternative'

    def __init__(self, subject='', body='', from_email=None, to=None, bcc=None,
                 connection=None, attachments=None, headers=None, alternatives=None,
                 cc=None, reply_to=None):
        """
        Initialize a single email message (which can be sent to multiple
        recipients).
        """
        super().__init__(
            subject, body, from_email, to, bcc, connection, attachments,
            headers, cc, reply_to,
        )
        self.alternatives = alternatives or []

方法【__init__】里的几个主要入参的分析:

  • subject: (必填,数据类型为字符串)邮件标题;
  • body: (必填,数据类型为字符串)邮件正文;
  • from_email: (非必填,数据类型为字符串)发件邮箱;
  • to: (非必填,数据类型为列表)列表中每个值都是一个接收邮件的邮箱地址;

3.2.类EmailMultiAlternatives里的方法【attach_file】的源码简单分析

    def attach_file(self, path, mimetype=None):
        """
        Attach a file from the filesystem.

        Set the mimetype to DEFAULT_ATTACHMENT_MIME_TYPE if it isn't specified
        and cannot be guessed.

        For a text/* mimetype (guessed or specified), decode the file's content
        as UTF-8. If that fails, set the mimetype to
        DEFAULT_ATTACHMENT_MIME_TYPE and don't decode the content.
        """
        path = Path(path)
        with path.open('rb') as file:
            content = file.read()
            self.attach(path.name, content, mimetype)

从方法【attach_file】的源码可以大概看出来,其实方法【attach_file】是对方法【attach】的进一步封装;

3.3.类EmailMultiAlternatives里的方法【attach】的源码简单分析

    def attach(self, filename=None, content=None, mimetype=None):
        """
        Attach a file with the given filename and content. The filename can
        be omitted and the mimetype is guessed, if not provided.

        If the first parameter is a MIMEBase subclass, insert it directly
        into the resulting message attachments.

        For a text/* mimetype (guessed or specified), when a bytes object is
        specified as content, decode it as UTF-8. If that fails, set the
        mimetype to DEFAULT_ATTACHMENT_MIME_TYPE and don't decode the content.
        """
        if isinstance(filename, MIMEBase):
            assert content is None
            assert mimetype is None
            self.attachments.append(filename)
        else:
            assert content is not None
            mimetype = mimetype or mimetypes.guess_type(filename)[0] or DEFAULT_ATTACHMENT_MIME_TYPE
            basetype, subtype = mimetype.split('/', 1)

            if basetype == 'text':
                if isinstance(content, bytes):
                    try:
                        content = content.decode()
                    except UnicodeDecodeError:
                        # If mimetype suggests the file is text but it's
                        # actually binary, read() raises a UnicodeDecodeError.
                        mimetype = DEFAULT_ATTACHMENT_MIME_TYPE

            self.attachments.append((filename, content, mimetype))

截取这部分源码:

            mimetype = mimetype or mimetypes.guess_type(filename)[0] or DEFAULT_ATTACHMENT_MIME_TYPE
            basetype, subtype = mimetype.split('/', 1)

从这部分源码可以简单看出来:当入参mimetype值为None,django会自动根据附件文件名来推测MIME内容类型的值并赋值给入参mimetype,然后入参mimetype的新值做后续相关处理;

 

3.4.每个应用的资源存放位置

什么是资源?比如:一个图片、一个html页面、一个css、一个js、一个视频、一个pdf、一个word、一个txt,等等这些都是不同的资源类型;

每个项目的应用都有对应所属的资源,那么每个应用的资源存放位置要怎么定呢?怎么定的思路,个人做法主要是这个思路步骤:

  • 第一步:每个应用的资源存放位置定为在每个应用根目录下的某个手动新增的文件夹,比如该新增的文件夹名为【public】;      
  • 第二步:在文件夹【public】里按不同的资源类型新增对应不同的文件夹,比如新增的文件夹名为【css】和【word】;
  • 第三步:在文件夹【word】里按不同的数据表/按不同的业务模块新增对应不同的文件夹,比如新增的文件夹名为【user】和【test】;

这样的思路步骤的主要目的是:每个应用的资源在各自应用目录里维护,大大减少项目代码的耦合度,方便后续维护;

以一个应用【hello】为例,应用【hello】的资源存放位置所对应的具体的文件层级结构大概如下:

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章