Django多线程异步发送邮件

Django多线程异步发送邮件

在我们的系统很多地方会使用到发邮件的模块,以前我们使用同步发邮件,但是在很多时候,如果使用同步发邮件的话,在执行完发邮件的程序后,返回值在返回到前台,需要很长的时间等待,这样造成了非常不好体验,所以我们可以采用异步发邮件

这边我们来采用多线程的形式达到异步发邮件的效果

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


在你的app里面新建一个sendemail.py的文件(跟你的views在同一层目录),代码如下:

#coding:utf-8
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 = False):
        self.subject = subject
        self.html_content = html_content
        self.send_from = send_from
        self.to_list = to_list
        self.fail_silently = fail_silently #默认fail_silently=True发送异常不报错
        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_from = settings.DEFAULT_FROM_EMAIL

    send_email = SendHtmlEmail(subject, html_content, send_from, to_list)
    send_email.start() #开启线程,自动运行线程里面的run方法

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设置一下相关的邮件配置。
– 在setting的最后加上如下代码:

#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 #设置发件人

大家配置写好,前面的sendemail.py写好,就可以使用两个方法发邮件:

  • 使用html模板来发邮件

在templates下面新建一个邮件模板,比如在这边我们新建一个directoremail.html的模板

<html xmlns="http://www.w3.org/1999/xhtml"><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>邮件通知</title>
<style type="text/css">
        .ListTable {  border :1px solid #BDBCBC;border-collapse: collapse; width:100%;}
        .ListTable td{ height:50px;font-size:12px;width:16.6%;border:1px  #BDBCBC ;  border-bottom-style:dashed; letter-spacing:1px; line-height:20px;}
        .recordTable {  border :1px solid #BDBCBC;border-collapse: collapse; width:100%;  table-layout:fixed}
        .recordTable td{ height:30px;  font-size:12px;border:1px solid #BDBCBC ;  letter-spacing:1px; text-align:center; }
        .wordbreak{WORD-BREAK: break-all;word-wrap: break-word;}
</style>
</head>
<body>
<div>
 <div style=" margin-top:20px;">
    <table class="recordTable">
       <tr>
           <td style="width:80px;background:#EFEFEF;" align="center" valign="middle">申请人账号</td>
           <td style="width:80px;background:#EFEFEF;" align="center" valign="middle">申请人</td>
           <td style="width:80px;background:#EFEFEF;" align="center" valign="middle">申请类型</td>
           <td style="width:100px;background:#EFEFEF;" align="center" valign="middle">申请内容</td>
           <td style="width:150px;background:#EFEFEF;" align="center" valign="middle">申请时间</td>
       </tr>
       <div style=" margin-top:20px;font-size:12px;">
             {% if emaillists != '' %}
             {% for emaillist in emaillists %}
            <tr>
                <td> {{ emaillist.adaccount }} </td>
                <td> {{ emaillist.displayname }} </td>
                <td>{{ emaillist.applytype }}</td>
                <td>{{  emaillist.applydetail }}</td>
                <td>{{  emaillist.submittime|date:"Y-m-d H:i:s"}}</td>
            </tr>
            {% endfor %}
            {% endif %}
       </div>
    </table>
 </div>
<a href="http://127.0.0.1:8000">请登录</a>
</div>
</body>
</html>


然后在你需要发邮件的程序里面(比如我会在views里面),会调这个发模板的邮件程序,代码如下:

from sendmail import *
def test1(request):

    #其他代码省略了

    #需要查询的数据
    emaillists=showemail(ids)
    #邮件主题
    subject = u'IT审批'
    #模版需要的数据,到html模板里面使用Django的模板系统来显示数据
    email_data={'emaillists':emaillists}
    #模版文件的位置
    template="directoremail.html"
    #收件人列表
    to_list = ['xxx@xx.com', ]
    #根据模版发送邮件
    send_email_by_template(subject,template,email_data,to_list)

这里面的email_data是一个字典类型,里面的数据可以直接在你html模板里面使用
就采用Django的模板来显示数据


  • 直接发送html格式的邮件

例如也可以在你的views里面加如下代码:

def test2(request):

    #其他代码省略了

    #邮件主题
    subject = u'IT审批'
    #html内容
    html_content = u'<p>hello,world!</a>'

    #根据发送html邮件
    send_html_email(subject, html_content, to_list)

这样就可以实现多线程异步发送邮箱。