Django 3.1.1 auth模块:如何触发密码重置邮件生成并成功发送
解决密码重置邮件发送问题及调用生成邮件函数的方法
一、先配置Django邮件后端(必做)
要让Django能发送邮件,第一步得在settings.py里配置邮件服务。以常用的SMTP为例:
# settings.py # 邮件后端配置 EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' # 替换为你的邮件服务商SMTP地址,比如QQ邮箱是smtp.qq.com,Gmail是smtp.gmail.com EMAIL_HOST = 'smtp.example.com' EMAIL_PORT = 587 EMAIL_USE_TLS = True # 你的邮箱账号 EMAIL_HOST_USER = 'your-email@example.com' # 邮箱授权码(不是登录密码,比如QQ/163邮箱需要单独生成授权码) EMAIL_HOST_PASSWORD = 'your-email-authorization-code' DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
如果只是测试用,也可以用文件后端,邮件会存在本地目录里:
EMAIL_BACKEND = 'django.core.mail.backends.filebased.EmailBackend' EMAIL_FILE_PATH = '/tmp/django-emails' # 自定义存放邮件的目录
二、修复现有视图的问题(让邮件正常发送)
你现在的视图核心问题是:父类PasswordResetView的post方法依赖request.POST获取邮箱,但你的请求是JSON格式,导致后端拿不到邮箱参数,既没触发邮件发送,还返回了模板内容。修改post方法如下:
class ResetPasswordView(SuccessMessageMixin, PasswordResetView): template_name = 'users/password_reset.html' email_template_name = 'users/password_reset_email.html' subject_template_name = 'users/password_reset_subject' success_message = "We've emailed you instructions for setting your password, " \ "if an account exists with the email you entered. You should receive them shortly." \ " If you don't receive an email, " \ "please make sure you've entered the address you registered with, and check your spam folder." success_url = reverse_lazy('users-home') @method_decorator(csrf_exempt) def dispatch(self, request, *args, **kwargs): request.csrf_processing_done = True return super().dispatch(request, *args, **kwargs) def post(self, request, *args, **kwargs): # 解析JSON请求里的邮箱 try: data = json.loads(request.body) except json.JSONDecodeError: return JsonResponse({'error': 'Invalid JSON'}, status=400) email = data.get('username') if not email: return JsonResponse({'error': 'Email is required'}, status=400) # 把邮箱参数放到request.POST里,让父类方法能正常获取 request.POST = request.POST.copy() request.POST['email'] = email # 调用父类post方法,此时能正确触发邮件发送逻辑 super().post(request, *args, **kwargs) # 给API请求返回JSON响应,而不是模板 return JsonResponse({'message': self.success_message}, status=200)
注意:你原来写的reset_password_template_name不是PasswordResetView的属性,父类用的是template_name,所以这个配置可以删掉。
三、直接调用Django生成密码重置邮件的函数
如果不想依赖PasswordResetView,想手动控制邮件生成逻辑,有两种常用方式:
方式1:用PasswordResetForm的save方法(推荐)
这是Django封装好的逻辑,会自动生成重置链接、渲染邮件模板并发送:
from django.contrib.auth.forms import PasswordResetForm from django.conf import settings def send_password_reset_email(email): form = PasswordResetForm({'email': email}) if form.is_valid(): # 生成重置链接并发送邮件 form.save( request=None, # 不需要request的话传None,会用settings.SITE_DOMAIN生成链接 use_https=settings.USE_HTTPS, email_template_name='users/password_reset_email.html', subject_template_name='users/password_reset_subject', from_email=settings.DEFAULT_FROM_EMAIL, )
直接调用这个函数就能发送重置邮件。
方式2:手动生成token并构建邮件
如果需要更灵活的自定义,可以手动生成重置token,自己构建邮件内容:
from django.contrib.auth.tokens import default_token_generator from django.core.mail import send_mail from django.contrib.auth.models import User from django.utils.http import urlsafe_base64_encode from django.utils.encoding import force_bytes from django.template.loader import render_to_string from django.conf import settings def send_custom_password_reset_email(email): try: user = User.objects.get(email=email, is_active=True) except User.DoesNotExist: return # 生成重置链接需要的uid和token uid = urlsafe_base64_encode(force_bytes(user.pk)) token = default_token_generator.make_token(user) # 构建你的密码重置页面链接 reset_url = f"{settings.SITE_DOMAIN}/reset/{uid}/{token}/" # 渲染邮件主题和内容 email_subject = render_to_string('users/password_reset_subject').strip() email_body = render_to_string('users/password_reset_email.html', { 'user': user, 'reset_url': reset_url, 'uid': uid, 'token': token, }) # 发送邮件 send_mail( subject=email_subject, message=email_body, from_email=settings.DEFAULT_FROM_EMAIL, recipient_list=[email], fail_silently=False, )
内容的提问来源于stack exchange,提问作者Dave
相关产品推荐
相关产品推荐

