Mark maildir messages as read after they are read (#726)

MaildirConnection.fetch_message() previously returned the message body
without touching the on-disk file, so messages stayed in new/ with no
"S" (Seen) flag and any MUA scanning the same maildir kept showing them
as unread. The call site now passes mark_read=not test (mirroring the
existing MSGraphConnection plumbing); on True, the message is moved to
cur/ and gains the S flag. Test mode leaves the maildir unmodified.

Co-authored-by: Sean Whalen <seanthegeek@users.noreply.github.com>
This commit is contained in:
Sean Whalen
2026-04-24 19:16:42 -04:00
committed by GitHub
parent adf36ca6a3
commit 342b467590
3 changed files with 16 additions and 6 deletions
+1
View File
@@ -4,6 +4,7 @@
### Fixed
- `MaildirConnection.fetch_message()` now marks messages as read after reading them (sets the `S` flag and moves the file from `new/` to `cur/`), unless `--test` is in effect. Previously, a message was processed but its on-disk maildir state was unchanged, so an MUA scanning the same maildir kept showing it as unread. Mirrors the existing `mark_read=not test` pattern used for `MSGraphConnection`.
- `get_ip_address_info()` no longer caches weak-fallback attributions (no PTR + no ASN-domain map match → raw `as_name` used as `source_name`, `source_type` left null). `get_reverse_dns()` swallows every `DNSException` as `None`, so a transient PTR lookup failure (timeout, SERVFAIL, socket error) is indistinguishable from a genuine no-PTR case at that layer — caching the weak result would poison the 4-hour cache with a misattribution that persisted even after the PTR became resolvable again. PTR-backed matches and ASN-domain matches (both stable attributions) are still cached as before; only the specific `reverse_dns=None AND type=None AND name=as_name` state skips the cache write so the next lookup retries.
## 9.10.1
+4
View File
@@ -48,6 +48,7 @@ from parsedmarc.mail import (
GmailConnection,
IMAPConnection,
MailboxConnection,
MaildirConnection,
MSGraphConnection,
)
from parsedmarc.types import (
@@ -2042,6 +2043,9 @@ def get_dmarc_reports_from_mailbox(
elif isinstance(connection, MSGraphConnection):
message_id = str(msg_uid)
msg_content = connection.fetch_message(message_id, mark_read=not test)
elif isinstance(connection, MaildirConnection):
message_id = str(msg_uid) if not isinstance(msg_uid, str) else msg_uid
msg_content = connection.fetch_message(message_id, mark_read=not test)
else:
message_id = str(msg_uid) if not isinstance(msg_uid, str) else msg_uid
msg_content = connection.fetch_message(message_id)
+11 -6
View File
@@ -65,13 +65,18 @@ class MaildirConnection(MailboxConnection):
self._active_folder = self._client
return self._active_folder.keys()
def fetch_message(self, message_id: str) -> str:
def fetch_message(self, message_id: str, **kwargs) -> str:
msg = self._active_folder.get(message_id)
if msg is not None:
msg = msg.as_string()
if msg is not None:
return msg
return ""
if msg is None:
return ""
msg_str = msg.as_string()
if kwargs.get("mark_read"):
# Maildir spec: a message is "read" once it has been moved out of
# new/ into cur/ with the "S" (Seen) flag set in its info field.
msg.set_subdir("cur")
msg.add_flag("S")
self._active_folder[message_id] = msg
return msg_str or ""
def delete_message(self, message_id: str):
self._active_folder.remove(message_id)