修复验证码提取到旧邮件的问题

问题:HTTP读邮件接口返回最新一封邮件,但可能是之前其他账号的旧验证码。
日志显示提取到485932(06-22的)和242740(25分钟前的),提交后报邮箱验证码错误。

根因:
1. 时间解析正则匹配到了HTML标签'</label>'前缀,导致parsedate_to_datetime失败
2. 解析失败后保守'纳入候选',导致旧验证码被使用

修复:
- 先清理HTML标签再提取时间
- 支持RFC2822格式和YYYY-MM-DD HH:MM:SS格式
- 解析失败时保守'拒绝'(而不是纳入候选),避免使用旧验证码
- 5项时间解析测试全部通过
This commit is contained in:
yml2213
2026-06-23 01:34:57 +08:00
parent 5a4805814f
commit c1c9d186d1
+36 -8
View File
@@ -144,25 +144,53 @@ class EmailVerifier:
检查邮件时间是否晚于验证码发送时间。
HTTP 接口返回的 HTML 中包含 "发信时间: Tue, 23 Jun 2026 01:06:09 +0800"
但可能被 HTML 标签包裹,如 "</label> Tue, 23 Jun 2026 01:06:09 +0800"
"""
# 提取发信时间
from email.utils import parsedate_to_datetime
time_match = re.search(r'发信时间:\s*(.+?)[\r\n<]', content)
# 先清理 HTML 标签,再提取时间
clean = re.sub(r'<[^>]+>', ' ', content)
clean = re.sub(r'\s+', ' ', clean)
# 匹配 RFC2822 格式时间:Day, DD Mon YYYY HH:MM:SS ±HHMM
time_match = re.search(
r'发信时间[:]?\s*'
r'((?:Mon|Tue|Wed|Thu|Fri|Sat|Sun),\s*\d{1,2}\s+'
r'(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+'
r'\d{4}\s+\d{2}:\d{2}:\d{2}\s*[+-]\d{4})',
clean,
)
if not time_match:
# 找不到时间,保守认为足够新
logger.debug("邮件中未找到发信时间,保守纳入候选")
return True
# 也尝试匹配不带星期的时间格式:2026-06-23 01:31:38
time_match2 = re.search(
r'发信时间[:]?\s*(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2})',
clean,
)
if time_match2:
time_str = time_match2.group(1).strip()
try:
from datetime import datetime
msg_time = datetime.strptime(time_str, '%Y-%m-%d %H:%M:%S')
if msg_time.timestamp() < after_timestamp - allow_old_seconds:
logger.debug(f"邮件时间 {time_str} 早于发送时间,跳过旧邮件")
return False
return True
except ValueError:
pass
# 找不到时间且无法解析,保守拒绝(避免使用旧验证码)
logger.debug("邮件中未找到可解析的发信时间,保守拒绝")
return False
time_str = time_match.group(1).strip()
try:
from datetime import datetime
msg_time = parsedate_to_datetime(time_str)
if msg_time and msg_time.timestamp() < after_timestamp - allow_old_seconds:
logger.debug(f"邮件时间 {time_str} 早于发送时间,跳过旧邮件")
return False
return True
except (TypeError, ValueError):
logger.debug(f"无法解析邮件时间: {time_str},保守纳入候选")
return True
logger.debug(f"无法解析邮件时间: {time_str},保守拒绝")
return False
def _extract_verification_code(self, text: str) -> Optional[str]:
"""从文本中提取6位验证码"""