Files
myagents/myclaude/mail/utils.py
T
Zhengshou Lai 5a665e38bb feat(mail): add IMAP/STP email subcommand
New `myclaude mail` group with:
- config: interactive account setup
- inbox: list recent messages
- read: show message by UID
- send: send email with attachments
- reply/forward: reply to or forward messages
2026-04-17 00:02:54 +08:00

61 lines
1.9 KiB
Python

"""Mail utility helpers."""
import re
from datetime import datetime
from email.header import decode_header
from email.utils import mktime_tz, parsedate_tz
from typing import Any
def decode_header_value(value: Any) -> str:
"""Decode email header value safely."""
if value is None:
return ""
raw = value if isinstance(value, str) else str(value)
parts = decode_header(raw)
result: list[str] = []
for part, charset in parts:
if isinstance(part, bytes):
result.append(part.decode(charset or "utf-8", errors="replace"))
else:
result.append(part)
return "".join(result)
def format_date(date_str: str | None) -> str:
"""Format email date string to local-friendly form."""
if not date_str:
return ""
try:
tt = parsedate_tz(date_str)
if tt is None:
return date_str
ts = mktime_tz(tt)
dt = datetime.fromtimestamp(ts)
return dt.strftime("%Y-%m-%d %H:%M")
except Exception:
return date_str
def strip_html_tags(html: str) -> str:
"""Very basic HTML tag stripping for fallback text extraction."""
text = re.sub(r"<script[^>]*>.*?</script>", "", html, flags=re.S)
text = re.sub(r"<style[^>]*>.*?</style>", "", text, flags=re.S)
# Replace block-level tags with newlines before stripping remaining tags
text = re.sub(r"</(p|div|h[1-6]|li|tr|blockquote)>", "\n", text, flags=re.I)
text = re.sub(r"<br\s*/?>", "\n", text, flags=re.I)
text = re.sub(r"<[^>]+>", "", text)
text = re.sub(r"&nbsp;", " ", text)
text = re.sub(r"&lt;", "<", text)
text = re.sub(r"&gt;", ">", text)
text = re.sub(r"&amp;", "&", text)
text = re.sub(r"\n\s*\n+", "\n\n", text)
return text.strip()
def truncate_text(text: str, max_len: int = 60) -> str:
"""Truncate text with ellipsis."""
if len(text) <= max_len:
return text
return text[: max_len - 1] + "…"