- Replace logging.basicConfig with QueueHandler/QueueListener
so all log output writes from a single thread
- Add %(threadName)s to format for thread identification
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
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.
- 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