22 Commits

Author SHA1 Message Date
c684090b9c feat: handle Reply-To header, add account_email field, decode address headers 2026-07-02 22:37:15 +08:00
d7daddf491 feat: IMAP 支持 SSL/STARTTLS 配置 2026-07-02 22:18:51 +08:00
05135ee0cc chore: 添加 requirements.txt 2026-07-02 22:05:07 +08:00
ad950ff367 feat: 收件人/发件人改用邮件原始头数据
- sender 从 decode 改为使用原始 From 头
- 新增 recipient 字段,使用原始 To 头
- 移除 ai_process 中对 acct.username 的依赖
2026-07-02 22:04:27 +08:00
2ebcad0a70 feat: include reply content in send confirmation message 2026-07-02 21:01:05 +08:00
d334b6f3eb feat: enhance logging detail across all modules
- email_client: log IMAP connection, login, UNSEEN count, each email
  details (subject/sender/body size), mark-as-seen progress
- ai_client: log AI request params, timing, token usage, response size
- smtp_client: log SMTP connect, login, send details
- tg_bot: log all callback actions with subject context, message states
- main: periodic queue depth report (email_queue/tg_queue/pending_uids)
2026-07-02 21:00:40 +08:00
934d6a7545 fix: thread-safe logging with QueueHandler + QueueListener
- Replace logging.basicConfig with QueueHandler/QueueListener
  so all log output writes from a single thread
- Add %(threadName)s to format for thread identification
2026-07-02 20:57:33 +08:00
be412168bb fix: also delete user's message when cleaning up reply/hint flow 2026-07-02 20:56:30 +08:00
08a1a32367 fix: use original email From header for reply address instead of AI output
- send_summary now accepts original_sender (raw From header)
- Context stores original_sender separately from AI-generated sender
- _do_send_reply tries original_sender first, then AI sender fallback
2026-07-02 20:55:40 +08:00
ded61e25c1 refactor: split AI processor and TG worker into separate threads
- Three independent threads: email poller, AI processor, TG worker
- Two queues: _email_queue (raw emails→AI), _tg_queue (AI results→TG)
- summarizer.py split: ai_process() (AI only) + tg_send_and_mark() (TG only)
- AI retries no longer affect TG polling or email polling
2026-07-02 20:52:34 +08:00
1be3aadb08 refactor: separate email poll, email process, TG poll into threads
- main.py spawns 3 daemon threads: email poller, email processor, TG poller
- Each thread runs independently so retries don't block other operations
- _pending_uids set + lock prevents duplicate queueing across poll cycles
- summarizer.py split into poll_accounts() (generator) and process_email()
- Graceful shutdown via shared _running flag
2026-07-02 20:48:05 +08:00
09d11a6c03 feat: cancel button, regenerate AI replies, custom reply hints
- Reply prompt now has an inline '取消回复' button instead of typing text
- AI reply selection adds '换一批' button: passes all previous suggestions
  to AI to generate different replies
- '我想说:' button: lets user type a hint/tone instruction, AI tailors
  suggestions accordingly
- Cancel button also works on prompt/hint messages (deletes them)
- Extract _show_ai_suggestions helper for reuse
2026-07-02 20:45:40 +08:00
18db9caa8b feat: cancel reply flow with cleanup & remove AI reply confirmation
- send_text now returns message_id for tracking
- Reply prompt includes cancel hint; typing '取消'/'/cancel' clears it
- Prompt message auto-deleted after reply sent or cancelled
- AI reply suggestions always send immediately on tap (no confirm step)
- Removed _confirm_keyboard, CALLBACK_CONFIRM_REPLY handler
2026-07-02 20:41:56 +08:00
3d33aeb0dd fix: parse sender email properly & show confirmation tag clearly
- Use email.utils.parseaddr() to extract pure email from sender
  field (was passing raw 'Name <email>' to SMTP, causing 550 error)
- AI reply selection now shows confirmation status as bold tag
  on its own line for better visibility
2026-07-02 20:35:28 +08:00
0d9237ffdd fix: handle 400 errors from Telegram callback interactions
- Remove redundant editMessageText in CALLBACK_REPLY (text unchanged)
- Wrap answerCallbackQuery in try/except (non-critical)
- Wrap each update in its own try/except to ensure last_update_id
  always advances, preventing infinite retry loops
2026-07-02 20:32:25 +08:00
870ab4a59a refactor: merge reply suggestions into single AI request
- Summary prompt now includes can_reply + reply_suggestions fields
- Removed separate generate_reply_suggestions function and REPLY_PROMPT
- tg_bot reads reply suggestions from cached summary_data
- AI Reply button conditionally hidden based on can_reply
2026-07-02 20:22:54 +08:00
0dbc7ee661 feat: interactive inline buttons, SMTP reply, AI reply suggestions
- Inline keyboard: view original / back to summary toggle per message
- SMTP config per account for sending replies
- Reply button: click, type message, auto-send via SMTP
- AI Reply button: generates 3 suggestions via DeepSeek
  - Simple replies (OK, Got it) send immediately on tap
  - Substantive replies require confirm before send
  - Hides AI Reply button when AI determines reply unnecessary
- Telegram long polling integrated into main loop for real-time interaction
2026-07-02 20:21:06 +08:00
279f8c50e7 feat: show recipient & AI-generated subject in summary
- AI now generates a concise subject title (not copy original)
- AI prompt includes recipient field in JSON schema
- Telegram message shows recipient and uses AI-generated title
2026-07-02 20:05:16 +08:00
a6817d3e11 feat: add retry(10) on all network requests
- New src/retry.py with configurable retry decorator
- Applied @retry() to fetch_unseen_emails, mark_as_seen,
  summarize_email, and send_message
- No backoff delay between retries
2026-07-02 20:02:03 +08:00
89149b506c 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.
2026-07-02 19:56:14 +08:00
82403de6df fix: check IMAP select() return status before issuing commands
- Add _select_mailbox helper that raises on non-OK status
- Prevents 'command SEARCH illegal in state AUTH' by catching
  failed mailbox selection early with a clear error message
2026-07-02 19:53:26 +08:00
e2826a3e3b feat: init AI email summarization bot
- Multi-account IMAP email polling with UID tracking
- DeepSeek API integration with JSON Mode structured output
- Telegram notification with formatted MarkdownV2 message
- YAML config with dataclass-based type validation
- Graceful shutdown on SIGINT/SIGTERM
- 60s default polling interval
2026-07-02 19:45:34 +08:00