"""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"]*>.*?", "", html, flags=re.S) text = re.sub(r"]*>.*?", "", text, flags=re.S) # Replace block-level tags with newlines before stripping remaining tags text = re.sub(r"", "\n", text, flags=re.I) text = re.sub(r"", "\n", text, flags=re.I) text = re.sub(r"<[^>]+>", "", text) text = re.sub(r" ", " ", text) text = re.sub(r"<", "<", text) text = re.sub(r">", ">", text) text = re.sub(r"&", "&", 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] + "…"