From 5a6ae3e94f126aa985bf4bf9c9300293e15a6dc3 Mon Sep 17 00:00:00 2001 From: Kacper Kwapisz Date: Wed, 25 Mar 2026 14:47:42 +0100 Subject: [PATCH 1/2] Add mark_as_read config option to preserve email read status Emails forwarded to Poke are no longer marked as read by default, so users can continue using read/unread status to organize their inbox. Set mark_as_read: true (global or per-account) to restore the previous behavior. Closes #5 --- config.example.yml | 5 +++++ src/server.py | 9 +++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/config.example.yml b/config.example.yml index 477bd02..62129df 100644 --- a/config.example.yml +++ b/config.example.yml @@ -11,6 +11,10 @@ poke_api_key: "your-api-key-here" # Agents can still use create_draft. Override per account with allow_send. allow_send: true +# Mark forwarded emails as read — set to true to mark emails as read after +# forwarding to Poke. Defaults to false. Override per account with mark_as_read. +mark_as_read: false + accounts: # iCloud Mail — login is @icloud.com, send as your custom domain # Generate an App-Specific Password: https://support.apple.com/en-us/102654 @@ -24,6 +28,7 @@ accounts: from_address: "you@yourdomain.com" # Override From: header (login is @icloud.com but send as custom domain) watch_folders: - INBOX + # mark_as_read: false # Keep emails unread after forwarding # Custom SMTP server — SMTP falls back to IMAP credentials if not specified # - id: work diff --git a/src/server.py b/src/server.py index 1d9faca..12c9474 100755 --- a/src/server.py +++ b/src/server.py @@ -194,10 +194,12 @@ def parse_accounts(config: dict) -> list[dict]: os.environ.get("SMTP_USERNAME", os.environ["IMAP_USERNAME"]), ), "watch_folders": ["INBOX"], + "mark_as_read": os.environ.get("MARK_AS_READ", "false").lower() == "true", } ] global_allow_send = config.get("allow_send", True) + global_mark_as_read = config.get("mark_as_read", False) required = ("imap_host", "imap_username", "imap_password") for i, acc in enumerate(accounts): acc.setdefault("id", f"account-{i}") @@ -210,6 +212,7 @@ def parse_accounts(config: dict) -> list[dict]: acc.setdefault("smtp_password", acc.get("imap_password")) acc.setdefault("from_address", acc.get("smtp_username")) acc.setdefault("allow_send", global_allow_send) + acc.setdefault("mark_as_read", global_mark_as_read) for field in required: if field not in acc: raise RuntimeError( @@ -491,7 +494,8 @@ async def watch_folder( email_data = parse_email_message(raw) await forward_to_poke(email_data, account, webhook_url, api_key) - await asyncio.to_thread(client.set_flags, new_uids, [b"\\Seen"]) + if account.get("mark_as_read", False): + await asyncio.to_thread(client.set_flags, new_uids, [b"\\Seen"]) existing_unseen.update(new_uids) except asyncio.CancelledError: @@ -535,7 +539,8 @@ async def _poll_folder( continue email_data = parse_email_message(raw) await forward_to_poke(email_data, account, webhook_url, api_key) - await asyncio.to_thread(client.set_flags, uids, [b"\\Seen"]) + if account.get("mark_as_read", False): + await asyncio.to_thread(client.set_flags, uids, [b"\\Seen"]) except Exception as e: logger.warning("[%s/%s] Poll error: %s", account["id"], folder, e) raise # reconnect via outer loop From 7ac653124893625d57d4df1a4acb2c2401ff5579 Mon Sep 17 00:00:00 2001 From: Kacper Kwapisz Date: Wed, 25 Mar 2026 14:49:21 +0100 Subject: [PATCH 2/2] Fix ruff formatting --- src/server.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/server.py b/src/server.py index 12c9474..d4a93b7 100755 --- a/src/server.py +++ b/src/server.py @@ -194,7 +194,8 @@ def parse_accounts(config: dict) -> list[dict]: os.environ.get("SMTP_USERNAME", os.environ["IMAP_USERNAME"]), ), "watch_folders": ["INBOX"], - "mark_as_read": os.environ.get("MARK_AS_READ", "false").lower() == "true", + "mark_as_read": os.environ.get("MARK_AS_READ", "false").lower() + == "true", } ]