# 找回密码邮件发送问题修复计划 ## 问题描述 用户在找回密码页面输入邮箱后,页面显示发送成功,但实际未收到验证码邮件。 ## 根因分析 ### 当前代码流程 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 ```python 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` 调用后检查返回结果 - 如果同步发送失败,返回更明确的错误信息 - 添加日志记录发送状态 ```python 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` **修改**: - 发送成功后提示用户检查垃圾邮件箱 - 如果发送失败,提示用户稍后重试 ```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. 提供"重新发送"按钮