eml-to-jsonl
EML parser for shell pipelines.
Reads .eml files and outputs structured JSONL — one JSON object per message — to stdout.
Designed to compose with lite-llm and other tools for email analysis pipelines.
Features
- Extracts headers:
from, to, cc, bcc, subject, date, message_id, in_reply_to, x_mailer, received
- Decodes all content to UTF-8; records original charset in the
encoding field
- Handles multipart bodies:
text/plain preferred, text/html included when present
- Decodes
base64, quoted-printable, 7bit, and 8bit transfer encodings
- Supports Japanese charsets: ISO-2022-JP, Shift_JIS, EUC-JP (and any IANA-registered charset)
- Attachment metadata (filename, MIME type, size) without embedding binary content
- Input: stdin, file arguments, or directory (processes all
*.eml in the directory)
Installation
git clone https://github.com/nlink-jp/eml-to-jsonl.git
cd eml-to-jsonl
make build
# Add dist/ to PATH or copy dist/eml-to-jsonl to a directory on PATH
Usage
# Single file
eml-to-jsonl message.eml
# Multiple files
eml-to-jsonl mail1.eml mail2.eml
# Directory (processes all *.eml)
eml-to-jsonl ~/exported-mail/
# Stdin
cat message.eml | eml-to-jsonl
# Pretty-print for inspection
eml-to-jsonl --pretty message.eml
# Pipe into lite-llm for analysis
eml-to-jsonl inbox/ | lite-llm -p "Summarise each email in one sentence."
Each message produces one JSON line:
{
"source": "inbox/message.eml",
"message_id": "<abc123@example.com>",
"in_reply_to": "<xyz@example.com>",
"from": "Alice <alice@example.com>",
"to": ["Bob <bob@example.com>"],
"cc": ["Carol <carol@example.com>"],
"bcc": [],
"subject": "Hello World",
"date": "2026-03-27T10:00:00+09:00",
"x_mailer": "Apple Mail",
"received": [
"from mx2.example.com by mx1.corp.com; Mon, 30 Mar 2026 09:00:00 +0900",
"from sender.example.org by mx2.example.com; Mon, 30 Mar 2026 08:59:55 +0900"
],
"encoding": "ISO-2022-JP",
"body": [
{"type": "text/plain", "content": "Hello..."},
{"type": "text/html", "content": "<html>...</html>"}
],
"attachments": [
{"filename": "report.pdf", "mime_type": "application/pdf", "size": 102400}
]
}
Body ordering rules:
text/plain is always listed first if present.
text/html follows.
- If the message is HTML-only, a single
text/html part is output.
Encoding field:
Set to the original charset of the primary text part (e.g. ISO-2022-JP).
Omitted when the message is already UTF-8 or ASCII.
Attachments:
Only metadata is included (filename, MIME type, decoded byte size).
Binary content is not embedded in the output.
Flags
| Flag |
Default |
Description |
-pretty |
false |
Pretty-print JSON instead of JSONL |
-version |
— |
Print version and exit |
Building
make build # current platform
make build-all # all release platforms → dist/
make test # run tests
make check # vet + lint + test + build + govulncheck
Documentation
Working with PST files
Outlook PST (Personal Storage Table) files can be converted to EML using
readpst and then processed with eml-to-jsonl:
# Install readpst
# macOS: brew install libpst
# Debian/Ubuntu: apt install pst-utils
# Convert PST to EML files
readpst -e -o /tmp/pst-output/ archive.pst
# Parse all extracted EML files
eml-to-jsonl /tmp/pst-output/
# Pipeline: PST → EML → JSONL → LLM analysis
readpst -e -o /tmp/pst-output/ archive.pst && \
eml-to-jsonl /tmp/pst-output/ | gem-cli --batch -s "Summarize each email"
This approach also works with msg-to-jsonl —
use readpst -m to output MSG format instead of EML.
Part of util-series
eml-to-jsonl is part of the util-series —
a collection of lightweight CLI tools for working with local and cloud LLMs.