Introduction
Aspose.Email FOSS for Python goes beyond basic message creation. The library exposes the full depth of the MAPI property model, letting you read, write, and query individual properties by ID and type. It handles recipients, attachments, and embedded messages as first-class objects, and provides bidirectional conversion between the MSG binary format and Python’s standard email.message.EmailMessage.
At the container level, the CFB reader and writer give you deterministic control over Compound File Binary documents. You can traverse storage hierarchies, extract raw stream data, build new containers from scratch, and serialize them back to bytes. Both CFBError and MsgError provide structured exception handling for malformed input.
This post walks through each capability with verified code examples drawn directly from the library’s own test suite and example scripts.
What’s Included
MAPI Property Access
Every MSG file is built on MAPI properties. MapiMessage exposes set_property() and get_property() to work with properties by their PropertyId enum value. Use iter_properties() to enumerate all properties on a message, or get_property_value() for direct value retrieval with optional type decoding.
from aspose.email_foss import msg
message = msg.MapiMessage.create("Status report", "Weekly update attached.")
message.set_property(msg.PropertyId.SENDER_NAME, "Build Agent")
message.set_property(msg.PropertyId.SENDER_EMAIL_ADDRESS, "build.agent@example.com")
message.set_property(msg.PropertyId.DISPLAY_TO, "Alice Example; Bob Example")
message.set_property(msg.PropertyId.DISPLAY_CC, "Carol Example")
message.set_property(msg.PropertyId.DISPLAY_BCC, "Ops Archive")
message.set_property(
msg.PropertyId.TRANSPORT_MESSAGE_HEADERS,
"X-Environment: production\nX-Workflow: weekly-report\n",
)
message.save("report.msg")
To read properties back from an existing file:
from aspose.email_foss import msg
with msg.MapiMessage.from_file("report.msg") as loaded:
print(f"Subject: {loaded.subject}")
print(f"Body: {loaded.body}")
for prop in loaded.iter_properties():
print(f"tag=0x{prop.property_tag:08X}")
Recipients and Attachments
Add recipients with add_recipient(), specifying display name and recipient type (To, CC, or BCC). Attach files with add_attachment() using raw bytes and a MIME type. For nested messages, add_embedded_message_attachment() embeds a complete MapiMessage as a child object inside the parent.
from aspose.email_foss import msg
message = msg.MapiMessage.create("Team update", "See attached notes.")
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_recipient(
"archive@example.com",
display_name="Ops Archive",
recipient_type=msg.RECIPIENT_TYPE_BCC,
)
message.add_attachment("notes.txt", b"Meeting notes content\n", mime_type="text/plain")
message.add_attachment("data.bin", b"\x00\x01\x02\x03", mime_type="application/octet-stream")
message.save("team-update.msg")
To inspect attachments on an existing message:
from aspose.email_foss import msg
with msg.MapiMessage.from_file("team-update.msg") as loaded:
for att in loaded.iter_attachments_info():
print(f"name={att.filename} mime={att.mime_type} size={len(att.data)}")
print(f" embedded={att.is_embedded_message} storage={att.storage_name}")
MSG to EmailMessage Conversion
The library converts in both directions between MSG and Python’s email.message.EmailMessage. Use to_email_message() to produce a standards-compliant MIME object, or from_email_message() to import an existing EmailMessage into the MSG format. Convenience methods to_email_bytes() and to_email_string() serialize directly to bytes or text.
from aspose.email_foss import msg
with msg.MapiMessage.from_file("example.msg") as loaded:
email_msg = loaded.to_email_message()
print(f"content_type: {email_msg.get_content_type()}")
print(f"is_multipart: {email_msg.is_multipart()}")
print(f"headers: {len(email_msg)}")
for key, value in email_msg.items():
print(f" {key}: {value}")
body_part = email_msg.get_body(preferencelist=("plain", "html"))
if body_part is not None:
print(f"body: {body_part.get_content()[:200]}")
CFB Container Round-Trip
Build and serialize Compound File Binary containers independently of the MSG layer. CFBDocument.from_file() loads an existing container into a mutable document model with CFBStorage and CFBStream nodes. CFBWriter.write_file() serializes the document back to disk deterministically.
from aspose.email_foss.cfb import CFBDocument, CFBReader, CFBWriter
reader = CFBReader.from_file("container.cfb")
document = CFBDocument.from_reader(reader)
reader.close()
output = CFBWriter.to_bytes(document)
print(f"Serialized {len(output)} bytes")
Error Handling
The library raises CFBError for malformed CFB content and MsgError for invalid MSG structure. MapiMessage also exposes a validation_issues property that returns a tuple of warning strings without raising an exception, letting you decide how strictly to handle non-conformant files.
from aspose.email_foss.cfb import CFBReader, CFBError
from aspose.email_foss.msg import MsgReader, MsgError
try:
reader = CFBReader.from_file("corrupted.cfb")
except CFBError as e:
print(f"CFB parse error: {e}")
try:
reader = MsgReader.from_file("malformed.msg")
except MsgError as e:
print(f"MSG parse error: {e}")
Quick Start
pip install aspose-email-foss>=26.3
Load an existing MSG, read its metadata, and list attachments:
from aspose.email_foss import msg
with msg.MapiMessage.from_file("inbox-message.msg") as message:
print(f"Subject: {message.subject}")
print(f"Body preview: {message.body[:200] if message.body else '(empty)'}")
for att in message.iter_attachments_info():
print(f"Attachment: {att.filename} ({att.mime_type}, {len(att.data)} bytes)")
issues = message.validation_issues
if issues:
print(f"Warnings: {issues}")
Supported Formats
| Format | Import | Export |
|---|---|---|
| MSG | Yes | Yes |
| CFB | Yes | Yes |
Open Source & Licensing
Aspose.Email FOSS for Python is released under the MIT License. You may use it in personal, internal, and commercial projects without restriction. The source code is available on GitHub.