Skip to content

Commit b751d65

Browse files
committed
feat(email): update email polling logic to use configurable intervals
1 parent 101169e commit b751d65

12 files changed

Lines changed: 46 additions & 53 deletions

File tree

src/core/register.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737

3838
logger = logging.getLogger(__name__)
3939

40-
OTP_SECONDARY_TIMEOUT_SECONDS = 120
40+
OTP_SECONDARY_TIMEOUT_SECONDS = 120 # 默认值,运行时由 get_settings().email_code_timeout 覆盖
4141
PHASE_EMAIL_PREPARE = "email_prepare"
4242
PHASE_OTP_SECONDARY = "otp_secondary"
4343
ERROR_EMAIL_PROVIDER_RATE_LIMITED = "EMAIL_PROVIDER_RATE_LIMITED"
@@ -646,7 +646,7 @@ def _phase_otp_secondary(
646646

647647
email_id = self.email_info.get("service_id") if self.email_info else None
648648
budget = Budget(
649-
timeout_seconds=OTP_SECONDARY_TIMEOUT_SECONDS,
649+
timeout_seconds=get_settings().email_code_timeout,
650650
started_at=started_at if started_at is not None else time.time(),
651651
)
652652
remaining_timeout = budget.remaining_seconds()

src/services/base.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,21 @@
1313
from enum import Enum
1414

1515
from ..config.constants import EmailServiceType, OTP_CODE_PATTERN, OTP_CODE_SEMANTIC_PATTERN
16+
from ..config.settings import get_settings
1617

1718

1819
logger = logging.getLogger(__name__)
1920

2021
EMAIL_PROVIDER_BACKOFF_BASE_SECONDS = 30
22+
23+
24+
def get_email_code_settings() -> dict:
25+
"""获取验证码等待配置(timeout、poll_interval)"""
26+
settings = get_settings()
27+
return {
28+
"timeout": settings.email_code_timeout,
29+
"poll_interval": settings.email_code_poll_interval,
30+
}
2131
EMAIL_PROVIDER_BACKOFF_MAX_SECONDS = 3600
2232
OTP_TIMEOUT_ERROR_PREFIX = "OTP_TIMEOUT"
2333

src/services/cloud_mail.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from datetime import datetime, timezone
1111
from typing import Any, Dict, List, Optional
1212

13-
from .base import BaseEmailService, EmailServiceError, EmailServiceType, RateLimitedEmailServiceError
13+
from .base import BaseEmailService, EmailServiceError, EmailServiceType, RateLimitedEmailServiceError, get_email_code_settings
1414
from ..config.constants import OTP_CODE_PATTERN
1515
from ..core.http_client import HTTPClient, RequestConfig
1616

@@ -231,6 +231,7 @@ def get_verification_code(
231231
) -> Optional[str]:
232232
logger.info(f"正在从 Cloud Mail 邮箱 {email} 获取验证码...")
233233

234+
poll_interval = get_email_code_settings()["poll_interval"]
234235
start_time = time.time()
235236
seen_mail_ids: set = set()
236237

@@ -252,7 +253,7 @@ def get_verification_code(
252253
mails = mails["list"]
253254

254255
if not isinstance(mails, list):
255-
time.sleep(3)
256+
time.sleep(poll_interval)
256257
continue
257258

258259
for mail in mails:
@@ -288,7 +289,7 @@ def get_verification_code(
288289
except Exception as e:
289290
logger.debug(f"检查 Cloud Mail 邮件时出错: {e}")
290291

291-
time.sleep(3)
292+
time.sleep(poll_interval)
292293

293294
logger.warning(f"等待 Cloud Mail 验证码超时: {email}")
294295
return None

src/services/duck_mail.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from html import unescape
1313
from typing import Any, Dict, List, Optional
1414

15-
from .base import BaseEmailService, EmailServiceError, EmailServiceType, RateLimitedEmailServiceError
15+
from .base import BaseEmailService, EmailServiceError, EmailServiceType, RateLimitedEmailServiceError, get_email_code_settings
1616
from ..config.constants import OTP_CODE_PATTERN
1717
from ..core.http_client import HTTPClient, RequestConfig
1818

@@ -258,6 +258,7 @@ def get_verification_code(
258258
logger.warning(f"DuckMail 邮箱缺少访问 token: {email}")
259259
return None
260260

261+
poll_interval = get_email_code_settings()["poll_interval"]
261262
start_time = time.time()
262263
seen_message_ids = set()
263264

@@ -307,7 +308,7 @@ def get_verification_code(
307308
except Exception as e:
308309
logger.debug(f"DuckMail 轮询验证码失败: {e}")
309310

310-
time.sleep(3)
311+
time.sleep(poll_interval)
311312

312313
return None
313314

src/services/freemail.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import string
1111
from typing import Optional, Dict, Any, List
1212

13-
from .base import BaseEmailService, EmailServiceError, EmailServiceType, RateLimitedEmailServiceError
13+
from .base import BaseEmailService, EmailServiceError, EmailServiceType, RateLimitedEmailServiceError, get_email_code_settings
1414
from ..core.http_client import HTTPClient, RequestConfig
1515
from ..config.constants import OTP_CODE_PATTERN
1616

@@ -211,14 +211,15 @@ def get_verification_code(
211211
"""
212212
logger.info(f"正在从 Freemail 邮箱 {email} 获取验证码...")
213213

214+
poll_interval = get_email_code_settings()["poll_interval"]
214215
start_time = time.time()
215216
seen_mail_ids: set = set()
216217

217218
while time.time() - start_time < timeout:
218219
try:
219220
mails = self._make_request("GET", "/api/emails", params={"mailbox": email, "limit": 20})
220221
if not isinstance(mails, list):
221-
time.sleep(3)
222+
time.sleep(poll_interval)
222223
continue
223224

224225
ordered_mails = self._sort_items_by_message_time(
@@ -287,7 +288,7 @@ def get_verification_code(
287288
except Exception as e:
288289
logger.debug(f"检查 Freemail 邮件时出错: {e}")
289290

290-
time.sleep(3)
291+
time.sleep(poll_interval)
291292

292293
logger.warning(f"等待 Freemail 验证码超时: {email}")
293294
return None

src/services/imap_mail.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from email.header import decode_header
1313
from typing import Any, Dict, Optional
1414

15-
from .base import BaseEmailService, EmailServiceError
15+
from .base import BaseEmailService, EmailServiceError, get_email_code_settings
1616
from ..config.constants import (
1717
EmailServiceType,
1818
OPENAI_EMAIL_SENDERS,
@@ -123,6 +123,7 @@ def get_verification_code(
123123
otp_sent_at: Optional[float] = None,
124124
) -> Optional[str]:
125125
"""轮询 IMAP 收件箱,获取 OpenAI 验证码"""
126+
poll_interval = get_email_code_settings()["poll_interval"]
126127
start_time = time.time()
127128
seen_ids: set = set()
128129
mail = None
@@ -136,7 +137,7 @@ def get_verification_code(
136137
# 搜索所有未读邮件
137138
status, data = mail.search(None, "UNSEEN")
138139
if status != "OK" or not data or not data[0]:
139-
time.sleep(3)
140+
time.sleep(poll_interval)
140141
continue
141142

142143
msg_ids = data[0].split()
@@ -177,7 +178,7 @@ def get_verification_code(
177178
except Exception:
178179
pass
179180

180-
time.sleep(3)
181+
time.sleep(poll_interval)
181182

182183
except Exception as e:
183184
logger.warning(f"IMAP 连接/轮询失败: {e}")

src/services/moe_mail.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from typing import Optional, Dict, Any, List
1111
from urllib.parse import urljoin
1212

13-
from .base import BaseEmailService, EmailServiceError, EmailServiceType, RateLimitedEmailServiceError
13+
from .base import BaseEmailService, EmailServiceError, EmailServiceType, RateLimitedEmailServiceError, get_email_code_settings
1414
from ..core.http_client import HTTPClient, RequestConfig
1515
from ..config.constants import OTP_CODE_PATTERN
1616

@@ -303,6 +303,7 @@ def get_verification_code(
303303

304304
logger.info(f"正在从自定义域名邮箱 {email} 获取验证码...")
305305

306+
poll_interval = get_email_code_settings()["poll_interval"]
306307
start_time = time.time()
307308
seen_message_ids = set()
308309

@@ -313,7 +314,7 @@ def get_verification_code(
313314

314315
messages = response.get("messages", [])
315316
if not isinstance(messages, list):
316-
time.sleep(3)
317+
time.sleep(poll_interval)
317318
continue
318319

319320
ordered_messages = self._sort_items_by_message_time(
@@ -370,7 +371,7 @@ def get_verification_code(
370371
logger.debug(f"检查邮件时出错: {e}")
371372

372373
# 等待一段时间再检查
373-
time.sleep(3)
374+
time.sleep(poll_interval)
374375

375376
logger.warning(f"等待验证码超时: {email}")
376377
return None

src/services/outlook/service.py

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,8 @@
88
import time
99
from typing import Optional, Dict, Any, List
1010

11-
from ..base import BaseEmailService, EmailServiceError, EmailServiceStatus, EmailServiceType
11+
from ..base import BaseEmailService, EmailServiceError, EmailServiceStatus, EmailServiceType, get_email_code_settings
1212
from ...config.constants import EmailServiceType as ServiceType
13-
from ...config.settings import get_settings
1413
from .account import OutlookAccount
1514
from .base import ProviderType, EmailMessage
1615
from .email_parser import EmailParser, get_email_parser
@@ -34,15 +33,6 @@
3433
]
3534

3635

37-
def get_email_code_settings() -> dict:
38-
"""获取验证码等待配置"""
39-
settings = get_settings()
40-
return {
41-
"timeout": settings.email_code_timeout,
42-
"poll_interval": settings.email_code_poll_interval,
43-
}
44-
45-
4636
class OutlookService(BaseEmailService):
4737
"""
4838
Outlook 邮箱服务

src/services/outlook_legacy_mail.py

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,29 +20,14 @@
2020
from email.utils import parsedate_to_datetime
2121
from urllib.error import HTTPError
2222

23-
from .base import BaseEmailService, EmailServiceError, EmailServiceType
23+
from .base import BaseEmailService, EmailServiceError, EmailServiceType, get_email_code_settings
2424
from ..config.constants import (
2525
OTP_CODE_PATTERN,
2626
OTP_CODE_SIMPLE_PATTERN,
2727
OTP_CODE_SEMANTIC_PATTERN,
2828
OPENAI_EMAIL_SENDERS,
2929
OPENAI_VERIFICATION_KEYWORDS,
3030
)
31-
from ..config.settings import get_settings
32-
33-
34-
def get_email_code_settings() -> dict:
35-
"""
36-
获取验证码等待配置
37-
38-
Returns:
39-
dict: 包含 timeout 和 poll_interval 的字典
40-
"""
41-
settings = get_settings()
42-
return {
43-
"timeout": settings.email_code_timeout,
44-
"poll_interval": settings.email_code_poll_interval,
45-
}
4631

4732

4833
logger = logging.getLogger(__name__)

src/services/temp_mail.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from html import unescape
1616
from typing import Optional, Dict, Any, List
1717

18-
from .base import BaseEmailService, EmailServiceError, EmailServiceType, RateLimitedEmailServiceError
18+
from .base import BaseEmailService, EmailServiceError, EmailServiceType, RateLimitedEmailServiceError, get_email_code_settings
1919
from ..core.http_client import HTTPClient, RequestConfig
2020
from ..config.constants import OTP_CODE_PATTERN
2121

@@ -307,6 +307,7 @@ def get_verification_code(
307307
logger.info(f"正在从 TempMail 邮箱 {email} 获取验证码...")
308308

309309
start_time = time.time()
310+
poll_interval = get_email_code_settings()["poll_interval"]
310311
seen_mail_ids: set = set()
311312

312313
# 优先使用用户级 JWT,回退到 admin API 先注释用户级API
@@ -332,7 +333,7 @@ def get_verification_code(
332333
# /user_api/mails 和 /admin/mails 返回格式相同: {"results": [...], "total": N}
333334
mails = response.get("results", [])
334335
if not isinstance(mails, list):
335-
time.sleep(3)
336+
time.sleep(poll_interval)
336337
continue
337338

338339
ordered_mails = self._sort_items_by_message_time(
@@ -381,7 +382,7 @@ def get_verification_code(
381382
except Exception as e:
382383
logger.debug(f"检查 TempMail 邮件时出错: {e}")
383384

384-
time.sleep(3)
385+
time.sleep(poll_interval)
385386

386387
logger.warning(f"等待 TempMail 验证码超时: {email}")
387388
return None

0 commit comments

Comments
 (0)