使用Flask-Mail发送电子邮件
Flask-Mail包装了python标准库中的stmplib包并简化了在flask中发送电子邮件的过程
初始化
安装: pip install flask-mail
初始化:使用flask-mail提供的Mail类并传入实例完成初始化
from flask-mail import Mail
app = Flask(__name__)
mail = Mail(app)
配置Flask-Mail
Flask-mail通过连接SMTP(Simple Mail Transfer Protocol简单邮件传输协议)服务器来发送邮件,因此在发送邮件之前需要配置STMP服务器。可以电脑本地安装stmp服务器, 开发测试阶段可以使用邮件服务提供商的SMTP服务器如gmail、163。
Flask-Mail常用配置变量
配置键 | 说明 | 默认值 |
---|---|---|
MAIL_SERVER | 用于发送邮件的STMP服务器 | localhost |
MAIL_PORT | 发送端口 | 25 |
MAIL_USE_TLS | 是否使用STARTLS | False |
MAIL_USE_SSL | 是否使用SSL/TLS | False |
MAIL_USERNAME | 发送服务器的用户名 | None |
MAIL_PASSWORD | 发送服务器的密码 | None |
MAIL_DEFAULT_SENDER | 默认的发信人,由一个两元素元组组成(姓名,邮箱地址) 。 Flask_Mail会把这个元组转换成标准发信人格式即:姓名 <邮箱地址>。也可以直接使用这个格式指定发信人. | None |
- 对发送的邮件进行加密,可以避免邮件在发送的过程被第三方截获篡改,SSL和TLS是常用的电子邮件安全协议,TSL继承了SSL并在SSL的基础上做了一些改进。因此多数情况下SSL和TSL可以互相转换,通过MAIL_USE_SSL设置为True启用
- STASRTTLS是另外一种加密方式,对不安全的连接进行升级。
根据加密方式不同端口也要相应的改变
#SSL/TSL 加密
MAIL_USE_SSL=True
MAIL_PORT=465
# STARTTSL加密
STARTTSL=True
MAIL_PORT = 587
#不对邮件进行加密时端口使用默认的25
常用的邮件服务商STMP配置信息:
服务商 | MAIL_SERVER | MAIL_USERNAME | MIAL_PASSWORD | 其他 |
---|---|---|---|---|
GMAIL | smtp.gmail.com | 邮箱账号 | 邮箱密码 | 开启allow less secure apps,在本地设置vpn代理 |
QQ邮箱 | smtp.qq.com | 邮箱账号 | 授权码 | 开启STMP服务并获得授权码 |
163邮箱 | smtp.163.com | 邮箱账号 | 授权码 | 开启STMP服务并获得授权码 |
- 163邮箱的SMTP不支持START_TSL,需要使用TSL/SSL。 具体设置为MAIL_USE_SSL=True,MAIL_PORT=465。
发送大量邮件更好的选择是使用自己配置的STMP服务器或使用类似SendGrid、Mailgun的事务性服务提供商(Transactional Email Service)。
大量的配置可以使用app.config()对象的update()方法加载配置。在实例化Mail类时,Flask-Mail会获取配置创建一个用于发信的对象, 因此确保在实例化之前加载配置。 ```python from flask_mail import Mail
app = Flask(name)
app.config.update( MAIL_SERVER=os.getenv(‘MAIL_SERVER’), MAIL_PORT=587, MAIL_USE_TSL=True, MAIL_USERNSAME=os.getenv(‘MAIL_USERNAME’), MAIL_PASSWORD=os.getenv(‘MAIL_PASSWORD’), MAIL_DEFAULT_SENDER=(‘Mike’, os.getenv(‘MAIL_USERNAME’)) #或MAIL_DEFAULT_SENDER=’姓名 <邮箱地址>’。 设置后在发信人可以不用再设置。 )
mail = Mail(app)
铭感信息从环境变量获取, 可以使用set/export设置环境变量,不过建议把这些保存在.env。
<a name="wd4tG"></a>
### 构建邮件数据并发送
- 邮件通过Flask-Mail的Message类表示。
- 一封邮件至少包括主体、收件人、正文、发件人。分别通过Message类中的subject、recipients、body关键字传入参数。其中recipients时一个包含邮件地址的列表
- 发送邮件功能通过实例化的mail对象调用send()方法实现,传入构造的邮件对象。
```python
from flask-mail import Message
from app import mail
message = Message(subject='Hello Email', recipients=['hehe' <hehe.reedo.cn>], body='hello ,test content')
mail.send(message)
抽象成方法调用
#定义send_mail()方法
from flask_mail import Message
from app import mail
def send_mail(subject, to, body):
message=Message(subject=subject, recipients=[to], body = body)
mail.send(message)
#使用,调用send_mail函数即可
使用事物邮件服务SendGrid
在生产环境除了自己安装运行邮件服务器外,更便捷的方法是使用事物邮件服务如Mailgun、sendgrid。
注册sengrid
- 注册:https://sendgrid.com/
- 注册完成后为项目创建一个API密钥。 作为环境变量SENDGRID_API_KEY=’key’。
SendGrid STMP转发
设置STMP服务器
from flask_mail import Mail
app = Flask(__name__)
app.config.update(
MAIL_SERVER=os.getenv('MAIL_SERVER'),
MAIL_PORT=587,
MAIL_USE_TSL=True,
MAIL_USERNSAME=os.getenv('MAIL_USERNAME'),
MAIL_PASSWORD=os.getenv('SENDGRID_API_KEY'),
MAIL_DEFAULT_SENDER=('Mike', os.getenv('MAIL_USERNAME')) #或MAIL_DEFAULT_SENDER='姓名 <邮箱地址>'。 设置后在发信人可以不用再设置。
)
mail = Mail(app)
# 铭感信息从环境变量获取, 可以使用set/export设置环境变量,不过建议把这些保存在.env。
MAIL_SERVER='stmp.sendgrid.net'
MAIL_USERNAME='api key'
SendGrid Web API转发
SendGrid还支持通过它提供的Web API转发邮件, 好处是更安全、速度更快。
- 在程序中向SendGrid提供的WebAPI发出一个POST请求并且附带必要的信息如密钥、邮件主题、收件人、正文等,SendGrid就会为发我们发送邮件。
- 接口URL:
- Authorization首部字段提供相应的API密钥
- 报文主体:JSON格式表示的电子邮件数据。
手动编写发送邮件内容
使用SendGrid提供的SDK(Software Development Kit软件开发工具包)。
安装: pip install sendgrid
构建邮件并发送:
# 1 创建发信对象
from sendgrid import SendGridApiClient
sg = SendGridApiClient(apikey=os.getenv('SENDGRID_API_KEY'))
# 2 构建邮件内容
from sendgrid.helpers.mail import Email, Content, Mail
from = Email('from@reedo.cn', 'Reedo官网') # Email用来创建邮件地址,依次传入邮箱地址和姓名, 3中形式均可
to = Email('user@reedo.cn')
subject = 'hello Email'
content = Content('text/plain', 'email content') #接收MIME类型(type_)和正文value
mail = Mail(from, subject, to , content) #构造邮件对象,分别传入发信人、主题、收信人、正文
#通过mail.get()可以获得邮件内容
# 对sg对象调用sg.client.mail.send.post()方法并用关键字传入邮箱对象即可发送发信的POST请求
sg.client.mail.send.post(request_body=mail.get)
抽象成方法调用
#定义send_mail()方法
from sendgrid import SendGridApiClient
from sendgrid.helpers.mail import Email, Content, Mail
def send_mail( subject, to, body):
from_email = Email('from@email.com', 'Reedo官网')
to = Email(to)
content = Content('text/plain', body)
mail = Mail(from_email, subject, to, content)
sg = SendGridApiClinet(apikey=os.getev('SENDGRID_API_KEY'))
response = sg.mail.send.post(request_body=mail.get())
#使用,调用send_mail函数即可
电子邮件进阶
提供HTML正文
- 一般在HTML邮件中,html和文本都提供,在无法显示html的客户端中显示文本。
- 最佳实践:1 table布局而不使用div,2 行内样式css; 3 宽度不超过600px; 4 不适应js、背景图片。
Flask-Mail中:
Message类中HTML正文可以在实例化时传入html参数指定; 或 通过类属性message.html指定
#1
message = Message(... , body='正文..', html='<h1>标题1 </h1>,html内容')
# 2 方式2
message = Message(...)
message.body = '..'
message.html = '..'
SendGrid-Python中:
使用Content类构造邮件正文中传入的第一个type_参数指定类型
- 如果是html, 则type=’text/html’
- 如果要邮件同时提供这两种格式的文字,则在Mail类构造邮件对象是传入包含两个content类实例的列表多为content的参数值
text_content = Content('text/plain', '文本正文')
html_content = Content('text/html', <h1>html内容</h1>)
mail = Mail(..., content = [text_content, html_content])
使用Jinja2模板组织邮件正文
在发送邮件的函数中使用render_template()函数渲染邮件正文
from flask import render_template
from flask_mail import Message
def send_welcome_mail(subject, to, body, **kwargs):
message = Message(subject, recipients=[to] )
message.body = render_template('email/welcome.txt', **kwargs)
message.html = render_template('email/welcome.html', **kwargs)
mail.send(message)
如果使用SendGrid的WebApi发送邮件,可以使用SendGrid提供的在线模板功能,快速编写邮件正文并支持用特殊语法标记变量。 在程序中发送邮件时传入变量及对应的模板id。
异步发送邮件
from threading import Thread
def _send_async_mail(app, message):
with app.app_context():
mail.send(message) #因为send()在内部调用了current_app变量, 因此需要激活上下文
def send_mail(subject, to , body):
message = Message(subject, recipients = [to], body=body)
thr = Thread(target=_send_asyc_mail, args=[app, message])
thr.start()
return thr