1. 程式人生 > >flask 電子郵件進階實踐-用模板發送163郵件

flask 電子郵件進階實踐-用模板發送163郵件

接收 編寫 radi ren 電子 http 子郵件 **kwargs doctype

電子郵件進階實踐

下面來學習構建郵件的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> &copy; 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: 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;
}

瀏覽器訪問127.0.0.1:5000/subscribe

技術分享圖片

點擊按鈕後,稍等幾秒鐘,會有flash消息提示已經發了郵件了

技術分享圖片

到郵箱中查看,已經收到

技術分享圖片

flask 電子郵件進階實踐-用模板發送163郵件