Flask 教程,第十一部分:电子邮件 已翻译 100%

oschina 投递于 2012/12/28 09:43 (共 16 段, 翻译完成于 03-06)
阅读 14187
收藏 7

This is the eleventh article in the series in which I document my experience writing web applications in Python using the Flask microframework.

The goal of the tutorial series is to develop a decently featured microblogging application that demonstrating total lack of originality I have decided to callmicroblog.

Here is an index of all the articles in the series that have been published to date:

已有 1 人翻译此段

In the most recent installments of this tutorial we've been looking at improvements that mostly had to do with our database.

Today we are letting our database rest for a bit, and instead we'll look at another important function that most web applications have: the ability to send emails to its users.

In our littlemicroblogapplication we are going to implement one email related function, we will send an email to a user each time he/she gets a new follower. There are several more ways in which email support can be useful, so we'll make sure we design a generic framework for sending emails that can be reused.

已有 1 人翻译此段

Introducing Flask-Mail

Luckily for us, Flask already has an extension that handles email, and while it will not take us 100% of the way, it gets pretty close.

Installing Flask-Mail into our virtual environment is very simple. Users on anything other than Windows do it as follows:

flask/bin/pip install flask-mail

Windows users do it a little different, due to the fact that one of the supporting modules used by Flask-Mail does not work in that OS. On Windows you do this instead:

flask\Scripts\pip install --no-deps lamson chardet flask-mail

已有 1 人翻译此段

Back when we looked at unit testing, we added configuration for Flask to send us an email should an error occur in the production version of our application. It turns out that same information is used for sending application related emails.

Just as a reminder, what we need is two pieces of information:

  • the email server that will be used to send the emails
  • the email address(es) of the admins

This is what we did in the previous article (fileconfig.py):

# email server
MAIL_SERVER = 'your.mailserver.com'
MAIL_PASSWORD = 'your-password'

# administrator list
ADMINS = ['you@example.com']

It goes without saying that you have enter the details of an actual email server and administrator above before the application can actually send emails. For example, if you want the application to send emails via your gmail account you would enter the following:

# email server
MAIL_SERVER = 'smtp.googlemail.com'
MAIL_USERNAME = 'your-gmail-username'
MAIL_PASSWORD = 'your-gmail-password'

# administrator list
ADMINS = ['your-gmail-username@gmail.com']

We also need to initialize aMailobject, as this will be the object that will connect to the SMTP server and send the emails for us (fileapp/__init__.py):

from flask.ext.mail import Mail
mail = Mail(app)

已有 1 人翻译此段
Let's send an email!

To learn how Flask-Mail works we'll just send an email from the command line. So let's fire up Python from our virtual environment and run the following:

>>> from flask.ext.mail import Message
>>> from app import mail
>>> from config import ADMINS
>>> msg = Message('test subject', sender = ADMINS[0], recipients = ADMINS)
>>> msg.body = 'text body'
>>> msg.html = '<b>HTML</b> body'
>>> mail.send(msg)

The snippet of code above will send an email to the list of admins that are configured inconfig.py. The sender will be the first admin in the list. The email will have text and HTML versions, so depending on how your email client is setup you may see one or the other.

Pretty, neat. Now it's time to integrate this code into our application!

已有 1 人翻译此段

A simple email framework

We will now write a helper function that sends an email. This is just a generic version of the above test. We'll put this function in a new source file that will be dedicated to our email support functions (fileapp/emails.py):

from flask.ext.mail import Message
from app import mail

def send_email(subject, sender, recipients, text_body, html_body):
    msg = Message(subject, sender, recipients)
    msg.body = text_body
    msg.html = html_body

Note that Flask-Mail support goes beyond what we are using. Bcc lists and attachments are available, for example, but we won't use them in this application.

已有 1 人翻译此段

Follower notifications

Now that we have the basic framework to send an email in place, we can write the function that sends out the follower notification (fileapp/emails.py):

from flask import render_template
from config import ADMINS

def follower_notification(followed, follower):
    send_email("[microblog] %s is now following you!" % follower.nickname,
            user = followed, follower = follower),
            user = followed, follower = follower))

Do you find any surprises in here? Our old friend therender_templatefunction is making an appearance. If you recall, we used this function to render all the HTML templates from our views. Like the HTML from our views, the bodies of email messages are an ideal candidate for using templates. As much as possible we want to keep logic separate from presentation, so emails will also go into thetemplatesfolder along with our views.

已有 1 人翻译此段

So we now need to write the templates for the text and HTML versions of our follower notification email. Here is the text version (fileapp/templates/follower_email.txt):

Dear {{user.nickname}},

{{follower.nickname}} is now a follower. Click on the following link to visit {{follower.nickname}}'s profile page:

{{url_for("user", nickname = follower.nickname, _external = True)}}


The microblog admin

For the HTML version we can do a little bit better and even show the follower's avatar and profile information (fileapp/templates/follower_email.html):

<p>Dear {{user.nickname}},</p>
<p><a href="{{url_for("user", nickname = follower.nickname, _external = True)}}">{{follower.nickname}}</a> is now a follower.</p>
    <tr valign="top">
        <td><img src="{{follower.avatar(50)}}"></td>
            <a href="{{url_for('user', nickname = follower.nickname, _external = True)}}">{{follower.nickname}}</a><br />
<p>The <code>microblog</code> admin</p>

Note the_external = Trueargument tourl_forin the above templates. By default, theurl_forfunction generates URLs that are relative to the domain from which the current page comes from. For example, the return value fromurl_for("index")will be/index, while in this case we wanthttp://localhost:5000/index. In an email there is no domain context, so we have to force fully qualified URLs that include the domain, and the_externalargument is just for that.

已有 1 人翻译此段

The final step is to hook up the sending of the email with the actual view function that processes the "follow" (fileapp/views.py):

from emails import follower_notification

def follow(nickname):
    user = User.query.filter_by(nickname = nickname).first()
    # ...
    follower_notification(user, g.user)
    return redirect(url_for('user', nickname = nickname))

Now you can create two users (if you haven't yet) and make one follow the other to see how the email notification works.

已有 1 人翻译此段

So that's it? Are we done?

We could now pat ourselves in the back for a job well done and take email notifications out of our list of features yet to implement.

But if you played with the application for some time and payed attention you may have noticed that now that we have email notifications when you click thefollowlink it takes 2 to 3 seconds for the browser to refresh the page, whereas before it was almost instantaneous.

已有 1 人翻译此段
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。


有坑,小心误入,邮件框架部分中msg = Message(subject, sender, recipients)改为
msg = Message(subject, sender=sender, recipients=recipients)方可使用