fix: handle imapclient named tuple format for ENVELOPE and Address

- parse_envelope now handles Envelope named tuple (imapclient format)
- parse_address now handles Address named tuple
- date field preserved as datetime object, not stringified
- Add .venv and __pycache__ to .gitignore
This commit is contained in:
James 2026-01-31 09:00:22 +00:00
parent 5d9e58f5ae
commit d62b62bb89
24 changed files with 57 additions and 30 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.venv/
__pycache__/

View File

@ -1 +0,0 @@
python3

View File

@ -1 +0,0 @@
/usr/bin/python3

View File

@ -1 +0,0 @@
python3

View File

@ -1 +0,0 @@
lib

View File

@ -1,5 +0,0 @@
home = /usr/bin
include-system-site-packages = false
version = 3.12.3
executable = /usr/bin/python3.12
command = /usr/bin/python3 -m venv /home/johan/dev/mail-agent/.venv

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -43,7 +43,20 @@ def parse_address(addr: Any) -> str:
if addr is None: if addr is None:
return "" return ""
# ENVELOPE address format: (name, route, mailbox, host) # Handle imapclient's Address named tuple
if hasattr(addr, 'mailbox') and hasattr(addr, 'host'):
name = decode_header_value(addr.name) if addr.name else ""
mailbox = decode_header_value(addr.mailbox) if addr.mailbox else ""
host = decode_header_value(addr.host) if addr.host else ""
if mailbox and host:
email_addr = f"{mailbox}@{host}"
if name:
return f"{name} <{email_addr}>"
return email_addr
return ""
# Legacy tuple format: (name, route, mailbox, host)
if isinstance(addr, (list, tuple)) and len(addr) >= 4: if isinstance(addr, (list, tuple)) and len(addr) >= 4:
name = decode_header_value(addr[0]) name = decode_header_value(addr[0])
mailbox = decode_header_value(addr[2]) mailbox = decode_header_value(addr[2])
@ -74,11 +87,28 @@ def parse_envelope(envelope: Any) -> dict:
if envelope is None: if envelope is None:
return {} return {}
# ENVELOPE format:
# (date, subject, from, sender, reply-to, to, cc, bcc, in-reply-to, message-id)
result = {} result = {}
try: try:
# Handle imapclient's Envelope named tuple
if hasattr(envelope, 'date'):
# Named tuple format (imapclient)
if envelope.date:
result["date"] = envelope.date # Keep as datetime object
if envelope.subject:
result["subject"] = decode_header_value(envelope.subject)
if envelope.from_:
from_list = parse_address_list(envelope.from_)
result["from"] = from_list[0] if from_list else ""
if envelope.to:
result["to"] = parse_address_list(envelope.to)
if envelope.cc:
result["cc"] = parse_address_list(envelope.cc)
if envelope.message_id:
result["message_id"] = decode_header_value(envelope.message_id)
else:
# Legacy tuple format
# (date, subject, from, sender, reply-to, to, cc, bcc, in-reply-to, message-id)
if len(envelope) >= 1: if len(envelope) >= 1:
result["date"] = decode_header_value(envelope[0]) result["date"] = decode_header_value(envelope[0])
if len(envelope) >= 2: if len(envelope) >= 2:
@ -191,9 +221,13 @@ def parse_message(uid: int, folder: str, msg_data: dict) -> Optional[Message]:
# Parse date # Parse date
msg_date = None msg_date = None
if date_str := env_data.get("date"): date_val = env_data.get("date")
if date_val:
if isinstance(date_val, datetime):
msg_date = date_val
else:
try: try:
msg_date = parsedate_to_datetime(date_str) msg_date = parsedate_to_datetime(str(date_val))
except Exception: except Exception:
pass pass

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.