异步发送邮件
app.py
import os from threading import Thread
import sendgrid from sendgrid.helpers.mail import Email as SGEmail, Content, Mail as SGMail from flask_mail import Mail, Message from flask_wtf import FlaskForm from wtforms import StringField, TextAreaField, SubmitField from wtforms.validators import DataRequired, Email from flask import Flask, flash, redirect, url_for, render_template, request
app = Flask(name) app.jinja_env.trim_blocks = True app.jinja_env.lstrip_blocks = True
app.config.update( SECRET_KEY=os.getenv('SECRET_KEY', 'secret string'), MAIL_SERVER=os.getenv('MAIL_SERVER'), MAIL_PORT=465, MAIL_USE_SSL=True, MAIL_USERNAME=os.getenv('MAIL_USERNAME'), MAIL_PASSWORD=os.getenv('MAIL_PASSWORD'), MAIL_DEFAULT_SENDER=('Grey Li', os.getenv('MAIL_USERNAME')) )
mail = Mail(app)
send over SMTP
def send_smtp_mail(subject, to, body): message = Message(subject, recipients=[to], body=body) mail.send(message)
send over SendGrid Web API
def send_api_mail(subject, to, body): sg = sendgrid.SendGridAPIClient(apikey=os.getenv('SENDGRID_API_KEY')) from_email = SGEmail('Grey Li noreply@helloflask.com') to_email = SGEmail(to) content = Content("text/plain", body) email = SGMail(from_email, subject, to_email, content) sg.client.mail.send.post(request_body=email.get())
send email asynchronously
def _send_async_mail(app, message): with app.app_context(): mail.send(message)
def send_async_mail(subject, to, body): # app = current_app._get_current_object() # if use factory (i.e. create_app()), get app like this message = Message(subject, recipients=[to], body=body) thr = Thread(target=_send_async_mail, args=[app, message]) thr.start() return thr
send email with HTML body
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)
class EmailForm(FlaskForm): to = StringField('To', validators=[DataRequired(), Email()]) subject = StringField('Subject', validators=[DataRequired()]) body = TextAreaField('Body', validators=[DataRequired()]) submit_smtp = SubmitField('Send with SMTP') submit_api = SubmitField('Send with SendGrid API') submit_async = SubmitField('Send with SMTP asynchronously')
class SubscribeForm(FlaskForm): name = StringField('Name', validators=[DataRequired()]) email = StringField('Email', validators=[DataRequired(), Email()]) submit = SubmitField('Subscribe')
@app.route('/', methods=['GET', 'POST']) def index(): form = EmailForm() if form.validate_on_submit(): to = form.to.data subject = form.subject.data body = form.body.data if form.submit_smtp.data: send_smtp_mail(subject, to, body) method = request.form.get('submit_smtp') elif form.submit_api.data: send_api_mail(subject, to, body) method = request.form.get('submit_api') else: send_async_mail(subject, to, body) method = request.form.get('submit_async')
代码语言:javascript复制 flash('Email sent %s! Check your inbox.' % ' '.join(method.split()[1:]))
return redirect(url_for('index'))
form.subject.data = 'Hello, World!'
form.body.data = 'Across the Great Wall we can reach every corner in the world.'
return render_template('index.html', form=form)
@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)
@app.route('/unsubscribe') def unsubscribe(): flash('Want to unsubscribe? No way...') return redirect(url_for('subscribe'))
subscribe.html
{% extends 'base.html' %} {% from 'macros.html' import form_field %}
{% block content %} <h2>Flask Weekly</h2> <p>A free weekly newsletter featuring curated news, articles, new releases, jobs etc related to Flask. </p> <p>Delivery at every Wednesday morning.</p> <p>Unsubscribe at any time.</p> <form method="post"> {{ form.csrf_token }} {{ form_field(form.name, placeholder='Your Name') }} {{ form_field(form.email, placeholder='Your Email') }} {{ form.submit(class='btn') }} </form> {% endblock %}
index.html
{% extends 'base.html' %} {% from 'macros.html' import form_field %}
{% block content %} <h2>Send an Email to Yourself</h2> <p>or subscribe <a href="{{ url_for('subscribe') }}">the fake newsletter</a></p>
<form method="post"> {{ form.csrf_token }} {{ form_field(form.to, placeholder='zorn@example.com') }} {{ form_field(form.subject, size=30) }} {{ form_field(form.body, rows=5, cols=50) }} {{ form.submit_smtp(class='btn') }} {{ form.submit_api(class='btn') }} {{ form.submit_async(class='btn') }} </form> {% endblock %}
macros.html
{% macro form_field(field) %} {{ field.label }} {% if field.flags.required -%} {{ field(required='required', kwargs) }} {%- else -%} {{ field(kwargs) }} {%- endif %} {% if field.errors -%} {% for error in field.errors -%} <small class="error">{{ error }}</small> {%- endfor %} {%- endif %} {% endmacro %}
base.html
<!DOCTYPE html> <html> <head> {% block head %} <meta charset="utf-8"> <title>{% block title %}Email - HelloFlask{% endblock %}</title> <link rel="icon" type="image/x-icon" href="{{ url_for('static', filename='favicon.ico') }}"> {% block styles %} <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='style.css' ) }}"> {% endblock %} {% endblock %} </head> <body> <nav> <ul> <li><a href="{{ url_for('index') }}">Home</a></li> </ul> </nav>
<main> {% for message in get_flashed_messages() %} <div class="alert"> {{ message }} </div> {% endfor %} {% block content %}{% endblock %} </main> <footer> {% block footer %} <small> © 2018 <a href="http://greyli.com" title="Written by Grey Li">Grey Li</a> / <a href="https://github.com/greyli/helloflask" title="Fork me on GitHub">GitHub</a> / <a href="http://helloflask.com" title="A HelloFlask project">HelloFlask</a> </small> {% endblock %} </footer> {% block scripts %}{% endblock %} </body> </html>
emails/subscribe.html subscribe.txt
<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) }}">unsubscribe</a>. </small> </div>
subscribe.txt
Hello {{ name }},
Thank you for subscribing Flask Weekly! Enjoy the reading :)
Visit this link to unsubscribe: {{ url_for('unsubscribe', _external=True) }}
static/style.css
body { margin: auto; width: 750px; }
nav ul { list-style-type: none; margin: 0; padding: 0; 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; }
转载自:https://github.com/greyli/