flask 电子邮件进阶实践-用模板发送163邮件
电子邮件进阶实践
下面来学习构建邮件的HTML正文,并使用模板组织内容。
一封电子邮件的正文可以是纯文本(text/plain),也可以是HTML格式的文本(text/html)。处于全面的考虑,一封邮件应该既包含纯文本正文又包含HTML格式的正文。HTML格式的正文将被优先读取;加入收信人的邮件系统比较古老,无法读取HTML格式的邮件,则会读取纯文本格式的正文。
下面来学习如何编写HTML邮件正文,以及如何在Flask-Mail中同时提供这两种格式的邮件正文。
如果HTML正文非常简单,比如仅仅在纯文本的基础上添加链接和少量HTML标签,那么不用太在意编写方式。如果想创建更加丰富美观的证件正文,那么会有很多事情需要考虑。出去无法读取HTML正文的古董邮件客户端,大多数主流的邮箱客户端都会HTML邮件有着各种各样的限制。对于HTML邮件正文的编写,下面是一些常见的“最佳实践”:
1) 使用Tabel布局,而不是Div布局
2) 使用行内(inline)样式定义,比如:
<span style = “font-family;Arial, Helvetica, sans-serif; font-size:12px; color:#000000;”>Hello, Email!</span>
3) 尽量使用比较基础的CSS属性,避免使用快捷属性(如background)和定位属性(比如float、position)。
4) 邮件正文的宽度不应超过600px
5) 避免使用JavaScript代码
6) 避免使用背景图片
为了确保邮件显示符合预期,最好提前在各个主流的邮箱客户端以及不同尺寸的设备上进行测试。
在Flask-Mail中,我们使用Message类实例来构建邮件。和纯文本正文类似,HTML正文可以在实例化时传入html参数指定,比如:
message = Message(…, body = ‘纯文本正文’, html=<h1>HTML正文</h1>)
或是通过类属性message.html指定:
message = Message(…)
message.body = ‘纯文本正文’
message.html = ‘<h1>HTML正文</h1>’
使用Jinja2模板组织邮件正文
大多数情况下,我们需要动态构建邮件正文,比如,在周刊订阅程序中,当用户订阅成功后,我们发送一封确认邮件。对于不同的用户来说,邮件的内容基本相同,但同时邮件中又包含用户名称的动态部分,使用模板来组织邮件正文再合适不过。
templates/emails/subscribe.txt: 纯文本邮件模板
Hello {{ name }},
Thank you for subscribing Flask Weekly!
Enjoy the reading :)
Visit this link ro unsubscribe: {{ url_for('unsubscribe', _external = True) }}
为了同时支持纯文本格式和HTML格式的邮件正文,每一类邮件我们都需要分别创建HTML和纯文本格式的模板。对应上面的纯文本模板的HTML格式模板如下:
templates/emails/subscribe.html: HTML邮件模板
<div style="width: 580px; padding: 20px;">
<h3>Hello {{ name }},</h3>
<p>Thank you for subscribing Flask Weekly!</p>
<p>Enjoy the reading :)</p>
<small style="color: #868e96;">
Click here to <a href="{{ url_for('unsubscribe', _external=True) }}"></a>.
</small>
</div>
以通过Flask-Mail创建的发信函数为例,我们在发送邮件的函数中使用render_template()函数渲染邮件正文,并传入相应的变量,如下所示:
from flask import render_template
from flask_mail import Mail, 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实现。
大多数程序需要发送多种不同类型的邮件,我们可以使用模板继承技术来为所有邮件创建一个包含基本样式的基模板。
在模板中发送163邮件:
app.py:
#encoding=utf-8
from flask import Flask, flash, redirect, url_for, render_template
from wtforms import StringField, TextAreaField, SubmitField
from flask_wtf import FlaskForm
from wtforms.validators import DataRequired, Email
from flask import render_template
from flask_mail import Mail, Message
import os app = Flask(__name__)
app.jinja_env.trim_blocks = True
app.jinja_env.lstrip_blocks = True app.config.update(
SECRET_KEY = "SECRET KEY",
MAIL_SERVER = os.getenv('MAIL_SERVER'),
MAIL_PORT = 465,
#MAIL_PORT = 587,
#MAIL_USE_TLS = True,
MAIL_USE_SSL = True,
MAIL_USERNAME = os.getenv('MAIL_USERNAME'),
MAIL_PASSWORD = os.getenv('MAIL_PASSWORD'),
MAIL_DEFAULT_SENDER = (os.getenv('MAIL_USERNAME'))
) mail = Mail(app) def send_mail(subject, to, body):
message = Message(subject, recipients = [to], body = body)
mail.send(message) class SubscribeForm(FlaskForm):
name = StringField('Name', validators=[DataRequired()])
email = StringField('Email', validators = [DataRequired(),Email()]) #Email(): Validates an email address
submit = SubmitField('Subscribe') 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) @app.route('/subscribe', methods = ['GET', 'POST'])
def subscribe():
form = SubscribeForm()
if form.validate_on_submit():
name = form.name.data
email = form.email.data
send_subscribe_mail('Subscribe Success!', email, name = name)
flash('Confirmation email have been sent! Check your inbox.')
return redirect(url_for('subscribe'))
return render_template('subscribe.html', form = form) if __name__ == '__main__':
print app.config
app.run(debug = True)
macros.html:
{% macro form_field(field) %}
{{ field.label }}<br>
{% if field.flags.required -%}
{{ field(required = 'required', **kwargs) }}<br>
{%- else -%}
{{ field(**kwargs) }}<br>
{%- endif %}
{% if field.errors -%}
{% for error in field.errors -%}
<small class="error">{{ error }}</small><br>
{%- endfor %}
{%- endif %}
{% endmacro %}
base.html:
<!DOCTYPE html>
<html lang="en">
<head>
{% block head %}
{% block metas %}
<meta charset="utf-8">
{% endblock metas %}
<title>{% block title %} Form - HelloFlask {% endblock title %}</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='favicon.ico') }}">
{% block styles %}
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='style.css') }}">
{% endblock styles %}
{% endblock head %}
</head>
<body>
<nav>
{% block nav %}
<ul>
<li><a href="{{ url_for('basic') }}">Home</a></li>
</ul>
{% endblock %}
</nav> <main>
{% for message in get_flashed_messages() %}
<div class="alert">
{{ message }}
</div>
{% endfor %}
{% block content %}{% endblock %}
</main>
<footer>
{% block footer %}
<small> © 2019 <a href="https://www.cnblogs.com/xiaxiaoxu/" title="xiaxiaoxu's blog">夏晓旭的博客</a> /
<a href="https://github.com/xiaxiaoxu/hybridDrivenTestFramework" title="Contact me on GitHub">GitHub</a> /
<a href="http://helloflask.com" title="A HelloFlask project">Learning from GreyLi's HelloFlask</a>
</small>
{% endblock %}
</footer>
{% block scripts %}{% endblock %}
</body>
</html>
subscribe.html
{% macro form_field(field) %}
{{ field.label }}<br>
{% if field.flags.required -%}
{{ field(required = 'required', **kwargs) }}<br>
{%- else -%}
{{ field(**kwargs) }}<br>
{%- endif %}
{% if field.errors -%}
{% for error in field.errors -%}
<small class="error">{{ error }}</small><br>
{%- endfor %}
{%- endif %}
{% endmacro %}
templates/emails/subscribe.html:
<div style="width: 580px; padding: 20px;">
<h3>Hello {{ name }},</h3>
<p>Thank you for subscribing Flask Weekly!</p>
<p>Enjoy the reading :)</p>
<small style="color: #868e96;">
Click here to <a href="{{ url_for('subscribe', _external=True) }}"></a>.
</small>
</div>
templates/emails/subscribe.txt:
Hello {{ name }},
Thank you for subscribing Flask Weekly!
Enjoy the reading :)
Visit this link ro unsubscribe: {{ url_for('subscribe', _external = True) }}
static/style.css:
body {
margin: auto;
width: 750px;
}
nav ul {
list-style-type: none;
margin:;
padding:;
overflow: hidden;
background-color: #333;
}
nav li {
float: left;
}
nav li a {
display: block;
color: white;
text-align: center;
padding: 14px 16px;
text-decoration: none;
}
nav li a:hover {
background-color: #111;
}
main {
padding: 10px 20px;
}
footer {
font-size: 13px;
color: #888;
border-top: 1px solid #eee;
margin-top: 25px;
text-align: center;
padding: 20px;
}
.alert {
position: relative;
padding: 0.75rem 1.25rem;
margin-bottom: 1rem;
border: 1px solid #b8daff;
border-radius: 0.25rem;
color: #004085;
background-color: #cce5ff;
}
.btn {
font-size: 14px;
padding: 5px 10px;
text-decoration: none;
cursor: pointer;
background-color: white;
color: black;
border: 2px solid #555555;
}
.btn:hover {
text-decoration: none;
background-color: black;
color: white;
border: 2px solid black;
}
浏览器访问127.0.0.1:5000/subscribe

