Local Flask app for inspecting .eml email files. It extracts core headers, authentication results, Received hops, MIME structure, bodies, attachments, X-headers, and IOCs.
- Upload
.eml,.msg,message/rfc822, or plain text email files. - Paste raw headers or full EML content.
- Parse SPF, DKIM, DMARC, and ARC results from
Authentication-Results. - Build oldest-first
Receivedhop timeline with delay values. - Extract public IPv4 addresses, domains, URLs, and attachment SHA-256 hashes.
- Display MIME tree, raw headers, HTML/plain body, attachments, and X-header vendor groups.
- Render HTML email body in a sandboxed iframe.
- Disable rendered email links while preserving visual link hints.
- Right-click disabled rendered links to copy their original URL.
- Download attachments as
.binby SHA-256 ID after analysis.
| File | Purpose |
|---|---|
main.py |
Flask backend, parser, routes, attachment download store |
eml-analyzer.html |
Frontend HTML and JavaScript |
static/eml-analyzer.css |
Frontend styling |
requirements.txt |
Python dependencies |
documentation.md |
Function-level code documentation |
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtgoogle-re2 is declared for safer regex behavior. If unavailable, main.py falls back to Python stdlib re.
python main.pyDefault URL:
http://127.0.0.1:5000/
Options:
python main.py -p 8080
python main.py -i 0.0.0.0 -p 5000
python main.py -dServes eml-analyzer.html.
Multipart upload endpoint.
Field:
file=<email file>
Returns parsed JSON.
JSON endpoint for pasted raw email.
{
"raw": "From: sender@example.com\n..."
}Returns parsed JSON.
Downloads an attachment from the in-memory store. The store is refreshed on each parse, so re-analyze first if a file is no longer available.
Returns:
{"status": "ok"}This app is intended for local or trusted-LAN use. Do not expose it publicly without authentication and additional hardening.
Current safeguards:
- 20 MB Flask request limit.
- CSRF origin/referer check for analysis endpoints.
- Security headers and
no-storecache header. - MIME traversal depth cap.
- HTML body size cap before base64 response.
- Rendered email links have
hrefremoved in the iframe. - Attachment downloads force
.binfilenames.
Syntax-check frontend JavaScript:
node -e "const fs=require('fs'); const html=fs.readFileSync('eml-analyzer.html','utf8'); const m=html.match(/<script>([\\s\\S]*)<\\/script>/); new Function(m[1]); console.log('frontend ok')"Python syntax check:
python -B -m py_compile main.py