Skip to content

Repository files navigation

AI Mail Watcher & Calendar Agent

Platform Optimized for Python LLM License

A privacy-first macOS daemon that watches your IMAP mailbox, classifies incoming messages with a fully local LLM (Qwen2.5-14B-Instruct), silently discards spam, and automatically creates Calendar events for work-related emails — no cloud API, no third-party data sharing, ever.

Optimized for Apple Silicon. Sentinella is built primarily around MLX, Apple's native ML framework, to get the best inference speed and memory efficiency out of the Neural Engine/GPU on M-series chips. Intel Macs are also supported via a llama.cpp fallback, but Apple Silicon is the reference, best-performing platform this project is designed for.

Built for a personal Italian mailbox: the scheduling logic understands Italian public holidays and skips weekends when auto-picking task due dates.

Features

  • 🔒 100% local LLM inference — no email content ever leaves your machine (Qwen2.5-14B-Instruct via MLX or llama.cpp, no external API calls)
  • 🧠 Smart LAVORO/SPAM classification with structured JSON output (title, summary, due date) used to build the calendar event
  • 🚫 Two-layer spam filtering — a deterministic sender/domain blocklist (.env + editable blocklist_mittenti.txt, reloaded before every scan) short-circuits obvious spam before it ever reaches the LLM
  • 📅 Italian holiday-aware scheduling — fallback due dates automatically skip weekends and Italian public holidays (via the holidays library)
  • 🛡️ Prompt-injection guardrail — the LLM is explicitly instructed to treat email content as untrusted data, never as commands
  • 🧹 Automatic data retention — local history and logs older than 15 days are purged automatically; attachments are never written to disk (they already live in the original email)
  • 🔐 Hardened by design — restrictive umask 077, 0600/0700 permissions enforced on every stored file, AppleScript-injection sanitized inputs, path-traversal-safe file handling, and pinned dependencies (including pinned Hugging Face model revisions for supply-chain safety)
  • Apple Silicon-optimized, adaptive AI backend — automatically picks the native MLX engine on M-series chips for best performance, with a llama.cpp (GGUF) fallback and dynamic CPU thread sizing on Intel Macs

Prerequisites

This project is built specifically for macOS, since Calendar integration relies on AppleScript (osascript) — it will not run on Windows or Linux.

  • macOS 13.5 (Ventura) or later with the Calendar app configured (required by mlx-lm on Apple Silicon)
  • Python 3.12+
  • One of:
    • Apple Silicon (M-series) → uses mlx-lm, Apple's optimized ML framework
    • Intel Mac → uses llama-cpp-python with a quantized GGUF model

⚠️ On Intel Macs, a plain pip install builds llama-cpp-python in slow CPU-only mode. See the comment above llama-cpp-python in requirements.txt for the recommended CMAKE_ARGS build flags (hardware-accelerated BLAS backend).

Hardware Requirements

This is not a lightweight script: on every scan cycle it loads a full 14-billion-parameter LLM (Qwen2.5-14B-Instruct) into memory, runs inference, then unloads it. Plan your hardware accordingly.

Resource Minimum Recommended
RAM / unified memory 16 GB 32 GB (comfortable multitasking while the model is loaded)
Free disk space 12 GB 20 GB (model weights + Python dependencies + headroom for updates)
Apple Silicon Any M-series chip (M1–M4)
Intel Mac CPU Multi-core, with llama-cpp-python built against a BLAS backend (see warning above)

Actual model download size, verified from the Hugging Face repos pinned in watcher.py:

  • MLX 4-bit build (Apple Silicon): ~8.3 GB
  • GGUF Q4_K_M build (Intel): ~9.0 GB

With only 16 GB of RAM/unified memory, expect the OS and other running apps to be tightly squeezed while a scan cycle is in progress; the daemon does unload the model between cycles (unload_llm()) to free that memory back up for the rest of the system.

Installation & Setup

git clone https://github.com/Pharma-Py/Sentinella_mail-IT-.git
cd Sentinella_mail-IT-

python3 -m venv .venv
source .venv/bin/activate

pip install -r requirements.txt

cp .env.example .env
# then edit .env with your IMAP server and email address

cp blocklist_mittenti.example.txt blocklist_mittenti.txt
# optional: list sender addresses/domains to always treat as SPAM

Keychain Setup

