fix: add IMAP ID command for 126.com/163.com support
These providers require a client identification (ID command, RFC 2971) before SELECT INBOX, otherwise they reject with 'SELECT Unsafe Login'. Extract shared login+select logic into _login_and_prepare helper.
This commit is contained in:
@@ -48,16 +48,36 @@ def _get_text_from_msg(msg) -> str:
|
||||
return ""
|
||||
|
||||
|
||||
_PROVIDERS_NEED_ID = ("163.com", "126.com")
|
||||
|
||||
|
||||
def _check_provider(email_addr: str, providers: tuple[str, ...]) -> bool:
|
||||
return any(email_addr.endswith(p) for p in providers)
|
||||
|
||||
|
||||
def _send_id_command(conn):
|
||||
imaplib.Commands["ID"] = "AUTH"
|
||||
args = ("name", "AI-Mail-Bot", "version", "1.0.0", "vendor", "personal")
|
||||
conn._simple_command("ID", '("' + '" "'.join(args) + '")')
|
||||
|
||||
|
||||
def _select_mailbox(conn, mailbox: str = "INBOX"):
|
||||
status, data = conn.select(mailbox)
|
||||
if status != "OK":
|
||||
raise RuntimeError(f"无法选择邮箱 {mailbox}: {data}")
|
||||
|
||||
|
||||
def fetch_unseen_emails(account: EmailAccount) -> list[Email]:
|
||||
def _login_and_prepare(account: EmailAccount):
|
||||
conn = imaplib.IMAP4_SSL(account.imap_server, account.imap_port)
|
||||
conn.login(account.username, account.password)
|
||||
if _check_provider(account.username, _PROVIDERS_NEED_ID):
|
||||
_send_id_command(conn)
|
||||
_select_mailbox(conn)
|
||||
return conn
|
||||
|
||||
|
||||
def fetch_unseen_emails(account: EmailAccount) -> list[Email]:
|
||||
conn = _login_and_prepare(account)
|
||||
|
||||
_, data = conn.uid("SEARCH", None, "UNSEEN")
|
||||
uids = data[0].split() if data[0] else []
|
||||
@@ -84,9 +104,7 @@ def fetch_unseen_emails(account: EmailAccount) -> list[Email]:
|
||||
def mark_as_seen(account: EmailAccount, uids: list[bytes]):
|
||||
if not uids:
|
||||
return
|
||||
conn = imaplib.IMAP4_SSL(account.imap_server, account.imap_port)
|
||||
conn.login(account.username, account.password)
|
||||
_select_mailbox(conn)
|
||||
conn = _login_and_prepare(account)
|
||||
for uid in uids:
|
||||
conn.uid("STORE", uid, "+FLAGS", "\\Seen")
|
||||
conn.logout()
|
||||
|
||||
Reference in New Issue
Block a user