# Inbox Solicitation Triaging — Design & Pitfalls

Pattern for cleaning an inbox by classifying and moving solicitations.

## Core Technique

1. **Connect via IMAP (imaplib)**, select INBOX, fetch ALL messages
2. **Iterate each message** with `BODY.PEEK[]` (non-destructive read — doesn't mark as seen)
3. **Run multi-heuristic solicitor detection** on sender domain, subject line, and body text
4. **Copy flagged to target folder**, then `+FLAGS \\Deleted` + `EXPUNGE` from INBOX
5. **Save detailed JSON report** and print a grouped summary

## Multi-Heuristic Detection Strategy

Four layered checks:

### 1. Allowlist Bypass (highest priority)
- **Internal senders** (first-name patterns, company domain): skip entirely
- **Legit domains** (`boxpilotlogistics.com`, etc.): skip entirely

### 2. Subject-Line Keywords (high signal)
Immediate giveaways: "insurance quote", "free quote", "factoring", "compliance", "load board", "mc number", "advertisement"

### 3. Body Content Analysis (by sender domain class)

**Free/personal domains** (gmail, yahoo, outlook, etc. — defined in FREE_DOMAINS set):
- If sender has free domain AND references an external business domain in the body → strong solicitation signal
- Also scan for solicitation keywords + phrases in body text

**Business-domain senders** (not free, not internal):
- Count multiple trucking-solicitation signals (keywords + phrases)
- Threshold: 2+ signals = solicitation

**Transactional invoice guard:** If subject/body contains ≥2 invoice keywords ("invoice", "receipt", "payment confirmation") and no other signals triggered, keep in inbox.

### 4. Combined Signal Accumulation
- Body keywords: +1 each
- Solicitation phrases: +2 each (trucking-specific phrases are stronger)
- Subject keyword match: +1
- Threshold: 2+ total = flagged

## Known False-Positive Categories

| Category | Why flagged | Typical senders | Action |
|---|---|---|---|
| Government registration notices | Body has "fmcsa", "usdot", "authority" | ucr.gov, login.gov, dot.gov | Move back — official notices |
| Bank product promos | Boilerplate contains "eld", "limited time" | americanexpress@blueprint.americanexpress.com | Review individually |
| Slack onboarding | Template has "eld", "limited time" in footer | no-reply@email.slackhq.com | Keep transactional, move promos |
| FMCSA process agent confirmations | Body has "boc-3", "process agent", "fmcsa" | fmcsaprocessagents.com | Keep if service was ordered |

## Pitfalls

- **HTML boilerplate noise**: Some email templates (Amex, Slack) contain trucking keywords like "eld" in their footer HTML. The heuristic catches them as false positives. Mitigation: whitelist known transactional templates or strip common boilerplate before matching.
- **UCR.gov is legitimate** but its subject/body triggers "compliance", "authority", "usdot". These are official registration notices, not solicitations.
- **BODY.PEEK[] vs BODY[]**: Always use PEEK to avoid marking messages as read during review.
- **IMAP COPY + STORE \\Deleted** is the portable move pattern. Some servers support `MOVE` but not all.
- **conn.expunge()** must be called after all deletions or the messages remain hidden but not freed.
- **Character encodings**: Fall back through `utf-8` → `iso-8859-1` → `windows-1252` when `get_content_charset()` returns None.
- **HTML-only emails**: Need regex tag stripping (`re.sub(r'<[^>]+>', ' ', body)`) before keyword matching. CSS class names (`style-Xia0GT4t_-text`) are noise — filter them out.

## Script

See `scripts/inbox-solicitation-cleaner.py` — a standalone runnable script with the full heuristic set. Adjust the Config block (host, credentials, folder name) and run:
```bash
python3 scripts/inbox-solicitation-cleaner.py
```
