Files
live-hub-py/test_email_fetch.py
T
2026-06-21 23:02:09 +08:00

203 lines
7.0 KiB
Python

#!/usr/bin/env python3
"""邮箱IMAP读取测试脚本"""
import argparse
import re
import sys
import time
from datetime import datetime, timedelta
from pathlib import Path
# 添加项目根目录到path
sys.path.insert(0, str(Path(__file__).parent))
from douyu.config import Config
from douyu.email_verifier import EmailVerifier
from utils.logger import setup_logger
def mask_email(email_address: str) -> str:
"""隐藏邮箱中间部分,避免控制台泄露完整账号。"""
if "@" not in email_address:
return email_address
name, domain = email_address.split("@", 1)
if len(name) <= 2:
masked_name = name[0] + "*"
else:
masked_name = name[:2] + "*" * max(2, len(name) - 4) + name[-2:]
return f"{masked_name}@{domain}"
def clean_preview(text: str, max_length: int = 120) -> str:
"""清理正文预览,保持输出紧凑。"""
preview = " ".join(text.split())
preview = re.sub(r"\b\d{6}\b", "******", preview)
if len(preview) <= max_length:
return preview
return preview[:max_length] + "..."
def format_code(code: str, show_code: bool) -> str:
"""格式化验证码输出,默认隐藏大部分数字。"""
if not code:
return "未提取到"
if show_code:
return code
return f"****{code[-2:]}"
def format_message_time(verifier: EmailVerifier, msg) -> str:
"""格式化邮件时间。"""
message_time = verifier._parse_message_time(msg)
if not message_time:
return "未知"
return message_time.strftime("%Y-%m-%d %H:%M:%S %z")
def load_account(config_path: str, index: int):
"""从配置文件加载指定账号。"""
config = Config(config_path)
accounts = config.get_accounts()
if not accounts:
raise ValueError("config.yaml 中没有配置账号")
if index < 0 or index >= len(accounts):
raise IndexError(f"账号索引超出范围: {index},当前共有 {len(accounts)} 个账号")
return accounts[index]
def list_recent_messages(
verifier: EmailVerifier,
lookback_minutes: int,
limit: int,
show_code: bool,
) -> None:
"""列出最近邮件,并测试斗鱼验证码解析。"""
verifier.connect()
try:
status, _ = verifier._connection.select(verifier.mailbox, readonly=True)
if status != "OK":
raise RuntimeError(f"选择邮箱目录失败: {verifier.mailbox}")
since_dt = datetime.now() - timedelta(minutes=lookback_minutes)
since = verifier._format_imap_date(since_dt)
status, messages = verifier._connection.search(None, "SINCE", since)
if status != "OK":
raise RuntimeError(f"搜索邮件失败: status={status}")
message_ids = messages[0].split() if messages and messages[0] else []
if not message_ids:
print(f"最近 {lookback_minutes} 分钟没有邮件")
return
recent_ids = list(reversed(message_ids[-limit:]))
print(f"搜索范围: 最近 {lookback_minutes} 分钟")
print(f"匹配邮件数: {len(message_ids)},展示最新 {len(recent_ids)}\n")
for index, message_id in enumerate(recent_ids, start=1):
msg = verifier._fetch_message(message_id)
if not msg:
print(f"[{index}] 读取失败: id={message_id.decode(errors='ignore')}")
continue
subject = verifier._decode_subject(msg.get("Subject", ""))
from_addr = msg.get("From", "")
body = verifier._get_email_body(msg)
is_douyu = verifier._is_douyu_email(subject, from_addr, body)
code = verifier._extract_verification_code(body) if is_douyu else ""
print(f"[{index}] 邮件ID: {message_id.decode(errors='ignore')}")
print(f" 时间: {format_message_time(verifier, msg)}")
print(f" 发件人: {from_addr}")
print(f" 主题: {subject}")
print(f" 斗鱼邮件: {'是' if is_douyu else '否'}")
print(f" 验证码: {format_code(code, show_code)}")
print(f" 正文预览: {clean_preview(body)}\n")
finally:
verifier.disconnect()
def wait_verification_code(
account,
max_wait: int,
interval: int,
new_only: bool,
show_code: bool,
) -> None:
"""等待并提取斗鱼验证码,不负责发送验证码邮件。"""
verifier = EmailVerifier(
imap_server=account.email_imap_server,
imap_port=account.email_imap_port,
username=account.email,
password=account.email_password,
)
after_timestamp = time.time() if new_only else None
code = verifier.get_verification_code(
max_wait=max_wait,
interval=interval,
after_timestamp=after_timestamp,
)
print(f"等待验证码结果: {format_code(code, show_code)}")
def parse_args() -> argparse.Namespace:
"""解析命令行参数。"""
parser = argparse.ArgumentParser(description="测试邮箱IMAP是否能读取邮件和验证码")
parser.add_argument("-c", "--config", default="config.yaml", help="配置文件路径")
parser.add_argument("-i", "--index", type=int, default=0, help="账号索引")
parser.add_argument("--lookback-minutes", type=int, default=30, help="读取最近多少分钟邮件")
parser.add_argument("--limit", type=int, default=5, help="展示最近多少封邮件")
parser.add_argument("--wait-code", action="store_true", help="额外等待并提取斗鱼验证码")
parser.add_argument("--new-only", action="store_true", help="等待验证码时只接受脚本启动后的新邮件")
parser.add_argument("--show-code", action="store_true", help="输出完整验证码")
parser.add_argument("--max-wait", type=int, default=60, help="等待验证码最大秒数")
parser.add_argument("--interval", type=int, default=2, help="验证码轮询间隔秒数")
parser.add_argument("--log-level", default="INFO", help="日志级别")
return parser.parse_args()
def main() -> None:
"""脚本入口。"""
args = parse_args()
setup_logger(level=args.log_level)
account = load_account(args.config, args.index)
print("=== 邮箱IMAP读取测试 ===")
print(f"账号索引: {args.index}")
print(f"邮箱账号: {mask_email(account.email)}")
print(f"IMAP服务器: {account.email_imap_server}:{account.email_imap_port}\n")
verifier = EmailVerifier(
imap_server=account.email_imap_server,
imap_port=account.email_imap_port,
username=account.email,
password=account.email_password,
lookback_minutes=args.lookback_minutes,
max_messages=args.limit,
)
list_recent_messages(
verifier=verifier,
lookback_minutes=args.lookback_minutes,
limit=args.limit,
show_code=args.show_code,
)
if args.wait_code:
print("=== 等待斗鱼验证码 ===")
wait_verification_code(
account=account,
max_wait=args.max_wait,
interval=args.interval,
new_only=args.new_only,
show_code=args.show_code,
)
if __name__ == "__main__":
main()