Skip to content

Ahright11/ost2pst

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ostpst — a from-scratch OST → PST converter (pure Python, free)

Convert an orphaned Exchange .ost file into a real, spec-valid .pst — with no Outlook, no paid library (Aspose et al.), and no cost. Just Python.

ostpst reads a source mailbox with libpff (which opens both OST and PST) and writes the output PST itself, byte by byte, following the Microsoft [MS-PST] file format.

pip install libpff-python
python -m ostpst  yourfile.ost  output.pst

Why this exists

There is no free, open-source tool that writes a valid PST. Readers are plentiful (libpff, readpst, XstReader) — they export to EML/MBOX. But to get an actual .pst you normally need Microsoft Outlook or the ~$1,200 Aspose.Email library. Every "free OST→PST" project on GitHub either wraps Aspose or invents a fake format that no mail client can open.

ostpst implements the PST format directly. The reason it works where fakes fail is a validation loop: every structure we write is immediately opened back up with libpff — a completely independent, trusted reader. If libpff accepts our bytes, they are genuinely spec-valid. The whole test suite is built this way.

What it does

  • Converts .ost or .pst.pst (libpff reads both as the source).
  • Preserves the full folder tree (nested folders).
  • Copies each message's subject, plain-text body, HTML body, sender name, sender email, To/Cc display names, and delivery date.
  • Copies attachments (filename + data), byte-exact, including multi-MB files.
  • Scales: 20,000+ messages in a single folder, multi-MB message bodies and attachments, mailboxes well past the format's internal block/allocation limits — via paginated multi-level B-trees, subnode B-trees, multi-block heaps, and XBLOCK/XXBLOCK data trees.

Install

Requires Python 3.9+ and the libpff Python bindings (used for reading the source and for validation):

pip install libpff-python
# or, from a clone:
pip install -e .

Usage

Command line:

python -m ostpst  source.ost  output.pst
# or, if installed:
ostpst  source.ost  output.pst

As a library:

from ostpst.ostreader import convert
stats = convert("source.ost", "output.pst")
print(stats)   # {'folders': ..., 'messages': ..., 'attachments': ...}

Build a PST from scratch (no source file):

from ostpst.messaging import PstBuilder

b = PstBuilder()
inbox = b.add_folder(b.root, "Inbox")
msg = b.add_message(inbox, subject="Hello", body="World", sender="me@example.com")
b.add_attachment(msg, "note.txt", b"file bytes")
open("out.pst", "wb").write(b.build())

How it works (architecture)

The PST format is a stack of layers; ostpst implements each one:

ostpst/
  crc.py         weak CRC-32 (poly 0xEDB88320, seeded, no in/out inversion)
  primitives.py  NID/BID, ComputeSig, page/block trailers, geometry
  ndb.py         NDB layer: header, AMap, paginated NBT/BBT B-trees,
                 blocks, XBLOCK/XXBLOCK data trees, subnode B-trees
  ltp.py         LTP layer: multi-block Heap-on-Node, BTree-on-Heap,
                 Property Context
  tc.py          LTP layer: Table Context (subnode-backed when large)
  messaging.py   message store, folders, messages, attachments
  ostreader.py   read a source OST/PST via libpff and re-emit
  __main__.py    CLI
tests/           regression tests, every one validated against libpff

The output targets the 64-bit (Unicode) PST format with encryption set to none (a valid configuration). See FORMAT_NOTES.md for the hard-won byte-layout details reverse-engineered from libpff's source and the MS-PST spec (header offsets, dual CRC ranges, the "root folder = node whose parent is itself" rule, TCOLDESC tag order, etc.).

Limitations & fidelity notes

  • Validated against libpff, not Microsoft Outlook. libpff is a rigorous independent reader and accepts everything ostpst produces, and the bytes follow the MS-PST spec — but Outlook itself has not been the test oracle. Open the output in Outlook to confirm on your data. Bug reports welcome.
  • Recipients are carried as display strings (To/Cc names + sender email), not as a structured recipient table with individual SMTP addresses — libpff does not expose structured recipients on the source side.
  • Not copied: named/custom properties, categories, per-recipient address entries, and message flags beyond read state.
  • AMap allocation pages are written but marked invalid (fAMapValid=0), so Outlook rebuilds them on first open. This is normal for generated PSTs.

Development

pip install libpff-python pytest
python -m pytest -q          # all tests validate output against libpff

Credits & license

  • Reading and validation use libpff by Joachim Metz (via the libpff-python bindings).
  • Format details follow Microsoft's [MS-PST] Outlook Personal Folders File Format specification.

Licensed under the MIT License — see LICENSE. This project is not affiliated with or endorsed by Microsoft.

About

Convert Exchange OST files to PST — pure Python, no Outlook, no paid libraries. Writes spec-valid MS-PST, validated against libpff.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages