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

FormatExtensionReadWrite
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.


Getting Started