sync from local backup

This commit is contained in:
chunyu
2026-08-05 23:59:22 +08:00
commit a59f46b894
409 changed files with 166027 additions and 0 deletions
@@ -0,0 +1,139 @@
# 找回密码邮件发送问题修复计划
## 问题描述
用户在找回密码页面输入邮箱后,页面显示发送成功,但实际未收到验证码邮件。
## 根因分析
### 当前代码流程
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. 提供"重新发送"按钮