agentleFS
dbhq-ukdbhq-uk/outlook-graph-skill/skills/outlook-to-md/SKILL.md

outlook-to-md

Skill2 starsChanged 50 days agoMITView on GitHub

Turn Outlook mail into organised markdown archives - from a PST export, or from live mail exported by the outlook skill. Use when the user wants to convert or extract a PST or Outlook export to markdown, build a searchable email archive, or keep an existing email archive current.

  • Installs packages

1 other project uses a version of this.

Adopted by

Most recently taken up by

  • Other versions1 project uses a version of this.

    Word for word · 1

    1. dbhq-uk/outlook-skill★ 2100% same

    Edited · 0

    None found.

    Wrote their own version · 0

    None found.

    How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.

  • In this repository2 other files it gives its agents.

The file

We split this skill into the rules it gives an agent

5 rules. About 0 are common, 4 are distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈4

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Add only new emails (skips already-extracted messages by Message-ID):

    line 59
  2. Distinctive:

    If emails were already extracted with readpst elsewhere, point at the directory:

    line 95
  3. Distinctive:

    index.csv: All emails with date, sender, recipient, subject, folder, attachment count

    line 130
  4. Very specific:

    If you run readpst yourself and point this tool at the output, pass -j 0 too.

    line 160
  5. Distinctive:

    Every extraction produces a verifiable chain of custody:

    line 164

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Outlook Email to Markdown

Turn Outlook mail into an organised, integrity-verified archive of markdown files, raw email backups, and attachments. Reads a PST export, or a directory of .eml files - which is how live mail arrives, via the outlook skill's export verb. Supports full extraction and incremental append mode, so one archive can span both.

Prerequisites

  • Python virtual environment set up (run setup.sh if not done)
  • readpst (system tool from pst-utils), to read a .pst. A directory of .eml files does not need it

First-Time Setup

# Set up Python environment (one-time)
${CLAUDE_SKILL_DIR}/setup.sh

System Dependency for PST Files

readpst is the only PST reader. If setup.sh reports it missing, ask the user to install it:

# Ubuntu/Debian
sudo apt install pst-utils

# macOS
brew install libpst

Extraction Operations

Full Extraction

Extract all emails from a PST file into markdown:

# Basic extraction
${CLAUDE_SKILL_DIR}/.venv/bin/python ${CLAUDE_SKILL_DIR}/scripts/outlook_to_md.py /path/to/file.pst /path/to/output/

# Verbose output with progress
${CLAUDE_SKILL_DIR}/.venv/bin/python ${CLAUDE_SKILL_DIR}/scripts/outlook_to_md.py /path/to/file.pst /path/to/output/ --verbose

# Include deleted items
${CLAUDE_SKILL_DIR}/.venv/bin/python ${CLAUDE_SKILL_DIR}/scripts/outlook_to_md.py /path/to/file.pst /path/to/output/ --include-deleted --verbose

# Render every date in one zone (default: the offset each message was sent with)
${CLAUDE_SKILL_DIR}/.venv/bin/python ${CLAUDE_SKILL_DIR}/scripts/outlook_to_md.py /path/to/file.pst /path/to/output/ --timezone "Europe/London"

# Fix MAILER-DAEMON sent items (provide the PST owner's email)
${CLAUDE_SKILL_DIR}/.venv/bin/python ${CLAUDE_SKILL_DIR}/scripts/outlook_to_md.py /path/to/file.pst /path/to/output/ --owner-email "user@example.com"

Incremental Extraction (Append Mode)

Add only new emails (skips already-extracted messages by Message-ID):

${CLAUDE_SKILL_DIR}/.venv/bin/python ${CLAUDE_SKILL_DIR}/scripts/outlook_to_md.py /path/to/file.pst /path/to/output/ --append --verbose

Keeping an Archive Current from Live Mail

A PST is a snapshot. To carry an archive forward, export new mail with the outlook skill and append it: the two produce the same shape.

  1. Export the folder as .eml with the outlook skill's export verb, for example export "Inbox/Clients" ./staging/ --since 2026-07-01. Its own instructions give the command. --count N caps how many messages it writes, newest first (default 1000). If the outlook skill is not installed or not configured, say so and stop: this skill cannot read live mail.
  2. Append the staging directory to the existing archive:
${CLAUDE_SKILL_DIR}/.venv/bin/python ${CLAUDE_SKILL_DIR}/scripts/outlook_to_md.py \
  ./staging/ ./archive/ --append

Deduplication is by Message-ID, so a --since window that overlaps what is already archived costs bandwidth and nothing else. Graph-sourced mail is recorded under the pst_folder index column like any other; the column means "the folder this message came from".

