python-oxmsg

Parse Outlook .msg files in Python to extract email text, headers, recipients, and attachments without needing Outlook installed.

Library
PyPI
v0.0.2
19stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
18/100Needs Attention
Development Activity0
Maintenance0
Community12
Maturity48
Momentum12

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
71/100Good
Architecture80
Code Quality85
Innovation55
Learning Curve65

python-oxmsg is a pure-Python library for reading Microsoft Outlook MSG (.msg) files — the binary Compound File Binary format Outlook uses to save individual email messages to disk. It parses the file’s OLE/CFB storage structure and Microsoft’s MS-OXMSG/MS-OXPROPS property scheme directly, exposing the sender, subject, plain-text and HTML body, recipients, and attachments (including raw attachment bytes) through a small, typed Python API.

Because it works from the raw binary layout rather than shelling out to Outlook or a COM automation bridge, it runs anywhere Python runs — Linux servers, CI pipelines, containers — making it well suited to email-ingestion pipelines, e-discovery/forensics tooling, and any workflow that needs to bulk-process archived .msg exports without a Windows/Outlook dependency.

What You Get

  • A Message.load() entry point that accepts a file path, file-like object, or raw bytes and validates the OLE magic bytes before parsing
  • Typed access to core message fields — subject, sender, body, html_body, sent_date, message_class, and raw message_headers
  • Attachment objects exposing file_name, mime_type, size, last_modified, and the raw file_bytes for saving to disk
  • Recipient objects for each To/Cc/Bcc entry on the message
  • A bundled oxmsg CLI (oxmsg dump, oxmsg storage) for inspecting a .msg file’s raw property table and storage tree during debugging

Common Use Cases

  • Bulk-extracting attachments from an archive of exported .msg files without opening Outlook
  • Feeding email subject/body/sender text into a search index or ML pipeline from a Linux/CI environment
  • E-discovery and forensic tooling that needs to read raw MS-OXMSG properties from evidence files
  • Migrating archived Outlook messages into another mail store or database

Under The Hood

Architecture Message.load() hands a .msg file to olefile.OleFileIO, then Storage.from_ole() (src/oxmsg/storage.py) recursively walks the OLE directory tree into an immutable dataclass tree of Storage/Stream nodes that mirror the file’s internal “directories and files” layout. Message, Attachment, and Recipient (message.py, attachment.py, recipient.py) are thin façades over a Storage plus a Properties view constructed at a type-specific header offset (MSG_HDR_OFFSET vs ATTACH_HDR_OFFSET in domain/model.py). Properties (properties.py) parses the raw property-segment bytes into typed objects via BaseProperty.factory(), which dispatches on the MS-OXPROPS property-type code. This cleanly separates three concerns — raw container format, binary property decoding, and the public domain API — so a change to the OLE storage layer would ripple through Properties but leave Message’s public surface untouched.

Tech Stack Pure Python 3.9+ with from __future__ import annotations throughout; olefile does the low-level Compound File Binary parsing and click powers the bundled CLI, with typing_extensions>=4.9.0 backporting newer typing features. Packaging uses a pyproject.toml-only setuptools build with a dynamic version pulled from oxmsg.__version__. Documentation is authored in Markdown and built with MkDocs, published to GitHub Pages. Dev tooling layers ruff (lint) and black (format) on top of pytest for tests and pyright in strict mode for type-checking, with a hand-written typings/ stub directory supplying types for the otherwise-untyped olefile dependency, all wired into a GitHub Actions CI workflow.

Code Quality The test suite (~600 lines across test_message.py, test_attachment.py, test_storage.py, test_recipient.py, and test_properties.py) uses a BDD-flavored pytest configuration (Describe/it_/they_ naming) and exercises each layer independently. Type safety is unusually rigorous for a project this size: pyright runs in strict mode with reportImportCycles, reportUnnecessaryCast, and reportUnnecessaryTypeIgnoreComment all enabled, backed by custom stubs for olefile. Error handling is explicit rather than swallowed — Message.load() raises ValueError on a bad magic-byte check, and internal invariants are asserted rather than silently defaulting. Naming is consistent throughout (private members prefixed with an underscore, lazyproperty used pervasively for memoized derived values), and ruff/black plus CI enforce style on every push.

What Makes It Unique Rather than wrapping an existing MSG-parsing library, python-oxmsg implements Microsoft’s MS-OXMSG/MS-OXPROPS binary property scheme directly — a typed dispatch table (BaseProperty.factory) covering binary, boolean, float, GUID, 16/32-bit integer, string, 8-bit string, and time property types — and it specifically handles the subtle encoding chicken-and-egg problem where the codepage needed to decode string properties is itself stored as a property that must be cherry-picked before the rest of the property collection can be decoded. It’s a narrowly scoped reimplementation of an established format rather than a novel technique, but the property-type handling is more careful about correctness than many ad hoc MSG parsers.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search