221 lines
12 KiB
Markdown
221 lines
12 KiB
Markdown
# Archived source note: imap-email-triage
|
|
|
|
This reference preserves the former `imap-email-triage` SKILL.md content as source material absorbed into `email-workflows`.
|
|
|
|
The original skill package had support files and was archived intact; relative links in the original body below may refer to that archived package, not this umbrella reference. Support files were not flattened here to avoid broken package integrity.
|
|
|
|
Original support files:
|
|
- `references/apple-icloud-caldav-bill-calendar.md`
|
|
- `references/direct-imap-triage-pattern.md`
|
|
|
|
---
|
|
|
|
---
|
|
name: imap-email-triage
|
|
description: "Inspect IMAP inbox emails for spam/phishing and bill-like messages; quarantine suspected spam and notify user about bills."
|
|
version: 1.0.0
|
|
author: Hermes Agent
|
|
license: MIT
|
|
platforms: [linux, macos]
|
|
metadata:
|
|
hermes:
|
|
tags: [email, imap, spam, phishing, bills, cron, notifications]
|
|
---
|
|
|
|
# IMAP Email Triage
|
|
|
|
Use this skill when the user wants Hermes to periodically inspect an IMAP inbox, decide whether new messages are legitimate or suspected spam/phishing, move suspected spam to a quarantine folder such as `Suspected Spam`, and send notifications for likely bills.
|
|
|
|
## Requirements
|
|
|
|
Prefer Himalaya CLI if configured, because it handles IMAP folders and message moves cleanly:
|
|
|
|
```bash
|
|
himalaya --version
|
|
himalaya account list
|
|
himalaya folder list
|
|
```
|
|
|
|
If Himalaya is not configured, collect IMAP details and configure `~/.config/himalaya/config.toml` or implement a Python script with `imaplib`.
|
|
|
|
Needed from the user:
|
|
|
|
1. IMAP host, port, encryption mode, username, and app password/OAuth credential command.
|
|
2. Account/folder names: inbox folder, suspected spam folder, archive/trash policy.
|
|
3. Whether to process unread only or all new messages since last run.
|
|
4. Notification target: current Hermes chat, Telegram DM, Slack DM/channel, or calendar provider.
|
|
5. Bill notification preferences: immediate DM, calendar reminder due date, lead time, ignored senders, vendors to recognize.
|
|
6. Safety threshold for moving spam automatically; default: move only high-confidence suspected spam and leave uncertain messages in Inbox with a notification/log.
|
|
|
|
## Recommended Schedule and Throughput
|
|
|
|
Default to every 10 minutes for normal inboxes. Use every 5 minutes only when the user wants near-real-time triage and the IMAP provider rate limits are acceptable.
|
|
|
|
Do not impose arbitrary message-count caps after the user says they control the mail server or otherwise authorizes full-mailbox processing. If the bottleneck is LLM context/output size rather than IMAP server load, solve that explicitly with chunking, deterministic pre-filtering, or a local classifier summary stage; do not frame a small cap as required for server safety.
|
|
|
|
See `references/direct-imap-triage-pattern.md` for a direct-IMAP implementation pattern, including protected password files, quoted folders with spaces, and unlimited collection semantics.
|
|
|
|
## Safe Operating Rules
|
|
|
|
1. Never permanently delete suspected spam. Move it to the user-approved spam/quarantine folder only. Prefer the exact existing webmail-visible spam folder the user selects (for example `INBOX.spam`), even if another IMAP folder has the `\\Junk` special-use flag.
|
|
2. Create/verify the quarantine folder before enabling automation, or verify the existing spam folder and use that instead.
|
|
3. Start with a dry run over recent messages and report classifications before moving anything.
|
|
4. Maintain a processed-message cache keyed by Message-ID or IMAP UID to avoid repeated actions.
|
|
5. Log every action with timestamp, message UID, sender, subject, decision, confidence, and reason.
|
|
6. Fetch only headers and plain-text body/snippet unless attachment inspection is explicitly requested.
|
|
7. Treat attachments and links as suspicious metadata; do not open links or execute attachments.
|
|
8. Whitelist known legitimate senders, banks, utilities, payroll, and recurring vendors where appropriate.
|
|
|
|
## Classification Rubric
|
|
|
|
Classify each message as one of:
|
|
|
|
- `legit`: normal expected email.
|
|
- `suspected_spam`: unsolicited marketing, obvious scam, phishing, spoofing, malware lure, fake invoice, or high-risk sender/auth mismatch.
|
|
- `bill_or_invoice`: likely bill, invoice, statement, payment due, renewal, receipt needing attention, or overdue notice.
|
|
- `uncertain`: insufficient confidence; do not move automatically.
|
|
|
|
Signals for suspected spam/phishing:
|
|
|
|
- Sender domain mismatch or display-name spoofing.
|
|
- User-maintained blocked sending domains are high-confidence suspected spam. When the user says to add sending domains to the spam list, update both the deterministic triage helper's blocked/base-domain list (for example `USER_BLOCKED_SPAM_DOMAINS` in `/root/.hermes/scripts/imap_triage.py` on this profile) and the active cron job prompt so future LLM runs treat those domains as move-to-spam. Match by base domain so subdomains such as `offers.example.com` inherit `example.com`.
|
|
- After editing a blocked-domain list, verify with `python3 -m py_compile /root/.hermes/scripts/imap_triage.py` and a small import/probe of `sender_reputation_hints()` to confirm each requested domain returns a blocked-domain hint.
|
|
- Low-reputation or abuse-prone sender domains/TLDs, especially unsolicited mail from `.click`, `.xyz`, `.top`, `.site`, `.icu`, `.buzz`, `.quest`, `.monster`, `.sbs`, `.shop`, `.pw`, `.loan`, `.download`, `.stream`, or similar domains.
|
|
- Random-looking sender domains/subdomains, typo/lookalike domains, or domains with no clear relationship to the claimed sender.
|
|
- Brand-spoof claims where the sender pretends to be a known brand from an unrelated/lookalike domain.
|
|
- Sensitive financial/order/security claims from freemail senders, e.g. PayPal/Amazon/bank/payment notices from Gmail/Yahoo/Outlook accounts.
|
|
- Suspicious links, URL shorteners, lookalike domains.
|
|
- Unexpected attachments, macros, executables, password-protected archives.
|
|
- Generic greeting plus financial/security demand.
|
|
- Message claims to be from a known vendor but differs from historical sender/domain patterns.
|
|
|
|
Avoid false positives:
|
|
|
|
- Do not classify newsletters as brand-spoof spam just because the subject mentions a brand, agency, or payment topic in a news headline. Example: a legitimate news newsletter headline mentioning Social Security is not a Social Security spoof unless the sender claims to be the Social Security Administration or asks for account/payment action.
|
|
- Do not classify ordinary retail marketing from real brand domains as spam solely because the subject contains words like "lowest", "sale", "points", "reward", "bonus", or "season".
|
|
|
|
Signals for bill/invoice:
|
|
|
|
- Subject/body contains invoice, bill, statement, payment due, amount due, renewal, past due, autopay, subscription, receipt, tax, premium, utilities.
|
|
- Sender matches historical billing vendors.
|
|
- Body includes due date, amount, account/customer number, invoice number, or payment link.
|
|
- Message resembles previous legitimate bills from the same sender/domain.
|
|
|
|
## Implementation Options
|
|
|
|
Prefer Himalaya CLI when it is installed and configured. If Himalaya is missing or the user wants a minimal dependency path, use Python stdlib `imaplib` directly instead. A direct-IMAP helper script works well for:
|
|
|
|
- verifying TLS login with `imaplib.IMAP4_SSL(host, 993, ssl_context=ssl.create_default_context())`
|
|
- listing folders via `M.list()`
|
|
- collecting headers/body snippets via UID fetches
|
|
- copying suspected spam to a quarantine folder with `UID COPY`, then marking the original `\Deleted` and expunging
|
|
- keeping a local processed-UID state file and JSONL audit log under `~/.hermes/`
|
|
|
|
Direct-IMAP scripts should use only protected password files or secret-manager commands, never hardcoded passwords. Use `chmod 600` for password files and verify login before creating scheduled jobs.
|
|
|
|
### IMAP folder names with spaces
|
|
|
|
When creating or selecting folders with spaces via Python `imaplib`, quote the mailbox name explicitly. `imaplib.create('Suspected Spam')` may be sent as two atoms and create the wrong folder (`Suspected`) on some servers. Use a quoted command or a helper that quotes/escapes mailbox names:
|
|
|
|
```python
|
|
def q(name: str) -> str:
|
|
return '"' + name.replace('\\\\', '\\\\\\\\').replace('"', '\\\\"') + '"'
|
|
|
|
M._simple_command('CREATE', q('Suspected Spam'))
|
|
M.uid('COPY', uid, q('Suspected Spam'))
|
|
```
|
|
|
|
After creation, list folders and clean up any accidental empty test folder only after verifying it contains zero messages.
|
|
|
|
## Himalaya Workflow
|
|
|
|
List folders:
|
|
|
|
```bash
|
|
himalaya folder list
|
|
```
|
|
|
|
List recent inbox envelopes as JSON:
|
|
|
|
```bash
|
|
himalaya envelope list --folder INBOX --page-size 20 --output json
|
|
```
|
|
|
|
Read a candidate message:
|
|
|
|
```bash
|
|
himalaya message read <ID> --folder INBOX
|
|
```
|
|
|
|
Create the quarantine folder if missing (check installed Himalaya help for exact command; command names vary by version):
|
|
|
|
```bash
|
|
himalaya folder --help
|
|
```
|
|
|
|
Move high-confidence suspected spam:
|
|
|
|
```bash
|
|
himalaya message move <ID> "Suspected Spam" --folder INBOX
|
|
```
|
|
|
|
Message IDs can be folder-relative. Re-list after moves and prefer UID/Message-ID caches when scripting.
|
|
|
|
## Cron Job Pattern
|
|
|
|
Use Hermes cron for the schedule. Attach this skill and the `himalaya` skill. The cron prompt should be self-contained and include:
|
|
|
|
- Account name and folders.
|
|
- Dry-run vs active mode.
|
|
- Classification threshold.
|
|
- Notification target and bill reminder policy.
|
|
- Instruction to summarize actions and notify only on bill/uncertain/high-risk events.
|
|
|
|
Example schedule: `every 10m`.
|
|
|
|
## Verification
|
|
|
|
Before enabling active mode:
|
|
|
|
1. `himalaya account list` succeeds.
|
|
2. `himalaya folder list` shows Inbox and `Suspected Spam` or the folder can be created.
|
|
3. Dry run classifies a sample of recent messages without moving them.
|
|
4. A test notification reaches the requested Slack/Telegram/current chat destination.
|
|
5. Active run moves one known test spam message to `Suspected Spam` and logs the action.
|
|
6. `hermes cron status` says `Gateway is running — cron jobs will fire automatically`.
|
|
7. `hermes cron list --all` shows the triage job enabled with a future `Next run`.
|
|
|
|
### Scheduler/Gateway Setup on Linux Servers
|
|
|
|
Hermes cron jobs fire from the gateway scheduler. If `hermes cron status` says the gateway is not running, the email triage script may work manually but scheduled automation will not run.
|
|
|
|
Recommended VPS setup:
|
|
|
|
```bash
|
|
hermes gateway install --system --run-as-user root --force
|
|
hermes gateway status
|
|
hermes cron status
|
|
hermes cron list --all
|
|
journalctl -u hermes-gateway -n 120 --no-pager
|
|
```
|
|
|
|
If the install command prompts for starting/enabling the service in a non-interactive run, answer yes to both prompts:
|
|
|
|
```bash
|
|
yes Y | hermes gateway install --system --run-as-user root --force
|
|
```
|
|
|
|
Use `--run-as-user <service-user>` instead of `root` on bare-metal hosts when a non-root Hermes profile owns the config. Running as root is acceptable for root-owned VPS/container installs where `HERMES_HOME=/root/.hermes` is the intended profile.
|
|
|
|
A gateway warning like `No messaging platforms enabled` does not by itself block cron scheduling; verify cron specifically with `hermes cron status` and the job's `Next run` advancement.
|
|
|
|
## Pitfalls
|
|
|
|
- IMAP folder names vary by provider (`INBOX`, `Junk`, `[Gmail]/Spam`, etc.). Always list folders first.
|
|
- Gmail and Microsoft often require app passwords/OAuth, not the account password.
|
|
- Some providers throttle frequent polling; increase interval if errors appear.
|
|
- Calendar reminders require a configured calendar integration or a separate notification fallback.
|
|
- For Apple Calendar/iCloud CalDAV bill events, use a protected app-specific-password file and the discovery/create flow in `references/apple-icloud-caldav-bill-calendar.md`.
|
|
- A successful icloud.com web login with the user's normal Apple ID password does not validate CalDAV automation; iCloud CalDAV requires an Apple app-specific password and returns HTTP 401 when the server-side file contains the wrong or truncated credential.
|
|
- LLM classification is probabilistic. Use conservative thresholds and keep an audit trail.
|