我的网站搭建(第29天) 多线程异步发送邮件

  • 发布时间:2016年9月7日 11:56
  • 作者:杨仕航
* 该文是基于Python2.7开发的,最新Python3.x和Django2.x视频教程可以前往 >> Django2.0视频教程

之前就有网友反馈在评论的时候会卡一下。原因我知道,只是一直没心思去处理。主要原因是评论或回复之后会发送一封邮件通知被评论或被回复的人。发送邮件这个步骤造成阻塞。

要解决这个问题需要把发送邮件这个步骤变成非阻塞,也就是不用得到发送结果。

再通俗点说,需要改成异步发送邮件

Django异步处理可以用Cerely。但我们这种情况不需要,Cerely配置起来也麻烦。

So~ 我采用多线程的形式达到异步发送邮件的效果。


python中,要定制一个多线程类可以继承threading库中的Thread类,并实现run方法即可。

为了方便管理代码,我决定使用这种方式。代码如下:

#coding:utf-8
"""
    用多线程实现异步发送邮件
    Author: 杨仕航
"""
from django.template import loader
from django.conf import settings

from django.core.mail import EmailMessage
import threading

#继承Thread,需要实现run方法
class SendHtmlEmail(threading.Thread):
    """send html email"""
    def __init__(self, subject, html_content, send_from, to_list, fail_silently = True):
        self.subject = subject
        self.html_content = html_content
        self.send_from = send_from
        self.to_list = to_list
        self.fail_silently = fail_silently #默认发送异常不报错
        threading.Thread.__init__(self)

    def run(self):
        msg = EmailMessage(self.subject, self.html_content, self.send_from, self.to_list)
        msg.content_subtype = "html" # Main content is now text/html
        msg.send(self.fail_silently)

def send_email_by_template(subject, module, data, to_list):
    """
        使用模版发送邮件,发件人默认使用配置的
        subject: string, 主题
        module:  string, 模版名称
        data:    dict,   数据
        to_list: list,   收件人
    """
    html_content = loader.render_to_string(module, data)
    send_html_email(subject, html_content, to_list)

def send_html_email(subject, html_content, to_list):
    """发送html邮件"""
    send_from = settings.DEFAULT_FROM_EMAIL
    send_email = SendHtmlEmail(subject, html_content, send_from, to_list)
    send_email.start()

其中,SendHtmlEmail类是继承了Thread类。

为了其他地方方便使用,再写了两个方法send_email_by_template和send_html_email进一步封装。这两个方法分别作用是用模版发送html邮件和直接发送html邮件。

发件人也是在settings.py中设置好。

在这两个方法中,可以看到用start方法执行线程,则运行线程类中的run方法。


另外,django发送邮件需要在settings.py设置一下相关的邮件配置。

settings.py的邮件配置分3种:

1、常规邮箱配置

#Email设置
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST= 'smtp.qq.com'#以QQ邮箱为例,SMTP服务器(邮箱需要开通SMTP服务)
EMAIL_PORT= 25         #QQ邮箱SMTP服务端口
EMAIL_HOST_USER = '**********@qq.com'  #我的QQ邮箱帐号
EMAIL_HOST_PASSWORD = '**************' #SMTP服务授权码
EMAIL_SUBJECT_PREFIX = 'website' #为邮件标题的前缀,默认是'[django]'
EMAIL_USE_TLS = True #开启安全链接
DEFAULT_FROM_EMAIL = SERVER_EMAIL = EMAIL_HOST_USER #设置发件人

以QQ邮箱为例,想163,新浪都差不多。这些邮箱通常都需要自己再设置中开通SMTP服务。然后获取授权码即可。


2、企业邮箱设置

#Email设置
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST= 'smtp.xxx.com'  #假设企业域名为 xxx.com
EMAIL_PORT= 25         #SMTP服务端口不一定是25。要询问管理人员,或看outlook的设置
EMAIL_HOST_USER = '**********@xxx.com'  #邮箱帐号
EMAIL_HOST_PASSWORD = '**************' #通常是邮箱密码
EMAIL_SUBJECT_PREFIX = 'website
EMAIL_USE_TLS = True #开启安全链接
DEFAULT_FROM_EMAIL = SERVER_EMAIL = EMAIL_HOST_USER #设置发件人

若是企业邮箱,通常要注意smtp发送的端口,不一定是25,可以看看outlook中的设置。EMALL_HOST_PASSWORD一般是邮箱密码。


3、服务器的邮箱服务(这个我不知道怎么归类好,又和前面不同,以WebFaction为例)

#Email设置
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST= 'smtp.webfaction.com'
EMAIL_PORT= 25
EMAIL_HOST_USER = '*********'          #Mailbox的名称
EMAIL_HOST_PASSWORD = '*************'  #Mailbox的密码 默认有SMTP服务
EMAIL_SUBJECT_PREFIX = '[yshblog.com]' #邮件标题前缀,默认是'[django]'
EMAIL_USE_TLS = True
DEFAULT_FROM_EMAIL = SERVER_EMAIL = '*****@yshblog.com' #发件人的邮箱地址

这种和企业邮箱比较类似。因为我的服务器是WebFaction的,第三方的邮箱不给用。只能用它赠送的邮箱。需要在管理界面开通Mailbox。


大家根据具体情况,设置即可。

写好前面的多线程异步发送邮件之后,就可以再需要发送html邮件的地方引用此处的函数,直接使用即可。

例如,我把这个文件保存在根目录的help文件夹中,命名为email.py。然后在某个views.py中使用

from help.email import send_email_by_template, send_html_email

def test1(request):
    """发送邮件测试"""
    #其他逻辑代码就省略了
    
    #邮件主题
    subject = u'[杨仕航的博客]博文评论'
    #模版需要的数据
    email_data = {'comment_name' : '测试', 'comment_content' : '评论内容',}
    #模版文件的位置
    template = 'email/comment.html'
    #收件人列表
    to_list = ['xxx@xx.com', ]
    
    #根据模版发送邮件
    send_email_by_template(subject, template, email_data, to_list)
    
def test2(request):
    """发送邮件测试"""
    #其他逻辑代码就省略了
    
    #邮件主题
    subject = u'[杨仕航的博客]博文评论'
    #html内容
    html_content = u'<p>有人评论了你的博文:</p><a href="#">博文标题</a>'
    
    #根据发送html邮件
    send_html_email(subject, html_content, to_list)


这样就可以实现多线程异步发送邮箱。我再修改对应发送邮件的地方之后,测试确实不会像之前因发送邮件造成阻塞了。

上一篇:我的网站搭建(第30天) 第三方登录:Github

下一篇:我的网站搭建(第28天) 第三方登录:新浪微博

相关专题: Django评论库开发   

评论列表

智慧如你,不想发表一下意见吗?

新的评论

清空