Skip to content

feat(email): add Outlook .msg support and optional attachment listing#3873

Open
DanielNg0729 wants to merge 1 commit into
docling-project:mainfrom
DanielNg0729:feat/email-msg-support
Open

feat(email): add Outlook .msg support and optional attachment listing#3873
DanielNg0729 wants to merge 1 commit into
docling-project:mainfrom
DanielNg0729:feat/email-msg-support

Conversation

@DanielNg0729

@DanielNg0729 DanielNg0729 commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Hi maintainers, this PR is to follow up with #3716.
Issue resolved by this Pull Request:
Resolves #3712

With Docling's README and docs/usage/supported_formats.md already advertise email parsing for both .eml and .msg, but only .eml (via mail-parser) was actually implemented. This PR adds native Outlook .msg parsing and an opt-in
listing of attachment names for both formats, using the MIT-licensed
Aspose.Email FOSS library suggested in the discussion.

Library choice

Reading .msg (OLE2/Compound File Binary + MAPI) uses
aspose-email-foss:

  • MIT licensed
  • Pure Python, zero runtime dependencies, Python ≥ 3.10
  • No Microsoft Office / COM / Win32 requirement

It is added only to the existing format-email extra, so default/slim installs are unaffected.

How it works

The .msg path is a thin bridge rather than a second renderer: a .msg is detected by its OLE2/CFB magic bytes, loaded via Aspose, and projected onto standard RFC 822 bytes (MapiMessage.to_email_bytes()). Those bytes flow through the same mail-parser code path already used for .eml, so subject/from/to/date, plain-text and HTML bodies, and attachments are handled identically for both formats.

Both the mail-parser and aspose-email-foss imports are guarded (same pattern as #3613), so import docling still works without the extra; using a .msg without the dependency raises an actionable format-email install hint.

Optional attachment listing

New EmailBackendOptions(list_attachments=False) (opt-in). When enabled, an "Attachments" section listing each attachment's filename and content type is appended. Attachment payload bytes are never embedded, only names/types and consistent with existing .eml behavior.

from docling.datamodel.base_models import InputFormat
from docling.datamodel.backend_options import EmailBackendOptions
from docling.document_converter import DocumentConverter, EmailFormatOption

converter = DocumentConverter(
    format_options={
        InputFormat.EMAIL: EmailFormatOption(
            backend_options=EmailBackendOptions(list_attachments=True)
        )
    }
)

# Works for both .msg and .eml
doc = converter.convert("message.msg").document
print(doc.export_to_markdown())

Note

DocumentOrigin.mimetype only accepts registered MIME types (no application/vnd.ms-outlook), so the origin stays message/rfc822 for both inputs; the .msg distinction is kept via the filename fallback and the backend.is_msg flag.

Testing

New .msg tests (path, stream, converter, attachment listing) plus a regression row asserting graceful degradation when aspose-email-foss is absent, 32 tests pass across test_backend_email.py and test_backend_optional_dependencies.py. ruff, ty, and tach are clean and uv.lock is regenerated.

Checklist:

  • Documentation has been updated, if necessary.
  • Examples have been added, if necessary.
  • Tests have been added, if necessary.

Signed-off-by: Daniel Nguyen <danielnguyenh07@gmail.com>
@github-actions

Copy link
Copy Markdown
Contributor

DCO Check Passed

Thanks @DanielNg0729, all your commits are properly signed off. 🎉

@mergify

mergify Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Merge Protections

🔴 1 of 2 protections blocking · waiting on 👀 reviews

Protection Waiting on
🔴 Require two reviewer for test updates 👀 reviews
🟢 Enforce conventional commit

🔴 Require two reviewer for test updates

Waiting for

  • #approved-reviews-by >= 2
This rule is failing.

When test data is updated, we require two reviewers

  • #approved-reviews-by >= 2

Show 1 satisfied protection

🟢 Enforce conventional commit

Make sure that we follow https://www.conventionalcommits.org/en/v1.0.0/

  • title ~= ^(fix|feat|docs|style|refactor|perf|test|build|ci|chore|revert)(?:\(.+\))?(!)?:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

E-Mail Parsing

1 participant