Your email password is never stored in .env or anywhere on disk in plain text. It is saved through Python's keyring library into your Mac's local "login" Keychain — the one managed by Keychain Access.appnot the iCloud Keychain. This is intentional: the login Keychain stays on this Mac and is never synced to your other Apple devices, which is the correct scope for a background daemon's credential.

  1. Make sure EMAIL_USER is already set in .env (see Installation & Setup above) — set_password.py reads it from there.
  2. Run:
    python3 set_password.py
  3. Enter your email password when prompted (input is hidden, never echoed to the terminal or written to any file).
  4. The password is stored under the service name ai_mail_watcher, keyed to your EMAIL_USER, and read back by watcher.py at every scan cycle.

To verify or revoke it later, open Keychain Access.app → search for ai_mail_watcher → the entry is listed under the "login" keychain (not under "iCloud").

Running in Production

Once configured, start the watcher with:

python3 watcher.py

For continuous background operation, wrap it in a launchd .plist (recommended, native to macOS) or trigger it via an Automator application/calendar trigger. The script itself manages a night-time pause window and a batch scan interval internally — no external scheduler cron logic is required beyond keeping the process alive.

Verification / Testing

A self-contained test suite (verify_sentinella.py) validates the core logic and can optionally audit a live installation:

# Logic tests only (no running instance required)
python3 verify_sentinella.py

# Logic tests + installation audit
python3 verify_sentinella.py /path/to/Watcher

The suite covers: JSON extraction, LLM output validation, date/time resolution (weekends, Italian holidays, night-hour clamping, far-future cap), atomic file writes, email text extraction (plain-text preference, attachment exclusion), file permissions, and environment checks.

Security Architecture

Security was treated as a first-class requirement, not an afterthought:

  • Restrictive umask 077 at startup ensures every file and folder created by the process (mail data, logs, downloaded models) is readable only by its owner; a secure_permissions() sweep also hardens any pre-existing files to 0600/0700.
  • No attachments on disk — attachment names are passed to the LLM as context, but their content is never written locally, since it already exists in the source email on the IMAP server.
  • AppleScript-injection-proof — calendar event values are passed via osascript argv (no string interpolation), with control characters stripped from all LLM-generated text.
  • Prompt-injection guardrail — the system prompt explicitly instructs the model to treat email content as untrusted data and to never execute or emit instructions/commands beyond the requested JSON classification.
  • Path-traversal-safe handling of filenames extracted from untrusted email headers.
  • Pinned dependencies, including pinned Hugging Face model revisions (commit SHAs) for both the MLX and GGUF model downloads, to prevent silent supply-chain changes.
  • Automatic data retention — local history/log entries older than 15 days are purged on every scan cycle.

Changelog

V1.1

  • Robust JSON extraction — brace-depth-tracking parser replaces brittle string slicing; handles unclosed fences, model preamble, trailing text
  • Fail-open LLM validation — unknown categoria defaults to LAVORO (false positive > missed task); case-insensitive normalization, type/length checks, control-char stripping
  • Holiday-aware date resolution — injectable now= for testing; far-future cap (365 days), night-hour clamp (< 7 or >= 20 → 09:00)
  • Silent task-loss preventionmark_as_processed() only on confirmed success; LLM/calendar failures → retry on next cycle
  • Argv-based AppleScript — no string interpolation = no injection risk; calendar alarm added; WORK_AI must pre-exist (no auto-create to iCloud)
  • IMAP hardening — UID-based commands, BODY.PEEK[], explicit SSL context, 30s timeout, finally close/logout, UIDVALIDITY fallback IDs
  • Single-instance lockfcntl.flock prevents duplicate model loads
  • Atomic history.log writes — write-tmp + os.replace() with 0600 permissions
  • Email extraction — skips attachment parts, prefers plain text over HTML
  • wait_for_system_idle timeout — max 120 min to prevent infinite block
  • Test suite (verify_sentinella.py) — 28 tests covering all core logic
    • optional installation audit

License

MIT

About

Privacy-first macOS 13.5+ (Ventura+) daemon: reads your IMAP inbox with a 100% local LLM (Qwen via MLX/llama.cpp, no API keys, no cloud), filters spam before/after inference, and auto-creates Calendar events via AppleScript for work tasks — Italian holiday-aware scheduling, hardened permissions.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages