cosmira / outlook-msg
Read and write Microsoft Outlook MSG files in modern PHP
Requires
- php: ^8.2
- brick/math: ^0.12|^0.13|^0.14|^0.15|^0.16|^0.17
- illuminate/support: ^11.0|^12.0|^13.0
Requires (Dev)
- driftingly/rector-laravel: ^2.1
- infection/infection: ^0.32.6
- laravel/pint: ^1.2
- phpstan/phpstan: ^2.1
- phpstan/phpstan-phpunit: ^2.0
- phpstan/phpstan-strict-rules: ^2.0
- phpunit/phpunit: ^11.5|^12.0
- rector/rector: ^2.3
- symfony/var-dumper: ^7.0
This package is not auto-updated.
Last update: 2026-04-15 09:46:48 UTC
README
Modern PHP library for reading and writing Microsoft Outlook .msg files.
It gives you a clean high-level API for message content, recipients, attachments, embedded messages, and raw MAPI properties, while still exposing the low-level building blocks when you need them.
Installation
composer require cosmira/outlook-msg
What You Get
- Read Outlook
.msgfiles into a friendlyMessageobject - Access subject, sender, recipients, headers, plain text, HTML, and RTF
- Extract regular attachments and embedded
.msgattachments - Create new
.msgfiles with a fluent builder API - Preserve unmapped MAPI properties for round-trip scenarios
- Work with low-level compound file and RTF helpers when needed
Read a Message
use Cosmira\OutlookMessage\Message; $message = Message::from( file_get_contents('example.msg') ); echo $message->subject(); echo $message->senderName(); echo $message->senderEmail(); echo $message->preferredBody();
Message::from() and Message::parse() are equivalent.
Work With Recipients
foreach ($message->recipients as $recipient) { printf( "[%d] %s <%s>\n", $recipient->type, $recipient->name ?? '', $recipient->email ?? '' ); } echo $message->to(); echo $message->cc(); echo $message->bcc();
Work With Attachments
foreach ($message->attachments as $index => $attachment) { $name = $attachment->fileName ?? $attachment->displayName ?? "attachment_{$index}"; file_put_contents(__DIR__."/out/{$name}", $attachment->content); }
Inline attachments
foreach ($message->attachments as $attachment) { if ($attachment->isInline) { echo $attachment->contentId; } }
Embedded .msg attachments
foreach ($message->attachments as $attachment) { if ($attachment->embedded !== null) { echo $attachment->embedded->subject(); } }
HTML, Plain Text, and RTF
For the best available body, use:
$body = $message->preferredBody();
If you want explicit access:
$message->body()for plain text$message->bodyHtml()for HTML$message->bodyRtf()for decompressed RTF text
To work with raw compressed RTF payloads directly:
use Cosmira\OutlookMessage\Rtf\RtfDecompressor; $rtf = RtfDecompressor::decompress($rawRtfBinary);
Create a Message
The best writing experience is the fluent builder API:
use DateTimeImmutable; use DateTimeZone; use Cosmira\OutlookMessage\Message; $draft = Message::make() ->from('Taylor Otwell', 'taylor@example.com') ->subject('Ship it') ->text('The plain text body') ->html('<p>The <strong>HTML</strong> body</p>') ->withHeaders("X-App: outlook-msg\r\n") ->sentAt(new DateTimeImmutable('2024-01-01 10:00:00', new DateTimeZone('UTC'))) ->to('Abigail', 'abigail@example.com') ->cc('Jess', 'jess@example.com') ->bcc('Ops', 'ops@example.com') ->attach('notes.txt', 'Remember the meeting at 11:40') ->attachInline('logo.png', $logoBinary, 'cid:logo'); $draft->save('message.msg');
Named Payload Constructors
If you want more control, you can create payload objects directly:
use Cosmira\OutlookMessage\Writer\AttachmentPayload; use Cosmira\OutlookMessage\Writer\RecipientPayload; $to = RecipientPayload::to('Abigail', 'abigail@example.com'); $cc = RecipientPayload::cc('Jess', 'jess@example.com'); $bcc = RecipientPayload::bcc('Ops', 'ops@example.com'); $file = AttachmentPayload::file('report.pdf', $pdfBinary); $inline = AttachmentPayload::inline('logo.png', $logoBinary, 'cid:logo');
Embedded Message Attachments
You can attach one .msg inside another:
use Cosmira\OutlookMessage\Writer\MessageBuilder; $nested = MessageBuilder::make() ->from('Nested Sender', 'nested@example.com') ->subject('Nested message') ->text('Hello from inside'); $draft = MessageBuilder::make() ->from('Parent Sender', 'parent@example.com') ->subject('Parent message') ->attachEmbedded($nested, 'forwarded.msg');
Raw MAPI Properties
Known message fields are mapped onto friendly objects. Everything else can still be preserved and inspected via raw properties:
$raw = $message->rawProperties();
This is useful when:
- you need round-trip fidelity
- you care about Outlook-specific metadata not mapped by the library
- you want to inspect or write custom MAPI values
Low-Level APIs
The package also includes lower-level APIs for advanced scenarios:
Cosmira\OutlookMessage\CompoundFile\CompoundFilefor CFBF/OLE storage accessCosmira\OutlookMessage\Support\BinaryBufferfor binary readsCosmira\OutlookMessage\Rtf\RtfDecompressorfor compressed RTF payloads
Testing
php vendor/bin/phpunit php vendor/bin/rector process php vendor/bin/phpstan a src --level=max