Tutorial on sending and receiving emails in the Python Flask framework

Source: Internet
Author: User

Tutorial on sending and receiving emails in the Python Flask framework

This article describes how to send and receive emails in the Python Flask framework. It mainly uses the Flask-mail tool in Flask. If you need it, refer

Brief Introduction

In most of these tutorials, we will spare no effort to introduce how to use databases. Today, we will focus on another important feature in web applications, that is, how to push emails to users.

In a lightweight application, we may add the following mail service function: when a user has a new fan, we send an email to notify the user. There are many ways to implement this feature, and we hope to provide a reusable general framework for processing.

Introduction to Flask-Mail

Fortunately for us, there are already many external plug-ins to process emails. Although we can't handle emails exactly as we thought, it's quite close.

Installing Flask-Mail in a virtual environment is quite simple. Users other than Windows can use the following command to install:

?

1

Flask/bin/pip install flask-mail

Windows user installation is slightly different, because some modules used by Flask-Mail cannot run on Windows systems. You can use the following command:

?

1

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

Configuration:

Looking back at the unit test cases in the previous article, we have added the configuration to support the function of notifying us by email when a test of a certain version of the application fails. This example shows how to configure mail support.

Remind everyone that we need to set two aspects:

Email server information

User email address

The following are the configurations used in the previous article.

?

1

2

3

4

5

6

7

8

9

10

# Email server

MAIL_SERVER = 'ur .mailserver.com'

MAIL_PORT = 25

MAIL_USE_TLS = False

MAIL_USE_SSL = False

MAIL_USERNAME = 'you'

MAIL_PASSWORD = 'your-password'

 

# Administrator list

ADMINS = ['you @ example.com ']

No email server or mailbox is available. Now let's take an example to see how to use a gmail account to send Emails:

?

1

2

3

4

5

6

7

8

9

10

# Email server

MAIL_SERVER = 'smtp .googlemail.com'

MAIL_PORT = 465

MAIL_USE_TLS = False

MAIL_USE_SSL = True

MAIL_USERNAME = 'your-gmail-username'

MAIL_PASSWORD = 'your-gmail-password'

 

# Administrator list

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

In addition, we can initialize a Mail object to connect to the SMTP Mail server and send the Mail:

?

1

2

From flask. ext. mail import Mail

Mail = Mail (app)

Try sending an email!

To learn how flask-mail works, we can send an email from the command line. Go to python shell and execute the following script:

?

1

2

3

4

5

6

7

>>> From flask. ext. mail import Message

>>> From app import mail

>>> From config import ADMINS

>>> Msg = Message ('test subobject', sender = ADMINS [0], recipients = ADMINS)

>>> Msg. body = 'text body'

>>> Msg.html = '<B> HTML </B> body'

>>> Mail. send (msg)

The above Code uses the first mailbox as the sender to send an email to all the mailboxes according to the list of email addresses configured in inconfig. py. The email content is displayed in two formats: Text and html, and you can see which format depends on your mail client.

How simple and small! You can integrate it into your application now.

Email framework

Now we can write a help function to send emails. This is a general version of the above test. We put this function into a new original file for mail support (fileapp/emails. py ):

?

1

2

3

4

5

6

7

8

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

Mail. send (msg)

The Mail support for Flask-Mail is beyond our current range of use. features such as BCC and attachments will not be used in this application.

Follower reminder

Now that we have the basic framework for sending emails, we can write the function for sending the follower reminder (fileapp/emails. py ):

?

1

2

3

4

5

6

7

8

9

10

11

From flask import render_template

From config import ADMINS

 

Def follower_notification (followed, follower ):

Send_email ("[microblog] % s is now following you! "% Follower. nickname,

ADMINS [0],

[Followed. email],

Render_template ("follower_email.txt ",

User = followed, follower = follower ),

Render_template ("follower_email.html ",

User = followed, follower = follower ))

Have you found any surprises here? Our old friend render_template function once appeared.

If you still remember, we use this function to render templates in views. Just as it is not good to write html in views, using mail templates is an ideal choice. We may want to separate the logic and performance, so the email template will be put together with other attempt templates in the template folder.

Therefore, we need to write plain text and webpage mail templates for follower reminders. below is the plain text version (fileapp/templates/follower_email.txt ):

?

1

2

3

4

5

6

7

8

9

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 )}}

 

Regards,

 

