Introduction
Aspose.Email FOSS for Python is a free, MIT-licensed library for creating, reading, and
converting Outlook-compatible message files in pure Python. Available on PyPI as
aspose-email-foss, it works on Windows, macOS, Linux, Docker, and serverless environments
with no Microsoft Office dependency and no proprietary runtime.
The library covers two major areas: a high-level MAPI layer (MapiMessage) for working
with message subjects, bodies, recipients, and attachments; and a low-level structural
layer (MsgReader, CFBReader, CFBStorage, CFBStream) that exposes the raw Compound
File Binary containers that underpin every .msg file.
This article walks through the key features shipped in version 26.3, grounded in the confirmed API surface.
Key Features
High-Level Message Creation with MapiMessage
MapiMessage is the primary entry point for creating Outlook-compatible messages from
scratch. Call MapiMessage.create() with a subject and body, add recipients and
attachments, then save directly to a .msg file.
from aspose.email_foss import msg
message = msg.MapiMessage.create(
"Quarterly status update",
"Hello team,\n\nPlease review the attached summary.\n\nRegards,\nEngineering",
)
message.set_property(msg.PropertyId.SENDER_NAME, "Build Agent")
message.set_property(msg.PropertyId.SENDER_EMAIL_ADDRESS, "agent@example.com")
message.add_recipient("alice@example.com", display_name="Alice Example")
message.add_recipient(
"carol@example.com",
display_name="Carol Example",
recipient_type=msg.RECIPIENT_TYPE_CC,
)
message.add_attachment("report.txt", b"Summary content here.\n", mime_type="text/plain")
message.save("output.msg")
Reading and Inspecting MSG Files
MsgReader provides structured access to an existing .msg file without fully loading it
into a MapiMessage. It exposes top-level property entries, recipient storages, and
attachment storages individually, making it practical for large-file inspection and
validation pipelines.
from aspose.email_foss import msg
with msg.MsgReader.from_file("output.msg") as reader:
header = reader.top_level_header
print(f"Recipients : {header.recipient_count}")
print(f"Attachments: {header.attachment_count}")
for entry in reader.iter_recipient_storages():
_, props = reader.parse_subobject_property_stream(entry.stream_id)
print(f" Recipient storage {entry.name}: {len(props)} property entries")
MSG Round-Trip: Load, Modify, Save
Because MapiMessage supports from_file() for loading and save() for writing, a full
read-modify-write cycle requires only a few lines. Named properties, typed enums, and
Unicode string handling are available through set_property, PropertyId, and
MapiNamedProperty.
from aspose.email_foss import msg
with msg.MapiMessage.from_file("original.msg") as message:
message.set_property(msg.PropertyId.SUBJECT, "Updated Subject")
message.save("updated.msg")
EML / RFC 5322 Conversion
MapiMessage.to_email_message() converts a loaded MSG into a standard Python
email.message.EmailMessage object, enabling export to RFC 5322 .eml format using
the standard library. The reverse direction (MapiMessage.from_email_message()) constructs
a MapiMessage from an EmailMessage.
from pathlib import Path
from aspose.email_foss import msg
with msg.MapiMessage.from_file("message.msg") as message:
eml_bytes = message.to_email_bytes()
Path("message.eml").write_bytes(eml_bytes)
# Reverse: load EML into MapiMessage
import email
raw_eml = Path("message.eml").read_bytes()
email_obj = email.message_from_bytes(raw_eml)
mapi = msg.MapiMessage.from_email_message(email_obj)
mapi.save("from_eml.msg")
CFB Container Traversal
Every .msg file is a Compound File Binary (CFB) container. CFBReader provides
read-only access to the directory tree, letting you list storages and streams, walk the
hierarchy, and extract raw stream bytes — without relying on MsgReader.
from aspose.email_foss.cfb import CFBReader
with CFBReader.from_file("message.msg") as reader:
print(f"CFB version : {reader.major_version}")
print(f"Sector size : {reader.sector_size}")
for depth, entry in reader.iter_tree():
indent = " " * depth
size = entry.stream_size if entry.is_stream() else "-"
print(f"{indent}{entry.name} [size={size}]")
Attachment Handling
Attachments are added via MapiMessage.add_attachment() (for binary data) or
MapiMessage.add_embedded_message_attachment() (for nested MSG messages). Both methods
accept a filename, raw bytes, and an optional MIME type.
from aspose.email_foss import msg
message = msg.MapiMessage.create("Attachment demo", "See files below.")
message.add_attachment("data.csv", b"id,value\n1,100\n", mime_type="text/csv")
inner = msg.MapiMessage.create("Nested message", "This is embedded.")
message.add_embedded_message_attachment(inner, "nested.msg")
message.save("with_attachments.msg")
Quick Start
pip install aspose-email-foss>=26.3
from aspose.email_foss import msg
# Create and save a minimal MSG
message = msg.MapiMessage.create("Hello World", "This is a test message.")
message.set_property(msg.PropertyId.SENDER_EMAIL_ADDRESS, "sender@example.com")
message.add_recipient("recipient@example.com", display_name="Recipient")
message.save("hello.msg")
# Load it back and convert to EML
with msg.MapiMessage.from_file("hello.msg") as loaded:
print(loaded.get_property_value(msg.PropertyId.SUBJECT))
eml = loaded.to_email_bytes()
open("hello.eml", "wb").write(eml)
Supported Formats
| Format | Extension | Read | Write |
|---|---|---|---|
| Compound File Binary | .cfb | ✓ | ✓ |
| Outlook Message | .msg | ✓ | ✓ |
| EML / RFC 5322 | .eml | ✓ | ✓ |
Open Source & Licensing
Aspose.Email FOSS for Python is released under the MIT License. The source repository is
available at github.com/aspose-email-foss and the
package is published on PyPI as aspose-email-foss. Commercial use, modification, and
redistribution are all permitted under the MIT terms.