#!/usr/bin/env python3 """Check shonuff@germainebrown.com inbox. Outputs JSON for LLM summary. Silent if nothing new. Skips trusted senders (Germaine, mailer-daemon). """ import imaplib, email, json, os, hashlib from email.utils import parsedate_to_datetime HOST = "mail.germainebrown.com" PORT = 993 USER = "shonuff@germainebrown.com" PW = "Catches.bullets1985" SEEN_FILE = "/root/.hermes/scripts/.shonuff-processed.json" TRUSTED = ["g@germainebrown.com"] def load_seen(): if os.path.exists(SEEN_FILE): return set(json.load(open(SEEN_FILE))) return set() def save_seen(seen): json.dump(list(seen), open(SEEN_FILE, "w")) def safe_str(val): if val is None: return "" if isinstance(val, str): return val try: return str(val) except: return "" def get_text_body(msg): body = "" # Try text/plain first if msg.is_multipart(): for part in msg.walk(): if part.get_content_type() == "text/plain": payload = part.get_payload(decode=True) if payload: body += payload.decode("utf-8", errors="replace") # Fallback: extract text from text/html if no plain text found if not body.strip(): for part in msg.walk(): if part.get_content_type() == "text/html": payload = part.get_payload(decode=True) if payload: import html text = payload.decode("utf-8", errors="replace") text = re.sub(r'<[^>]+>', ' ', text) text = html.unescape(text) body = text break else: payload = msg.get_payload(decode=True) if payload: ct = msg.get_content_type() text = payload.decode("utf-8", errors="replace") if ct == "text/html": text = re.sub(r'<[^>]+>', ' ', text) import html text = html.unescape(text) body = text import re body = re.sub(r'\s+', ' ', body).strip() return body[:500] def main(): seen = load_seen() new_msgs = [] try: conn = imaplib.IMAP4_SSL(HOST, PORT) conn.login(USER, PW) conn.select("INBOX") status, data = conn.search(None, "UNSEEN") if status == "OK" and data[0]: for num in data[0].split(): status, msg_data = conn.fetch(num, "(RFC822)") if status != "OK": continue raw = email.message_from_bytes(msg_data[0][1]) sender = safe_str(raw.get("From", "")).strip() subj = safe_str(raw.get("Subject", "(no subject)")) mid = safe_str(raw.get("Message-ID", str(num))) date = safe_str(raw.get("Date", "")) if any(t.lower() in sender.lower() for t in TRUSTED): continue h = hashlib.md5(mid.encode()).hexdigest() if h in seen: continue seen.add(h) new_msgs.append({"from": sender, "subject": subj, "date": date, "body_preview": get_text_body(raw)[:500], "uid": num.decode()}) conn.store(num, "+FLAGS", "\\Seen") conn.logout() save_seen(seen) except Exception as e: print(json.dumps({"error": str(e)})) return if new_msgs: print(json.dumps({"messages": new_msgs}, indent=2)) if __name__ == "__main__": main()