The microblog admin

The following is a webpage-based email with better results (fileapp/templates/follower_email.html ):

?

1

2

3

4

5

6

7

8

9

10

11

12

13

<P> Dear {user. nickname }}, </p>

<P> <a href = "{url_for (" user ", nickname = follower. nickname, _ external = True) }}" >{{ follower. nickname }}</a> is now a follower. </p>

<Table>

<Tr valign = "top">

<Td> </td>

<Td>

<A href = "{url_for ('user', nickname = follower. nickname, _ external = True) }}" >{{ follower. nickname }}</a> <br/>

{Follower. about_me }}

</Td>

</Tr>

</Table>

<P> Regards, </p>

<P> The <code> microblog </code> admin </p>

Note: The parameter _ external = True of the url_for function in the template. By default, the url generated by the url_for function is relative to our domain name. For example, the returned value of the url_for ("index") function is/index. However, when sending an email, we want a url such as http: // localhost: 5000/index, which has no domain context in the email, therefore, we must generate a url with a domain name, And _ external argument does this.

The last step is to process the "follow" process, that is, the view function for trigger mail notifications (fileapp/views. py ):

?

1

2

3

4

5

6

7

8

9

From emails import follower_notification

 

@ App. route ('/follow/<nickname> ')

@ Login_required

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 there are no users) and try to show one user to another to understand how email reminders work.

Is that true? Are we done?

We may be excited to complete this task and delete the email reminder function from the unfinished list.

However, if you test the application now, you will find that when you click the follow link, the page will respond in 2 to 3 seconds, and the browser will refresh the page, this is not available before.

What happened?

The problem is that Flask-Mail uses synchronous mode to send emails. Starting from sending an email until the email is delivered, the Web server is blocked throughout the process. If we try to send an email to a server slowly or even worse, it is temporarily offline. Can you imagine what will happen? Very bad.

This is a terrible restriction. Sending emails should be background tasks without interfering with the Web server. Let's see how we can solve this problem.

Execute asynchronous calls in Python

We want the send_email function to return immediately after sending the mail. We need to move the mail to the background process for asynchronous execution.

In fact, python already supports asynchronous tasks, but in fact, you can also use other methods, such as threads and multi-process modules, to Implement Asynchronous tasks.

Every time we need to send an email, start a thread to process it, saving resources than starting a new process. Therefore, let's put the mail. send (msg) call into another thread. (Fileapp/emails. py ):

?

1

2

3

4

5

6

7

8

9

10

11

From threading import Thread

 

Def send_async_email (msg ):

Mail. send (msg)

 

Def send_email (subject, sender, recipients, text_body, html_body ):

Msg = Message (subject, sender = sender, recipients = recipients)

Msg. body = text_body

Msg.html = html_body

Thr = threading. Thread (target = send_async_email, args = [msg])

Thr. start ()

If you test the 'follow' function, you will now find that the browser will refresh before sending the email.

Therefore, we have implemented asynchronous transmission. However, if we need other asynchronous functions in the future, do we still need to implement it again?

The process is the same, so there will be repeated code in every situation, this is very bad.

We can improve the Code through decorator. The code for using the decorator is as follows:

?

1

2

3

4

5

6

7

8

9

10

11

From decorators import async

 

@ Async

Def send_async_email (msg ):

Mail. send (msg)

 

Def send_email (subject, sender, recipients, text_body, html_body ):

Msg = Message (subject, sender = sender, recipients = recipients)

Msg. body = text_body

Msg.html = html_body

Send_async_email (msg)

Better, right?

The code to implement this method is actually very simple. Create a new source file (fileapp/decorators. py ):

?

1

2

3

4

5

6

7

From threading import Thread

 

Def async (f ):

Def wrapper (* args, ** kwargs ):

Thr = Thread (target = f, args = args, kwargs = kwargs)

Thr. start ()

Return wrapper

Now we have created a useful framework for asynchronous tasks. We can say it has been done!

Just as an exercise, let's think about why this method seems to use processes rather than threads. We don't want a process to be started whenever we need to send an email, so we can use thePoolclass instead of themultiprocessingmodule. This class will create a specified number of processes (these are the sub-processes of the main process), and these sub-processes will be sent to the process pool through theapply_asyncmethod, waiting to accept the task to work. This may be an interesting way for a busy website, but we will still maintain the current thread mode.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.