This guarantee depends on the message actually carrying a Message-ID header. Received mail always has one, but a message with none (some drafts, some malformed mail) has no key to dedupe on and is re-archived as a fresh entry on every overlapping run. Narrow in practice, but real: there is no content-hash fallback.

Extract from Pre-Extracted .eml Directory

If emails were already extracted with readpst elsewhere, point at the directory:

${CLAUDE_SKILL_DIR}/.venv/bin/python ${CLAUDE_SKILL_DIR}/scripts/outlook_to_md.py /path/to/eml-directory/ /path/to/output/

Output Structure

output/
├── emails/
│   ├── FolderName/
│   │   ├── 2023-01-15_093042_from-john.smith_to-jane.doe_RE-Subject/
│   │   │   ├── email.md              # Formatted markdown with YAML frontmatter
│   │   │   ├── email.eml             # Raw original email (RFC 822)
│   │   │   ├── attachment_001_doc.pdf # Extracted attachments
│   │   │   └── checksums.sha256      # Per-email integrity hashes
│   │   └── .../
│   └── .../
├── index.csv                          # Machine-readable master index
├── index.md                           # Human-readable index with timeline
├── extraction_log.txt                 # Processing log with statistics
└── manifest.sha256                    # Master integrity manifest

Email Markdown Format

Each email.md contains:

  • YAML frontmatter: message_id, date, from, to, cc, subject, attachments with SHA256 hashes
  • Formatted body: HTML converted to markdown, or plain text preserved
  • Attachment links: Relative links to extracted files with sizes
  • Original headers: Full RFC 822 headers in code block

Index Files

  • index.csv: All emails with date, sender, recipient, subject, folder, attachment count
  • index.md: Timeline view grouped by year/month with links to each email

CLI Reference

outlook_to_md.py [-h] [--include-deleted] [--timezone TZ] [--verbose] [--append | --overwrite] [--owner-email EMAIL] pst_file output_dir
ArgumentDescription
pst_filePath to PST file, or directory of pre-extracted .eml files
output_dirOutput directory (created if needed)
--include-deletedInclude deleted items from PST (passes -D to readpst)
--timezone TZRender every date in this IANA zone, e.g. Europe/London. An unknown name is refused. Default: the offset each message was sent with
--verbose, -vVerbose output with per-email logging
--appendSkip emails already in archive (by Message-ID)
--overwriteReplace an existing archive: deletes its emails/ folder and index files first
--owner-email EMAILPST owner's email (fixes MAILER-DAEMON in sent items)

With neither flag, an output directory that already holds an archive is refused. Use --append to add to it. Use --overwrite only when the user has asked to rebuild it.

Extraction Backends

A directory input (pre-extracted .eml files) is handled directly and needs nothing else. A PST file is read with readpst (from pst-utils), run as readpst -j 0 -e -8 -o <tmp> <pst> with -D added by --include-deleted. Its .eml output then goes through the same path as a directory input. -j 0 turns off readpst's parallel jobs, which can drop messages without an error. If you run readpst yourself and point this tool at the output, pass -j 0 too.

Integrity Verification

Every extraction produces a verifiable chain of custody:

  1. Each email folder has checksums.sha256 (SHA256 of all its files)
  2. manifest.sha256 hashes all checksum files plus the index
  3. Source PST SHA256 is recorded in the manifest

To verify: sha256sum -c manifest.sha256

Workflow: Extract and Search

Extract, then search the markdown with ripgrep. There is no semantic index - the output is plain files on disk, so use whatever search you already trust.

# Step 1: Extract
${CLAUDE_SKILL_DIR}/.venv/bin/python ${CLAUDE_SKILL_DIR}/scripts/outlook_to_md.py archive.pst ./email-output/ --verbose

# Step 2: Search the output
rg -i "settlement agreement" ./email-output/ -l

Grep is exact, so search on names, addresses and distinctive phrases rather than concepts.

Error Handling

  • "readpst is not installed": Install pst-utils (sudo apt install pst-utils, or brew install libpst on macOS)
  • Corrupt emails: Logged to extraction_log.txt, processing continues
  • Encoding issues: Decoded with the declared charset, or as UTF-8 if Python cannot use that charset; bytes that will not decode are replaced with U+FFFD
  • Duplicate timestamps: Appended with -001, -002 suffixes
  • Path too long: Subject truncated, uniqueness preserved

Performance

ScenarioApproximate Speed
Emails without attachments~5,000/hour
Emails with attachments~2,000/hour

A typical 300MB PST (~1,000-3,000 emails) processes in 5-15 minutes.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.