Files
chunyu_prject_react/.trae/documents/fix-forgot-password-email.md
T
2026-08-05 23:59:22 +08:00

4.6 KiB
Raw Blame History

找回密码邮件发送问题修复计划

问题描述

用户在找回密码页面输入邮箱后,页面显示发送成功,但实际未收到验证码邮件。

根因分析

当前代码流程

  1. 用户输入邮箱 → 前端调用 /api/forgot_password_send_code/
  2. 后端 ForgotPasswordSendCodeAPIView 生成验证码并保存到缓存
  3. 调用 submit_task(send_reset_password_email_task, to_email, code) 发送邮件
  4. 前端显示成功

发现的问题

1. Celery Worker 可能未运行

  • 问题:submit_task 函数先尝试 apply_async(异步),如果成功则直接返回
  • 风险:如果 Redis 可达但无 worker 运行,任务会永远留在队列中不被执行
  • 验证:本地测试显示 apply_async 返回 PENDING,说明任务已入队但可能无 worker 消费
  • fallback 机制:submit_task 只在 apply_async 抛异常或超时时才降级为同步 apply

2. QQ Mail 发送限制

  • 问题:QQ Mail 对同一地址发送频率有限制
  • 风险:短时间内多次发送可能被 QQ Mail 服务器静默丢弃
  • 特征:SMTP 连接成功,但邮件未投递

3. 邮件进入垃圾箱

  • 问题:验证码邮件可能被收件方归类为垃圾邮件
  • 风险:用户未检查垃圾邮件箱

修复方案

修复1:确保邮件同步发送(解决 Celery 不可用问题)

文件:utils/safe_task.py

修改:将 submit_task 改为默认同步发送,失败时降级为异步

理由:

  • 验证码邮件需要立即发送,不能依赖 Celery worker 的可用性
  • 同步发送确保邮件立即投递
  • 如果同步失败,再尝试异步作为 fallback
def submit_task(task, *args, **kwargs):
    """发送任务,优先同步执行,失败时降级为异步"""
    try:
        # 优先同步执行,确保立即发送
        return task.apply(*args, **kwargs)
    except Exception as exc:
        logger.warning('sync send failed, fallback to async: %s', exc)
        try:
            return task.apply_async(args, kwargs, kwargs.get('_timeout', SUBMIT_TIMEOUT))
        except Exception as exc2:
            logger.error('async fallback also failed: %s', exc2)
            return None

修复2:增加邮件发送状态反馈

文件:user/views/user.py → ForgotPasswordSendCodeAPIView

修改:

  • 在 submit_task 调用后检查返回结果
  • 如果同步发送失败,返回更明确的错误信息
  • 添加日志记录发送状态
result = submit_task(send_reset_password_email_task, to_email, code)
if result is None:
    logger.warning(f'Reset password email failed to send: {to_email}')
    # 不暴露内部错误给用户,但记录日志

修复3:前端增加提示

文件:src/pages/ForgotPassword/ForgotPassword.tsx

修改:

  • 发送成功后提示用户检查垃圾邮件箱
  • 如果发送失败,提示用户稍后重试
if (res?.code === 10009) {
  message.success(t('forgotPassword.successCodeSent'));
  message.info(t('forgotPassword.checkSpam')); // 新增:提示检查垃圾邮件
  // ...
}

修复4:QQ Mail 发送频率优化(可选)

文件:utils/safe_task.py

修改:

  • 添加发送间隔限制,避免被 QQ Mail 拦截
  • 对同一邮箱,短时间内不重复发送

涉及文件

文件 修改类型 说明
utils/safe_task.py 修改 改为同步优先发送
user/views/user.py 修改 增加发送状态日志
src/pages/ForgotPassword/ForgotPassword.tsx 修改 增加垃圾邮件提示
src/locales/zh.json 修改 添加提示文本

验证步骤

  1. 本地测试

    • 启动 Django 开发服务器
    • 访问找回密码页面
    • 输入已注册邮箱
    • 检查是否收到邮件
    • 检查 Django 日志是否有发送记录
  2. Celery 未运行场景

    • 确保本地无 Celery worker 运行
    • 测试邮件发送是否正常
  3. 同一邮箱多次发送

    • 连续发送3次验证码
    • 检查是否每次都能收到
    • 检查是否有频率限制
  4. 垃圾邮件检查

    • 检查 QQ Mail 垃圾邮件箱
    • 确认邮件是否被归类为垃圾邮件

风险评估

  • 同步发送会增加请求响应时间(约1-2秒),但验证码邮件场景下可接受
  • 如果 SMTP 服务器响应慢,可能导致请求超时
  • 需要监控邮件发送失败率

备选方案

如果同步发送影响性能,可以考虑:

  1. 使用数据库记录发送状态
  2. 前端轮询检查邮件是否发送成功
  3. 提供"重新发送"按钮