赵走x博客
网站访问量:151511
首页
书籍
软件
工具
古诗词
搜索
登录
Flask 实战:41、电子邮件进阶实践
Flask 实战:40、使用事务邮件服务SendGird
Flask 实战:39、使用Flask-Mail发送电子邮件
Flask 实战:38、数据库进阶实践
Flask 实战:37、更新数据库表
Flask 实战:36、定义关系
Flask 实战:35、在视图函数里操作数据库
Flask 实战:34、数据库操作:CRUD
Flask 实战:33、使用Flask-SQLAlchemy管理数据库
Flask 实战:32、ORM魔法
Flask 实战:31、数据库的分类
Flask 实战:30、单个页面多个表单
Flask 实战:29、单个表单多个提交按钮
Flask 实战:28、使用Flask-CKEditor集成富文本编辑器
Flask 实战:27、多文件上传
Flask 实战:26、文件上传
Flask 实战:25、自定义验证器
Flask 实战:24、使用宏渲染表单
Flask 实战:23、设置错误消息语言
Flask 实战:22、处理表单数据
Flask 实战:21、使用Flask-WTF处理表单
Flask 实战:20、HTML表单
Flask 实战:19、模板进阶实践
Flask 实战:18、模板结构组织
Flask 实战:17、模板辅助工具
Flask 实战:16、模板基本用法
Flask 实战:15、HTTP进阶实践
Flask 实战:14、Flask上下文
Flask 实战:13、HTTP响应
Flask 实战:12、HTTP请求
Flask 实战:11、请求响应循环
Flask 实战:10、Flask与MVC架构
Flask 实战:9、模板与静态文件
Flask 实战:8、Flask命令
Flask 实战:7、URL与端点
Flask 实战:6、项目配置
Flask 实战:5、Flask扩展
Flask 实战:4、Python Shell
Flask 实战:3、启动开发服务器
Flask 实战:2、Hello,Flask!
Flask 实战:1、初识Flask
Flask 实战:41、电子邮件进阶实践
资源编号:76089
Python Web
Flask Web开发实战:入门、进阶与原理解析
热度:98
这一节我们会介绍关于电子邮件的进阶内容,你将会了解如何构建邮件的HTML正文,并使用模板来组织内容。
这一节我们会介绍关于电子邮件的进阶内容,你将会了解如何构建邮件的HTML正文,并使用模板来组织内容。 # 1、 提供HTML正文 一封电子邮件的正文可以是纯文本(text/plain),也可以是HTML格式的文本(text/html)。出于更全面的考虑,一封邮件应该既包含纯文本正文又包含HTML格式的正文。HTML格式的正文将被优先读取;假如收信人的邮件系统比较古老,无法读取HTML格式的邮件,则会读取纯文本格式的正文。 这一节我们会介绍如何编写HTML邮件正文,以及如何在Flask-Mail和SendGrid-Python中同时提供这两种格式的邮件正文。 如果HTML正文非常简单,比如仅仅在纯文本的基础上添加链接和少量HTML标签,那么不用太在意编写方式。如果你想创建更加丰富美观的邮件正文,那么会有很多事情需要考虑。除去无法读取HTML正文的古董邮件客户端,大多数主流的邮箱客户端都对HTML邮件有着各种各样的限制。对于HTML邮件正文的编写,下面是一些常见的“最佳实践”: * 使用Tabel布局,而不是Div布局。 * 使用行内(inline)样式定义,比如: ```
Hello, Email!
``` * 尽量使用比较基础的CSS属性,避免使用快捷属性(比如background)和定位属性(比如float、position)。 * 邮件正文的宽度不应超过600px。 * 避免使用JavaScript代码。 * 避免使用背景图片。 为了确保邮件显示符合预期,最好提前在各个主流的邮箱客户端以及不同尺寸的设备上进行测试。 >附注 关于编写HTML邮件正文的更多技巧可以访问https://www.mailup.com/resources-mailup/strategy/strategies-techniques-and-best-practices/creating-a-good-html-email-message/ 了解。另外,Campaign Monitor提供了一个所有主流邮箱客户端支持的CSS属性列表(https://www.campaignmonitor.com/css/ )。 在Flask-Mail中,我们使用Message类实例来构建邮件。和纯文本正文类似,HTML正文可以在实例化时传入html参数指定,比如: ``` message = Message(..., body='纯文本正文', html='
HTML正文
') ``` 或是通过类属性message.html指定: ``` message = Message(...) message.body = '纯文本正文' message.html = '
HTML正文
' ``` 在SendGrid-Python中,使用Content类构建邮件正文时传入的第一个`type_`参数指定了邮件正文的MIME类型,如果你想提供HTML正文,可以将其设为text/html。如果要同时提供这两种格式的正文,那么就在使用Mail类构建邮件数据时传入一个包含两个Content类实例的列表作为正文content的参数值: ``` from sendgrid.helpers.mail import Email, Content, Mail ... text_content = Content("text/plain", "纯文本正文") html_content = Content("text/html", "
HTML正文
") mail = Mail(from_email, subject, to_email, content=[text_content, html_content]) ``` # 2、使用Jinja2模板组织邮件正文 大多数情况下,我们需要动态构建邮件正文。比如,在周刊订阅程序中,当用户订阅成功后,我们发送一封确认邮件。对于不同的用户来说,邮件的内容基本相同,但同时邮件中又包含用户名称的动态部分,使用模板来组织构建邮件正文再合适不过。示例邮件的纯文本正文模板如代码清单6-5所示。 代码清单6-5 templates/emails/subscribe.txt:纯文本邮件模板 ``` Hello {{ name }}, Thank you for subscribing Flask Weekly! Enjoy the reading :) Visit this link to unsubscribe: {{ url_for('unsubscribe', _external=True) }} ``` 为了同时支持纯文本格式和HTML格式的邮件正文,每一类邮件我们都需要分别创建HMTL和纯文本格式的模板。对应上面的纯文本模板的HTML格式模板如代码清单6-6所示。 代码清单6-6 templates/emails/subscribe.html:HTML邮件模板 ```
Hello {{ name }},
Thank you for subscribing Flask Weekly!
Enjoy the reading :)
Click here to
unsubscribe
.
``` 以通过Flask-Mail创建的发信函数为例,我们在发送邮件的函数中使用render_template()函数渲染邮件正文,并传入相应的变量,如下所示: ``` from flask import render_template from flask_mail import Message def send_subscribe_mail(subject, to, **kwargs): message = Message(subject, recipients=[to], sender='Flask Weekly <%s>' % os.getenv('MAIL_USERNAME')) message.body = render_template('emails/subscribe.txt', **kwargs) message.html = render_template('emails/subscribe.html', **kwargs) mail.send(message) ``` 为了支持在调用函数时传入模板中需要的关键字参数,我们在send_mail()中接收可变长关键字参数(**kwargs)并传入render_template()函数。 >注意 当邮件中需要加入URL时(比如链接和图片),注意要生成完整的外部URL,而不是内部URL。这可以通过在url_for()函数中将关键字参数_external设为True实现。 大多数程序需要发送多种不同类型的邮件,我们可以使用模板继承技术来为所有邮件创建一个包含基本样式的基模板。具体我们会在本书的第二部分进行实践。 > 附注 如果使用SendGrid的Web API发送邮件,那么你也可以使用SendGrid提供的功能丰富的在线模板功能(https://sendgrid.com/templates )。使用它可以快速编写格式良好的邮件正文,而且在线模板中也可以使用特殊语法标记变量。当在程序中发送发信时,可以传入这些变量,并根据模板ID来选择对应的模板,具体可以访问SendGrid-Python的文档了解。 # 3、异步发送邮件 当使用SMTP的方式发送电子邮件时,如果你手动使用浏览器测试程序的注册功能,你可能会注意到,在提交注册表单后,浏览器会有几秒钟的不响应。因为这时候程序正在发送电子邮件,发信的操作阻断了请求——响应循环,直到发信的send_mail()函数调用结束后,视图函数才会返回响应。这几秒的延迟带来了不好的用户体验,为了避免这个延迟,我们可以将发信函数放入后台线程异步执行,以Flask-Mail为例,如代码清单6-7所示。 代码清单6-7 email/app.py:异步发送电子邮件 ``` from threading import Thread ... def _send_async_mail(app, message): with app.app_context(): mail.send(message) def send_mail(subject, to, body): message = Message(subject, recipients=[to], body=body) thr = Thread(target=_send_async_mail, args=[app, message]) thr.start() return thr ``` 因为Flask-Mail的send()方法内部的调用逻辑中使用了current_app变量,而这个变量只在激活的程序上下文中才存在,这里在后台线程调用发信函数,但是后台线程并没有程序上下文存在。为了正常实现发信功能,我们传入程序实例app作为参数,并调用app.app_context()手动激活程序上下文。 >提示 在生产环境下,我们应该使用异步任务队列处理工具来处理这类任务,比如Celery(http://www.celeryproject.com )。 如果你运行了示例程序,访问http://localhost:5000 打开程序的主页,如图6-3所示。  图6-3 示例程序主页 >Mark有话说: 注意此时启动时,要让Flask支持多线程,不然上面代码无效,还是要等待,除非这样启动app: ``` app.run(threaded=True) ``` 在测试前,确保在demos/email目录下添加一个.env文件,并保存发送邮件所需要的MAIL_SERVER、MAIL_USERNAME、MAIL_PASSWORD以及SENDGRID_API_KEY变量的值。一切准备就绪后,在表单To字段里填入你的邮箱地址,然后单击下面的按钮发送邮件:Send with SMTP将通过普通的SMTP方式发信;Send with SendGrid API使用SendGrid Web API发信;Send with SMTP asynchronously则会以异步方式通过SMTP发信。 访问http://localhost:5000/subscribe 打开虚构的订阅页面,输入你的名字和邮件,就会收到包含HTML正文的邮件,如图6-4所示。  图6-4 HTML邮件正文 # 本章小结 本章介绍使用Flask-Mail和SendGrid实现在Flask程序中发送简单的电子邮件,如果你需要对邮件实现更多的配置,可以访问这两个工具的官方文档。 至此,本书的第一部分已经结束了,你已经学习了使用Flask开发Web程序的所有基础内容。如果你愿意,可以尝试自己开发一个程序。在本书的第二部分,我们会通过编写几个相对完整和真实的程序来学习更多Flask的进阶技术,同时巩固我们在第一部分学习的基础知识。