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-29 09:56:53 UTC
README
Read and write Microsoft Outlook .msg files with a clean, fluent PHP API.
It gives you a clean API for subjects, bodies, recipients, attachments, embedded messages, and raw MAPI properties, while still leaving the low-level pieces available when you need them.
Installation
composer require cosmira/outlook-msg
Why You'll Like It
- Read Outlook
.msgfiles into a friendlyMessageobject - Work with recipients and attachments through fluent collections
- Access subject, sender, headers, plain text, HTML, and RTF through expressive methods
- Create new
.msgfiles with a clean builder API - Attach regular files, inline files, and embedded
.msgmessages - Preserve unmapped MAPI properties for round-trip scenarios
- Drop down to low-level compound file and RTF helpers when needed
Quick Start
Read a message
use Cosmira\OutlookMessage\Attachment; use Cosmira\OutlookMessage\Message; $message = Message::from(file_get_contents('example.msg')); echo $message->subject(); echo $message->senderName(); echo $message->preferredBody(); $message ->attachments() ->filter(static fn (Attachment $attachment): bool => $attachment->isInline()) ->each(static fn (Attachment $attachment): void => print $attachment->contentId());
Create a message
use Cosmira\OutlookMessage\Message; Message::make() ->from('Jane Doe', 'jane@example.com') ->to('Abigail', 'abigail@example.com') ->subject('Ship it') ->text('The plain text body') ->save('message.msg');
Reading Messages
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. If you prefer, the original public properties are still
available too.
Working With Recipients
use Cosmira\OutlookMessage\Recipient; $message ->to() ->each(function (Recipient $recipient) { printf("%s <%s>\n", $recipient->name() ?? '', $recipient->email() ?? ''); }); // Additional recipient groups: $message->cc() ->each(static fn (Recipient $recipient): void => print $recipient->email()); // Formatted header lines from the original message: echo $message->displayTo(); echo $message->displayCc(); echo $message->displayBcc();
Working With Attachments
use Cosmira\OutlookMessage\Attachment; $message ->attachments() ->each(static function (Attachment $attachment, int $index): void { $name = $attachment->fileName() ?? $attachment->displayName() ?? "attachment_{$index}"; file_put_contents(__DIR__."/out/{$name}", $attachment->content() ?? ''); });
Inline attachments
use Cosmira\OutlookMessage\Attachment; $message ->attachments() ->filter(fn (Attachment $attachment) => $attachment->isInline()) ->each(fn (Attachment $attachment) => print $attachment->contentId());
Embedded .msg attachments
use Cosmira\OutlookMessage\Attachment; $message ->attachments() ->filter(fn (Attachment $attachment) => $attachment->embedded() !== null) ->each(fn (Attachment $attachment) => print $attachment->embedded()?->subject());
Bodies: HTML, Plain Text, and RTF
If you just want 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);
Creating Messages
The smoothest writing experience is the fluent builder API:
use DateTimeImmutable; use DateTimeZone; use Cosmira\OutlookMessage\Message; $draft = Message::make() ->from('Jane Doe', 'jane@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');
You can still use MessageBuilder::make() and MessageWriter::make() directly if you prefer the lower-level writer
entry points.
Named Payload Constructors
If you want more control, you can build 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 methods. Everything else can still be preserved and inspected through 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 analyse --no-progress