earthjasonlin
0abb7de5d3
fix: move regenerate to AI thread pool, fix parse_mode None error
2026-07-17 18:30:57 +08:00
earthjasonlin
5ca739456d
perf: reduce poll timeout to 1s and wait to 50ms for faster button response
2026-07-15 19:20:52 +08:00
earthjasonlin
c26d8aa294
fix: reduce long-poll timeout to 2s, make mark_as_seen async to unblock TG sender
2026-07-15 19:15:27 +08:00
earthjasonlin
c940a456bc
fix: clear all database tables on startup
2026-07-15 19:09:41 +08:00
earthjasonlin
b226f0b597
fix: clear processed_emails on startup to avoid stale state
2026-07-15 19:09:02 +08:00
earthjasonlin
687e60ede4
fix: add error logging for send_thinking failures in email poller
2026-07-15 19:02:59 +08:00
earthjasonlin
da1b266350
fix: increase Telegram long-poll timeout to 5s and HTTP timeout to 15s
2026-07-15 18:51:04 +08:00
earthjasonlin
dcdfba11fa
feat: show email subject and sender in all status messages
2026-07-15 18:39:58 +08:00
earthjasonlin
2822075f2f
refactor: split TG worker into poller (callbacks) and sender (email summaries) threads
2026-07-15 18:35:01 +08:00
earthjasonlin
2744d9dd77
fix: process one queued email per poll cycle to keep callbacks responsive
2026-07-15 18:32:42 +08:00
earthjasonlin
17514302f9
fix: import is_uid_processed instead of is_uids_processed
2026-07-15 18:25:57 +08:00
earthjasonlin
d42022cc2e
fix: ensure data directory exists before DB connection in all threads
2026-07-15 18:18:24 +08:00
earthjasonlin
54c4bf00fb
refactor: replace all in-memory state with SQLite database
2026-07-14 14:49:23 +08:00
earthjasonlin
c3132f746a
feat: AI generates plain_text field, view full text shows readable version instead of HTML
2026-07-14 14:37:12 +08:00
earthjasonlin
dd7fc61fd4
fix: remove all body truncation, show full email text everywhere
2026-07-14 14:34:17 +08:00
earthjasonlin
5113d78662
prompt: detailed instructions for extracting unsubscribe links from promotional emails
2026-07-13 08:38:05 +08:00
earthjasonlin
8b885f1c4c
fix: use threading.Event for immediate shutdown instead of sleep loops
2026-07-13 08:34:02 +08:00
earthjasonlin
8b577b4c12
prompt: emphasize extracting unsubscribe links from promotional emails
2026-07-13 08:30:44 +08:00
earthjasonlin
26468aa43d
fix: use ellipsis character instead of dots in status messages for MarkdownV2 compatibility
2026-07-13 08:28:23 +08:00
earthjasonlin
98147e6a6c
fix: omit parse_mode from payload when None instead of sending null
2026-07-13 08:27:16 +08:00
earthjasonlin
bd5b824a6a
fix: add parse_mode param to edit_message, status messages use plain text
2026-07-13 08:23:42 +08:00
earthjasonlin
01504e6295
feat: three-stage status: 获取邮件中 -> 等待处理 -> AI思考中
2026-07-13 08:19:36 +08:00
earthjasonlin
02b0941ed0
feat: two-stage status messages: 获取邮件中 -> AI思考中
2026-07-13 08:15:25 +08:00
earthjasonlin
85b02651b9
revert: use debug log for unselectable folders instead of warning
2026-07-13 08:11:30 +08:00
earthjasonlin
e74ae8be88
fix: quote folder names in IMAP SELECT for folders with spaces
2026-07-13 08:10:39 +08:00
earthjasonlin
f38259e4bb
fix: mark_as_seen uses readonly=False to actually set Seen flag
2026-07-13 08:05:40 +08:00
earthjasonlin
5368812e45
fix: skip NoSelect folders, clean up debug logging
2026-07-13 08:04:26 +08:00
earthjasonlin
8c088ddff5
debug: add skip_uids logging to diagnose re-fetch issue
2026-07-13 07:54:13 +08:00
earthjasonlin
0ec2048bc5
fix: never discard from _processing_uids to prevent re-fetching
2026-07-13 07:49:09 +08:00
earthjasonlin
155a6dfc53
fix: skip already-processing UIDs at FETCH level to avoid downloading email content
2026-07-13 07:35:28 +08:00
earthjasonlin
d31ec18ea3
fix: restore -FLAGS Seen after FETCH, protected by _processing_uids
2026-07-13 07:13:08 +08:00
earthjasonlin
02cf4b88b6
fix: add _processing_uids to prevent re-fetching emails being processed
2026-07-13 07:12:43 +08:00
earthjasonlin
ae140df3fb
chore: remove accidental file
2026-07-13 06:57:28 +08:00
earthjasonlin
e9398526e6
fix: login without selecting INBOX first so conn.list() returns all folders
2026-07-13 06:57:06 +08:00
earthjasonlin
479b855390
feat: scan all IMAP folders for unread emails, not just INBOX
2026-07-13 00:16:28 +08:00
earthjasonlin
46bc7c7057
prompt: force simplified Chinese for all AI outputs except reply suggestions
2026-07-13 00:12:50 +08:00
earthjasonlin
bbc43f8972
fix: keep pending_uids until TG send completes to prevent duplicate processing
2026-07-12 23:51:45 +08:00
earthjasonlin
87e4b0b01e
prompt: refine link extraction to exclude promotional links
2026-07-12 10:15:25 +08:00
earthjasonlin
fc4c5a175c
feat: show thinking indicator during AI processing, accept non-numeric verification codes
2026-07-11 22:54:06 +08:00
earthjasonlin
1c7d0c1b00
fix: mark emails back as UNSEEN after FETCH to counter server auto-read
2026-07-11 22:45:31 +08:00
earthjasonlin
5320b10317
fix: per-email error handling with connection rebuild, remove @retry on fetch
2026-07-11 22:43:39 +08:00
earthjasonlin
d8807ffbb5
fix: remove body truncation for large emails
2026-07-11 22:38:40 +08:00
earthjasonlin
8d40ed8b19
fix: use BODY.PEEK for large emails to prevent server auto-marking as read on timeout
2026-07-11 22:38:07 +08:00
earthjasonlin
57191ab00e
feat: remove body truncation for all AI requests, increase API timeout to 120s
2026-07-11 22:32:47 +08:00
earthjasonlin
13b76c00ab
feat: add tell me more button for promotion emails with AI-generated details
2026-07-11 22:17:10 +08:00
earthjasonlin
cf0f7d3956
style: restructure email formats with 收件账户 and app_name for verification
2026-07-11 22:11:15 +08:00
earthjasonlin
e56bdef0f7
fix: use single backtick for tap-to-copy, remove copy_text button
2026-07-11 22:05:02 +08:00
earthjasonlin
6d1fe29df4
fix: copy_text field must be an object with text key
2026-07-11 21:57:19 +08:00
earthjasonlin
05b15d9ee3
fix: use copy_text field instead of duplicate text key
2026-07-11 21:52:07 +08:00
earthjasonlin
03c18cdb76
fix: copy button shows only the code number
2026-07-11 21:49:54 +08:00
earthjasonlin
b835812f38
feat: add copy_text button for verification codes
2026-07-11 21:47:54 +08:00
earthjasonlin
070c32071a
style: beautify email formats with type labels and consistent layout
2026-07-11 21:42:35 +08:00
earthjasonlin
5a21aeee14
chore: remove test scripts
2026-07-11 21:35:58 +08:00
earthjasonlin
8007fa1cc4
fix: always use MarkdownV2 for all message types
2026-07-11 21:35:22 +08:00
earthjasonlin
43994d2b0d
fix: remove null parse_mode from tg payload, add error logging
2026-07-11 21:22:20 +08:00
earthjasonlin
a992af0e02
refactor: remove action_required/action_items/key_points, keep summary concise
2026-07-11 19:46:18 +08:00
earthjasonlin
1957eb2a73
feat: extract clickable links from email and show as URL buttons
2026-07-11 19:38:33 +08:00
earthjasonlin
be4e957af9
feat: verification emails displayed as platform + code
2026-07-08 16:15:51 +08:00
earthjasonlin
9991e4ef17
feat: promotional emails summarized as who promotes what
2026-07-08 16:13:54 +08:00
earthjasonlin
ea6358019d
chore: AI并行workers 5→10
2026-07-06 20:13:15 +08:00
earthjasonlin
d70b817fd4
feat: AI并行处理 + 修复邮件丢失
...
- _ai_processor 改用 ThreadPoolExecutor(5 workers) 并行调用AI
- _tg_worker 每轮排空所有待发TG消息(原来每轮只取1条)
- fetch_unseen_emails 单封FETCH失败不再丢弃整个批次,跳过继续
2026-07-06 20:12:24 +08:00
earthjasonlin
0c1ccdfc79
fix: 修复 _email_poller 线程静默死亡问题
...
- IMAP 连接加 30s socket timeout,防止 _send_id_command 等操作永久阻塞
- _email_poller 加顶层 try/except,异常后 sleep 5s 继续循环
- @retry() 加指数退避延迟(1s,2s,4s...),避免重试风暴
2026-07-06 19:54:23 +08:00
earthjasonlin
c684090b9c
feat: handle Reply-To header, add account_email field, decode address headers
2026-07-02 22:37:15 +08:00
earthjasonlin
d7daddf491
feat: IMAP 支持 SSL/STARTTLS 配置
2026-07-02 22:18:51 +08:00
earthjasonlin
05135ee0cc
chore: 添加 requirements.txt
2026-07-02 22:05:07 +08:00
earthjasonlin
ad950ff367
feat: 收件人/发件人改用邮件原始头数据
...
- sender 从 decode 改为使用原始 From 头
- 新增 recipient 字段,使用原始 To 头
- 移除 ai_process 中对 acct.username 的依赖
2026-07-02 22:04:27 +08:00
earthjasonlin
2ebcad0a70
feat: include reply content in send confirmation message
2026-07-02 21:01:05 +08:00
earthjasonlin
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
earthjasonlin
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
earthjasonlin
be412168bb
fix: also delete user's message when cleaning up reply/hint flow
2026-07-02 20:56:30 +08:00
earthjasonlin
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
earthjasonlin
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
earthjasonlin
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
earthjasonlin
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
earthjasonlin
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
earthjasonlin
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
earthjasonlin
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
earthjasonlin
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
earthjasonlin
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
earthjasonlin
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
earthjasonlin
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
earthjasonlin
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
earthjasonlin
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
earthjasonlin
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