feat: show full recipient and CC in email summary - Email class: add cc field - fetch_unseen_emails: parse Cc header - _format_normal: display full recipient, add CC line if present - send_summary/ai_process: pass cc through to email_context - save_email_context: store cc for callback use
This commit is contained in:
@@ -14,7 +14,7 @@ logger = logging.getLogger(__name__)
|
|||||||
class Email:
|
class Email:
|
||||||
def __init__(self, uid: bytes, subject: str, sender: str, recipient: str,
|
def __init__(self, uid: bytes, subject: str, sender: str, recipient: str,
|
||||||
body: str, date: str, reply_to: str = "", account_email: str = "",
|
body: str, date: str, reply_to: str = "", account_email: str = "",
|
||||||
folder: str = "INBOX"):
|
folder: str = "INBOX", cc: str = ""):
|
||||||
self.uid = uid
|
self.uid = uid
|
||||||
self.subject = subject
|
self.subject = subject
|
||||||
self.sender = sender
|
self.sender = sender
|
||||||
@@ -24,6 +24,7 @@ class Email:
|
|||||||
self.reply_to = reply_to
|
self.reply_to = reply_to
|
||||||
self.account_email = account_email
|
self.account_email = account_email
|
||||||
self.folder = folder
|
self.folder = folder
|
||||||
|
self.cc = cc
|
||||||
|
|
||||||
|
|
||||||
def _decode_str(s: str) -> str:
|
def _decode_str(s: str) -> str:
|
||||||
@@ -165,6 +166,7 @@ def fetch_unseen_emails(account: EmailAccount, skip_uids: set[bytes] | None = No
|
|||||||
subject = _decode_str(msg.get("Subject", ""))
|
subject = _decode_str(msg.get("Subject", ""))
|
||||||
sender = _decode_address_header(msg.get("From", ""))
|
sender = _decode_address_header(msg.get("From", ""))
|
||||||
recipient = _decode_address_header(msg.get("To", ""))
|
recipient = _decode_address_header(msg.get("To", ""))
|
||||||
|
cc = _decode_address_header(msg.get("Cc", ""))
|
||||||
reply_to = _decode_address_header(msg.get("Reply-To", ""))
|
reply_to = _decode_address_header(msg.get("Reply-To", ""))
|
||||||
date_str = msg.get("Date", "")
|
date_str = msg.get("Date", "")
|
||||||
body = _get_text_from_msg(msg)
|
body = _get_text_from_msg(msg)
|
||||||
@@ -173,7 +175,7 @@ def fetch_unseen_emails(account: EmailAccount, skip_uids: set[bytes] | None = No
|
|||||||
logger.info(" 邮件: [%s] from=%s to=%s reply-to=%s (%d 字符)", subject, sender, recipient, reply_to, body_len)
|
logger.info(" 邮件: [%s] from=%s to=%s reply-to=%s (%d 字符)", subject, sender, recipient, reply_to, body_len)
|
||||||
emails.append(Email(uid=uid, subject=subject, sender=sender, recipient=recipient,
|
emails.append(Email(uid=uid, subject=subject, sender=sender, recipient=recipient,
|
||||||
body=body, date=date_str, reply_to=reply_to, account_email=account.username,
|
body=body, date=date_str, reply_to=reply_to, account_email=account.username,
|
||||||
folder=folder))
|
folder=folder, cc=cc))
|
||||||
|
|
||||||
# FETCH 可能被服务器自动标已读,立即标回未读
|
# FETCH 可能被服务器自动标已读,立即标回未读
|
||||||
conn.uid("STORE", uid, "-FLAGS", "\\Seen")
|
conn.uid("STORE", uid, "-FLAGS", "\\Seen")
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ def ai_process(cfg: Config, user: UserConfig, acct_idx: int, mail: Email, tg_msg
|
|||||||
"original_sender": mail.sender,
|
"original_sender": mail.sender,
|
||||||
"original_recipient": mail.recipient,
|
"original_recipient": mail.recipient,
|
||||||
"original_reply_to": mail.reply_to,
|
"original_reply_to": mail.reply_to,
|
||||||
|
"original_cc": mail.cc,
|
||||||
"acct_idx": acct_idx,
|
"acct_idx": acct_idx,
|
||||||
"account_email": mail.account_email,
|
"account_email": mail.account_email,
|
||||||
"uid": mail.uid,
|
"uid": mail.uid,
|
||||||
@@ -86,11 +87,13 @@ def tg_send_and_mark(cfg: Config, user: UserConfig, info: dict):
|
|||||||
"plain_text": info["data"].get("plain_text", ""),
|
"plain_text": info["data"].get("plain_text", ""),
|
||||||
"original_sender": info.get("original_sender", ""),
|
"original_sender": info.get("original_sender", ""),
|
||||||
"original_recipient": info.get("original_recipient", ""),
|
"original_recipient": info.get("original_recipient", ""),
|
||||||
|
"original_cc": info.get("original_cc", ""),
|
||||||
"original_reply_to": info.get("original_reply_to", ""),
|
"original_reply_to": info.get("original_reply_to", ""),
|
||||||
"account_email": info.get("account_email", ""),
|
"account_email": info.get("account_email", ""),
|
||||||
"account_idx": info["acct_idx"],
|
"account_idx": info["acct_idx"],
|
||||||
"sender": info["data"].get("sender", ""),
|
"sender": info["data"].get("sender", ""),
|
||||||
"subject": info["data"].get("subject", ""),
|
"subject": info["data"].get("subject", ""),
|
||||||
|
"cc": info.get("original_cc", ""),
|
||||||
"can_reply": can_reply,
|
"can_reply": can_reply,
|
||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -21,10 +21,14 @@ _ai_pool = ThreadPoolExecutor(max_workers=3, thread_name_prefix="ai_regen")
|
|||||||
def send_summary(bot_token: str, chat_id: str, summary_text: str,
|
def send_summary(bot_token: str, chat_id: str, summary_text: str,
|
||||||
summary_data: dict, original_body: str, account_idx: int,
|
summary_data: dict, original_body: str, account_idx: int,
|
||||||
original_sender: str = "", original_recipient: str = "",
|
original_sender: str = "", original_recipient: str = "",
|
||||||
original_reply_to: str = "", account_email: str = "") -> int:
|
original_reply_to: str = "", account_email: str = "",
|
||||||
|
original_cc: str = "") -> int:
|
||||||
can_reply = summary_data.get("can_reply", True)
|
can_reply = summary_data.get("can_reply", True)
|
||||||
is_promotion = summary_data.get("category") == "promotion"
|
is_promotion = summary_data.get("category") == "promotion"
|
||||||
links = summary_data.get("links", [])
|
links = summary_data.get("links", [])
|
||||||
|
# summary_data 里可能有 cc
|
||||||
|
if original_cc:
|
||||||
|
summary_data["cc"] = original_cc
|
||||||
result = _tg_req(bot_token, "sendMessage", {
|
result = _tg_req(bot_token, "sendMessage", {
|
||||||
"chat_id": chat_id,
|
"chat_id": chat_id,
|
||||||
"text": summary_text,
|
"text": summary_text,
|
||||||
@@ -38,11 +42,13 @@ def send_summary(bot_token: str, chat_id: str, summary_text: str,
|
|||||||
"original_body": original_body,
|
"original_body": original_body,
|
||||||
"original_sender": original_sender or summary_data.get("sender", ""),
|
"original_sender": original_sender or summary_data.get("sender", ""),
|
||||||
"original_recipient": original_recipient or summary_data.get("recipient", ""),
|
"original_recipient": original_recipient or summary_data.get("recipient", ""),
|
||||||
|
"original_cc": original_cc,
|
||||||
"original_reply_to": original_reply_to,
|
"original_reply_to": original_reply_to,
|
||||||
"account_idx": account_idx,
|
"account_idx": account_idx,
|
||||||
"account_email": account_email,
|
"account_email": account_email,
|
||||||
"sender": summary_data.get("sender", ""),
|
"sender": summary_data.get("sender", ""),
|
||||||
"subject": summary_data.get("subject", ""),
|
"subject": summary_data.get("subject", ""),
|
||||||
|
"cc": original_cc,
|
||||||
"can_reply": can_reply,
|
"can_reply": can_reply,
|
||||||
})
|
})
|
||||||
return msg_id
|
return msg_id
|
||||||
@@ -146,15 +152,21 @@ def _format_verification(data: dict, account_email: str = "") -> str:
|
|||||||
|
|
||||||
|
|
||||||
def _format_normal(data: dict, account_email: str = "") -> str:
|
def _format_normal(data: dict, account_email: str = "") -> str:
|
||||||
|
recipient = data.get("recipient", "未知")
|
||||||
|
cc = data.get("cc", "")
|
||||||
lines = [
|
lines = [
|
||||||
f"📧 *{_escape(data.get('subject', '邮件摘要'))}*",
|
f"📧 *{_escape(data.get('subject', '邮件摘要'))}*",
|
||||||
f"━━━━━━━━━━━━━━━━━━",
|
f"━━━━━━━━━━━━━━━━━━",
|
||||||
f"*收件账户:* {_escape(account_email)}",
|
f"*收件账户:* {_escape(account_email)}",
|
||||||
f"*收件人:* {_escape(data.get('recipient', '未知'))}",
|
f"*收件人:* {_escape(recipient)}",
|
||||||
|
]
|
||||||
|
if cc:
|
||||||
|
lines.append(f"*抄送:* {_escape(cc)}")
|
||||||
|
lines.extend([
|
||||||
f"*发件人:* {_escape(data.get('sender', '未知'))}",
|
f"*发件人:* {_escape(data.get('sender', '未知'))}",
|
||||||
"",
|
"",
|
||||||
_escape(data.get("summary", "")),
|
_escape(data.get("summary", "")),
|
||||||
]
|
])
|
||||||
return "\n".join(lines)
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user