点击按钮后,稍等几秒钟,会有flash消息提示已经发了邮件了

到邮箱中查看,已经收到

flask 电子邮件进阶实践-用模板发送163邮件的更多相关文章
- flask_mail发送163邮件,报553错误的原因
最近在练习用flask_mail发送163邮件时报错: reply: '553 authentication is required,163 smtp9,DcCowAD3eEQZ561caRiaBA- ...
- 使用python发送163邮件 qq邮箱
使用python发送163邮件 def send_email(title, content): import smtplib from email.mime.multipart import MIME ...
- ABP 用SMTP 发送163邮件
/// <summary> /// 发送 /// </summary> /// <param name="Subject">邮件标题</p ...
- python 发送163邮件
可能还需要使用 邮箱第三方客户端的授权码. 网易163免费邮箱相关服务器信息 from email import encoders from email.header import Header fr ...
- java发送163邮件
在服务挂掉后,可以采用发送邮件的方式来通知开发人员进行异常处理 import java.io.IOException; import java.util.Properties; import java ...
- 模板发送java邮件
Creating email content using a templating library The code in the previous examples explicitly creat ...
- flask 电子邮件Flask-Mail
电子邮件 在web程序中,经常会需要发送电子邮件.比如,在用户注册账户时发送确认邮件:定期向用户发送热门内容或是促销信息等等.在Web程序中发送电子邮件并不复杂,借助扩展Flask-Mail或是第三方 ...
- Selenium自动化发送163邮箱
自动化发送163邮件 方法一: import time import datetime from selenium import webdriver from selenium.webdriver.s ...
- SpringBoot集成Thymeleaf发送Html邮件报错
由于业务需求需要使用Thymeleaf作为模板发送Html邮件,开发调试过程中发生以下错误 org.thymeleaf.exceptions.TemplateInputException: Error ...
随机推荐
- in与exists和not in 与 not exists的区别
1.in 与 exists: 外表大,用IN:内表大,用EXISTS: 原理: 用in:外表使用了索引,直接作hash连接: 用exists:内表使用了索引,外表作loop循环再进行匹配: 2.not ...
- [dev][crypto][strongswan] 有关strongswan的forward policy的源码分析
一 默认情况下,我们使用strongswan建立了一个ipsec隧道之后,建立的policy如下: [root@D129 OUTPUT]# ip xfrm policy src dst dir pty ...
- memcached加固
Memcached服务安全加固 更新时间:2017-06-30 10:07:49 漏洞描述 Memcached是一套常用的key-value缓存系统,由于它本身没有权限控制模块,所以对公网开放的 ...
- delphi odbc远程连接sqlserver
ip设置格式xx.xx.xx.xx,port ip和端口号之间是逗号
- echo 与 printf的区别与联系
echo命令默认是带有换行符的. 如果想让echo命令去掉每一行后面的换行符 方法1; 如果确信自己的脚本程序只运行在bash上,可以使用如下语法来出去空格: echo -n "Is it ...
- node.js爬取ajax接口数据
爬取页面数据与爬取接口数据,我还是觉得爬取接口数据更加简单一点,主要爬取一些分页的数据. 爬取步骤: 1.明确目标接口地址,举个例子 : https://www.vcg.com/api/common/ ...
- 基于ROS的分布式机器人远程控制平台
基于ROS的分布式机器人远程控制平台 1 结构说明 HiBot架构主要使用C/S架构,其中HibotServer为服务器,Muqutte为消息服务器中间件,HiBotClient为运行在机器人上的 ...
- input type = file 在部分安卓手机上无法调起摄像头和相册
移动端H5web 用input type = file 在部分安卓手机上无法调起摄像头拍照,有的也无法访问相册而是直接访问了文档,解决办法是: 加上 accept = "image/*&qu ...
- 正则re
1.简介 其实re在基本模块里已经介绍过,但是在爬虫中re是非常重要的,所以在这里再进行详细描述. re在解析html内容时是效率最高的,但是也是最难的,一般来说,都是结合xpath和re使用,这样解 ...
- Oracle 12C CRS-5013
1.背景 OS:SUSE 12SP3 DB:12.2.0.1.190115 2节点RAC Q:crs alert日志一直刷如下报错 2019-02-12 12:46:18.163 [ORAAGENT( ...