Django框架中使用Celery异步发送邮件

(1)邮箱设置
Django框架中使用Celery异步发送邮件
(2)在新页面中点击“客户端授权密码”,勾选“开启”,弹出新窗口填写手机验证码。
Django框架中使用Celery异步发送邮件
(3)填写授权码(授权码不能和登录密码一致)
Django框架中使用Celery异步发送邮件
(4)提示开启成功
Django框架中使用Celery异步发送邮件
(5)打开Django项目settings.py文件,配置如下

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
# 163邮箱smtp服务器地址
EMAIL_HOST = 'smtp.163.com'
# 端口
EMAIL_PORT = 25
# 发送邮件的邮箱(设置授权码的邮箱)
EMAIL_HOST_USER = '[email protected]'
# 在邮箱中设置的客户端授权密码
EMAIL_HOST_PASSWORD = 'XXXXXX'
# 收件人看到的发件人
# XXXX:收件人收到邮件时看到的信息
# < >里面的内容必须和发送邮件的邮箱一致
EMAIL_FROM = 'XXXX<[email protected]>'

(6)添加路由处理

from django.conf.urls import url
from user.views import RegisterView, ActivateView

urlpatterns = [
	url(r'^register/$', RegisterView.as_view(), name='register'),  # 用户注册
	url(r'^active/(?P<token>.*)$' ActiveView.as_view(), name='active'),  # 邮件**
]

(7)在user应用下的views.py文件中新建类视图RegisterView进行注册

from user.models import User
from django.shortcuts import render,redirect
from django.conf import settings
from django.views.generic import View

from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
from .tasks import SendEmailTask


# /user/register
class RegisterView(View):
    '''注册'''
    def get(self, request):
        '''显示注册页面'''
        return render(request, 'register.html')

    def post(self, request):
        '''进行注册处理'''
        # 接收数据
        username = request.POST.get('user_name')
        password = request.POST.get('pwd')
        email = request.POST.get('email')
        # 是否同意协议
        allow = request.POST.get('allow')

        # 进行数据校验
        if not all([username, password, email]):
            # 数据不完整
            return render(request, 'register.html', {'errmsg': '数据不完整'})

        # 校验邮箱
        if not re.match(r'^[a-z0-9][\w.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
            return render(request, 'register.html', {'errmsg': '邮箱格式不正确'})

        if allow != 'on':
            return render(request, 'register.html', {'errmsg': '请同意协议'})

        # 校验用户名是否重复
        try:
            user = User.objects.get(username=username)
        except User.DoesNotExist:
            # 用户名不存在
            user = None

        if user:
            # 用户名已存在
            return render(request, 'register.html', {'errmsg': '用户名已存在'})

        # 进行业务处理: 进行用户注册
        user = User.objects.create_user(username, email, password)
        user.is_active = 0
        user.save()

        # 发送**邮件,包含**链接: http://127.0.0.1:8000/user/active/3
        # **链接中需要包含用户的身份信息(我们选择用户id), 并且要把身份信息进行加密

        # 加密用户的身份信息,生成**token
        # settings.SECRET_KEY:django框架自己使用的秘钥字符串
        serializer = Serializer(settings.SECRET_KEY, 3600)
        info = {'confirm':user.id}
        token = serializer.dumps(info) # bytes
        token = token.decode()

        # 发邮件(使用celery异步发送)
        SendEmailTask.apply_async(args=(email, username, token))

        # 返回应答, 跳转到首页
        return redirect(reverse('goods:index'))

(8)在user应用下创建tasks.py文件用于存放发送邮件任务函数

from django.core.mail import send_mail
from django.conf import settings

from celery.task import Task


class SendEmailTask(Task):
	def run(to_email, username, token):
	    '''发送**邮件'''
	    # 组织邮件信息
	    subject = 'XXX欢迎信息'
	    message = ''
	    sender = settings.EMAIL_FROM
	    receiver = [to_email]
	    html_message = '<h1>%s, 欢迎您成为XXX注册会员</h1>请点击下面链接**您的账户<br/><a href="http://127.0.0.1:8000/user/active/%s">http://127.0.0.1:8000/user/active/%s</a>' % (username, token, token)
		#             主题     正文       发件人       收件人列表
		# send_mail(subject, message, from_eamil, recipient_list)
		# 如果正文中包含html标签则会被转义,所以需要使用 html_message 来接收
	    send_mail(subject, message, sender, receiver, html_message=html_message)
	    time.sleep(5)

(9)在settings.py文件同级目录创建celeryconfig.py,存放celery配置文件

import djcelery


# 加载django中注册的应用中的任务(例如我们此项目中user应用中的tasks.py任务)
djcelery.setup_loader()


# 导入应用中任务文件
CELERY_IMPORTS = (
    'user.tasks',
)


# 有些情况下可以防止死锁
CELERYD_FORCE_EXECV = True

# 设置并发的worker数量
CELERYD_CONCURRENCY = 4

# 设置失败允许重试
CELERYD_ACKS_LATE = True

# 每个worker最多执行100个任务被销毁,可以防止内存泄漏
CELERYD_MAX_TASKS_PER_CHILD = 100

# 单个任务的最大运行时间,超时会被杀死
CELERYD_TASK_TIME_LIMIT = 12 * 30

(10)在settings中注册celery

# 注册应用中添加我们的course应用和要使用的异步队列应用djcelery
INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'djcelery',  # 注册djcelery
    'user',  
)

# 导入celery配置信息
from .celeryconfig import *

# 以下配置可以放在celeryconfig.py文件中,但为了方便配置,放在settings文件中更好
BROKER_BACKEND = 'redis'
BROKER_URL = 'redis://localhost:6379/1'
CELERY_RESULT_BACKEND = 'redis://localhost:6379/2'

(11)在user应用下的views.py文件中新建类视图ActiveView进行**处理

from django.http import HttpResponse
from user.models import User

from itsdangerous import TimedJSONWebSignatureSerializer as Serializer


# /user/active
class ActiveView(View):
    '''用户**'''
    def get(self, request, token):
        '''进行用户**'''
        # 进行解密,获取要**的用户信息
        serializer = Serializer(settings.SECRET_KEY, 3600)
        try:
            info = serializer.loads(token)
            # 获取待**用户的id
            user_id = info['confirm']

            # 根据id获取用户信息
            user = User.objects.get(id=user_id)
            user.is_active = 1
            user.save()

            # 跳转到登录页面
            return redirect(reverse('user:login'))
        except SignatureExpired as e:
            # **链接已过期
            return HttpResponse('**链接已过期')

(12)启动celery

python3 manage.py celery worker -l info