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

140 lines
4.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 找回密码邮件发送问题修复计划
## 问题描述
用户在找回密码页面输入邮箱后,页面显示发送成功,但实际未收到验证码邮件。
## 根因分析
### 当前代码流程
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. 提供"重新发送"按钮