67 lines
2.6 KiB
Markdown
67 lines
2.6 KiB
Markdown
# Sho'Nuff Inbox Monitoring
|
|
|
|
Goal: Monitor `shonuff@germainebrown.com` for incoming replies/emails, extract content, and notify Germaine via Telegram.
|
|
|
|
## Architecture
|
|
|
|
Two-layer system:
|
|
|
|
1. **Collector script** (`shonuff-inbox-collect.py`, `no_agent=True`) — runs every 15m, checks for UNSEEN messages from non-trusted senders, outputs JSON with: from, subject, date, body_preview (first 500 chars), uid. Silent when nothing new. Marks messages as Seen after processing.
|
|
|
|
2. **LLM cron job** — takes the collector's JSON output, summarizes each message in 2-3 sentences for Germaine: who sent it, what it's about, whether action is needed. Responds with SILENT when nothing new.
|
|
|
|
## Script location
|
|
|
|
`/root/.hermes/scripts/shonuff-inbox-collect.py`
|
|
|
|
## Trusted senders (skipped, not reported)
|
|
|
|
```python
|
|
TRUSTED = ["g@germainebrown.com"]
|
|
```
|
|
|
|
The collector skips messages FROM these addresses entirely — no output, no summary. All other senders are reported.
|
|
|
|
## Known limitations
|
|
|
|
- **Apple Mail replies are HTML-only** — they often send with no `text/plain` alternative. The `get_text_body()` function strips HTML tags to extract plain text, but this can miss content that's rendered only through CSS or loaded images.
|
|
- **Body preview is truncated at 500 chars** — the LLM summary may need more context for long messages. The preview in the JSON output is an excerpt, not the full body.
|
|
|
|
## Body extraction
|
|
|
|
```python
|
|
def get_text_body(msg):
|
|
body = ""
|
|
if msg.is_multipart():
|
|
for part in msg.walk():
|
|
ct = part.get_content_type()
|
|
if ct == "text/plain":
|
|
payload = part.get_payload(decode=True)
|
|
if payload:
|
|
body += payload.decode("utf-8", errors="replace")
|
|
else:
|
|
payload = msg.get_payload(decode=True)
|
|
if payload:
|
|
body = payload.decode("utf-8", errors="replace")
|
|
body = re.sub(r'\s+', ' ', body).strip()
|
|
return body[:2000]
|
|
```
|
|
|
|
The fallback path (HTML-only) is handled by extracting `text/html` parts and stripping tags manually.
|
|
|
|
## Cron config
|
|
|
|
- Schedule: `every 15m`
|
|
- `no_agent=True` on the collector
|
|
- LLM cron reads output via `context_from` job ID
|
|
- If nothing changed from last run, the LLM responds SILENT and the user sees nothing
|
|
|
|
## Setup checklist
|
|
|
|
- [x] IMAP credentials in `.env` (`SHONUFF_EMAIL`, `SHONUFF_EMAIL_PASS`)
|
|
- [x] Collector script at `~/scripts/shonuff-inbox-collect.py`
|
|
- [x] `no_agent=True` cron at 15m
|
|
- [x] LLM cron reading collector's output
|
|
- [x] Trusted senders configured
|
|
- [x] Base64 image for signature stored at `~/references/shonuff-image-b64.txt`
|