Turn email threads into a searchable knowledge base. Parse EML files, index with embeddings, and use RAG to learn how your best engineers analyze issues.
Project description
MailWise
Turn email threads into a searchable knowledge base. Parse EML files, index with embeddings, and use RAG to learn how your best engineers analyze issues.
What it does
MailWise reads .eml files (exported from Outlook, Thunderbird, etc.), splits email threads into individual replies, and builds a semantic search index. You can then:
- Search for similar past issues using natural language
- Analyze new issues with RAG — Claude reads how your experts solved similar problems and synthesizes advice
- Tag expert engineers whose replies get boosted in search results and highlighted in output
Why
If your team handles bugs/incidents via email, years of tribal knowledge is buried in threads. MailWise makes that knowledge searchable and actionable.
Quick start
Prerequisites
- Python 3.10+
- Claude Code (for the
analyzecommand — uses your existing auth, no API key needed)
Install
From PyPI:
pip install mailwise
Or from source:
git clone https://github.com/PetrGuan/MailWise.git
cd MailWise
pip install -e .
Configure
The easiest way to get started:
mailwise init
This will walk you through setting up your EML directory, adding expert engineers, and verifying the setup.
Or configure manually:
cp config.example.yaml config.yaml
Edit config.yaml with your settings:
eml_directory: /path/to/your/eml/files
database: data/index.db
markdown_directory: markdown
embedding_model: all-MiniLM-L6-v2
expert_boost: 1.5
experts:
- email: senior.dev@company.com
name: Jane Doe
Usage
# Index your emails (incremental — only processes new/changed files)
mailwise index
# Search for similar past issues
mailwise search "sync failure after folder migration"
# Search with previews
mailwise search "calendar not updating" --show-body
# Only show expert replies
mailwise search "deleted emails reappear" --expert-only
# Deep analysis — Claude reasons over similar expert threads
mailwise analyze "User reports emails moved to local folder keep reappearing in Inbox"
# View full markdown of a specific email thread
mailwise show 42
# Check index stats
mailwise stats
Managing experts
# Add an expert
mailwise experts add engineer@company.com --name "Jane Doe"
# List all experts
mailwise experts list
# Remove an expert
mailwise experts remove engineer@company.com
How it works
EML files → Parser → Markdown + Embeddings → SQLite index
↓
Query → Semantic search → Top matches
↓
Claude (via RAG) → Expert-informed analysis
- Parse: EML files are parsed in parallel and threads are split into individual replies using Outlook-style
From:/Sent:delimiters - Clean: Microsoft SafeLinks are unwrapped, mailto artifacts are removed
- Markdown: Each thread becomes a structured markdown file with
[Expert]tags on replies from your designated engineers - Embed: Each reply is embedded using
all-MiniLM-L6-v2(runs locally, no API calls) - Index: Embeddings and metadata are stored in SQLite for fast retrieval
- Search: Cosine similarity with expert score boosting finds relevant past issues
- Analyze: Top matches are fed to Claude (via Claude Code CLI) with a system prompt that focuses on expert reasoning patterns
Performance
Designed for large mailboxes (25K+ emails, 16GB+):
| Operation | Performance |
|---|---|
| Incremental check (no changes) | ~2-3s for 25K files (stat-based, no file reads) |
| Full index | ~5-10 min (parallel parsing + batch embedding) |
| Search query | <100ms (single matrix multiply over 100K+ vectors) |
| RAG analysis | ~10-20s (retrieval + Claude response) |
Key optimizations:
- Two-phase change detection: mtime+size stat check before SHA256 hashing
- Parallel EML parsing: multiprocessing with configurable workers
- Batch embedding: pre-computed offset arrays, no O(n²) lookups
- Optimized search: loads only embedding BLOBs into contiguous numpy array; fetches metadata only for top-k results
- SQLite tuning: WAL journal, 64MB cache, 256MB mmap, batch inserts via
executemany
Architecture
src/email_issue_indexer/
├── cli.py # Click-based CLI
├── parser.py # EML parsing + thread splitting (parallel-safe)
├── markdown.py # Markdown conversion with expert tags
├── safelinks.py # Microsoft SafeLinks URL cleaning
├── embeddings.py # sentence-transformers embeddings + vector search
├── store.py # SQLite storage layer (performance-tuned)
├── indexer.py # Parallel batch orchestrator with progress tracking
├── search.py # Optimized similarity search with expert boosting
└── rag.py # RAG layer using Claude Code CLI
Privacy
All processing is local:
- Embeddings run on your machine (no data sent to any API for indexing)
- Email content stays in your local SQLite database and markdown files
- The
analyzecommand sends relevant thread excerpts to Claude — same as chatting in Claude Code
Your config.yaml, emails/, data/, and markdown/ directories are gitignored by default. Only config.example.yaml (with no real data) is committed. A pre-commit hook (scripts/install-hooks.sh) scans for accidental PII leaks.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mailwise-0.1.0.tar.gz.
File metadata
- Download URL: mailwise-0.1.0.tar.gz
- Upload date:
- Size: 30.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c4fe1cf34fe213514f49eda76e2372f86aec46f36bd7eef17e41e3c217d88e8d
|
|
| MD5 |
44d231609327e24c6e903bd77d18eecf
|
|
| BLAKE2b-256 |
f22d3fb74d8345e072c832a42f32539b009db1b889a3c50f0a0743df267f8eed
|
Provenance
The following attestation bundles were made for mailwise-0.1.0.tar.gz:
Publisher:
publish.yml on PetrGuan/MailWise
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mailwise-0.1.0.tar.gz -
Subject digest:
c4fe1cf34fe213514f49eda76e2372f86aec46f36bd7eef17e41e3c217d88e8d - Sigstore transparency entry: 1195926281
- Sigstore integration time:
-
Permalink:
PetrGuan/MailWise@b1c6ae1863ab85cb54e1a1cafc6fd20c5e00586a -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/PetrGuan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b1c6ae1863ab85cb54e1a1cafc6fd20c5e00586a -
Trigger Event:
release
-
Statement type:
File details
Details for the file mailwise-0.1.0-py3-none-any.whl.
File metadata
- Download URL: mailwise-0.1.0-py3-none-any.whl
- Upload date:
- Size: 24.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0962ccdf831b964b0b191c8ddd09fd90e9b42d5c1b389993b82c4d575240d4d2
|
|
| MD5 |
4ffd3cc81f693caf2c3cab9f6542c0f8
|
|
| BLAKE2b-256 |
dde97185d948d9110580dc722c4534d373ff91341ae55c10cc550608ca246bd9
|
Provenance
The following attestation bundles were made for mailwise-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on PetrGuan/MailWise
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mailwise-0.1.0-py3-none-any.whl -
Subject digest:
0962ccdf831b964b0b191c8ddd09fd90e9b42d5c1b389993b82c4d575240d4d2 - Sigstore transparency entry: 1195926296
- Sigstore integration time:
-
Permalink:
PetrGuan/MailWise@b1c6ae1863ab85cb54e1a1cafc6fd20c5e00586a -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/PetrGuan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b1c6ae1863ab85cb54e1a1cafc6fd20c5e00586a -
Trigger Event:
release
-
Statement type: