# Python Email Fallback (when himalaya is not installed) When `himalaya` CLI is unavailable, use Python's built-in `smtplib` and `imaplib` with credentials from `~/.hermes/config.yaml`. ## Sending Email ```python import smtplib from email.mime.text import MIMEText smtp_host = "claw.163.com" sender = "ephronren@claw.163.com" password = "" recipient = "recipient@example.com" msg = MIMEText("Body text", "plain", "utf-8") msg["From"] = sender msg["To"] = recipient msg["Subject"] = "Subject" with smtplib.SMTP_SSL(smtp_host, 465) as server: server.login(sender, password) server.sendmail(sender, recipient, msg.as_string()) ``` ## Reading Email ```python import imaplib from email import message_from_bytes from email.header import decode_header imap_host = "claw.163.com" imap_port = 993 user = "ephronren@claw.163.com" password = "" with imaplib.IMAP4_SSL(imap_host, imap_port) as mail: mail.login(user, password) mail.select("INBOX") _, data = mail.search(None, "ALL") ids = data[0].split() eid = ids[-1] # latest _, msg_data = mail.fetch(eid, "(RFC822)") msg = message_from_bytes(msg_data[0][1]) def decode_str(s): if s is None: return "" parts = decode_header(s) return " ".join( p.decode(c or "utf-8", errors="replace") if isinstance(p, bytes) else p for p, c in parts ) print(f"From: {decode_str(msg['From'])}") print(f"Subject: {decode_str(msg['Subject'])}") if msg.is_multipart(): for part in msg.walk(): if part.get_content_type() == "text/plain": payload = part.get_payload(decode=True) charset = part.get_content_charset() or "utf-8" print(payload.decode(charset, errors="replace")) break else: payload = msg.get_payload(decode=True) charset = msg.get_content_charset() or "utf-8" print(payload.decode(charset, errors="replace")) ``` ## Pitfalls - **Port 25 times out** — 163 SMTP blocks plain SMTP. Use `SMTP_SSL` with port **465** instead. - **Port 465 config mismatch** — config.yaml says port 25, but actual working port is 465. - **send_message tool limitation** — `send_message(action='send', target='email:addr@domain')` does NOT resolve external addresses. Must use Python/terminal directly. - **IMAP fetch auto-marks as read** — `mail.fetch(eid, "(RFC822)")` and even `fetch(eid, "(BODY[HEADER.FIELDS ...])")` automatically set the `\Seen` flag. If you need to check unread count after reading, the count will drop. Use `mail.search(None, "UNSEEN")` before fetching to get accurate unread count.