What is a .msg file?

How Outlook's .msg format works: the OLE2 container, MAPI property streams, where the body is stored, and why other applications cannot read it.

A .msg file is Microsoft Outlook's format for storing a single Outlook item as a standalone file. Despite the name, it holds more than email: an appointment, contact, task, note or meeting request saved from Outlook all produce a .msg file.

The container: Compound File Binary Format

Internally, a .msg file is an OLE2 Compound File — effectively a small filesystem inside a single file, with directories ("storages") and files ("streams"). Every such file begins with the same eight signature bytes, D0 CF 11 E0 A1 B1 1A E1, which is how a reader can identify one regardless of its extension.

The same container format underlies legacy .doc, .xls and .ppt files. What differs is the naming and meaning of the streams inside, which for .msg is specified by [MS-OXMSG].

What is stored inside

Each message property lives in its own stream named after a MAPI property tag — a 16-bit property id plus a 16-bit type. For example:

PropertyTagHolds
PidTagSubject0037001FThe subject line
PidTagBody1000001FPlain-text body
PidTagHtml10130102HTML body, as raw bytes
PidTagRtfCompressed10090102Compressed RTF body
PidTagSenderEmailAddress0C1F001FSender address

Recipients and attachments are not properties but sub-storages — __recip_version1.0_#00000000, __attach_version1.0_#00000000 and so on — each with its own property streams inside.

The three ways a body can be stored

This is where most simple viewers fail, and why the same file can look perfect in one tool and blank in another. Outlook may store the body as:

  • Plain text in PidTagBody.
  • HTML in PidTagHtml, as raw bytes that must be decoded using the code page named in PidTagInternetCodepage. Decoding these as UTF-8 by default is what produces mojibake in Chinese, Japanese, Korean, Cyrillic and Greek messages.
  • Compressed RTF in PidTagRtfCompressed. When the message was originally HTML, Outlook wraps that HTML inside the RTF using the [MS-OXRTFEX] encapsulation scheme. Recovering it requires decompressing the stream and then de-encapsulating \htmltag and \htmlrtf control words. Viewers that skip this step show an empty body for a large share of real-world Outlook mail.

Inline images and cid: references

Images that appear inside the message body are stored as ordinary attachments carrying a PidTagAttachContentId. The HTML body then references them as <img src="cid:image001.png@01D9…">. A viewer has to match each cid: reference to its attachment and substitute a usable URL; otherwise the message renders with broken image placeholders where the signature and logos should be.

Reading the streams by hand

Every property lives in a stream whose name encodes what it is: __substg1.0_XXXXYYYY, where XXXX is the property tag in hex and YYYY is its type. So the subject, tag 0x0037, stored as Unicode (0x001F), appears as __substg1.0_0037001F. The same tag ending 001E would be the eight-bit version of the same field.

That naming is the whole reason a .msg can be read at all without Outlook. Given an OLE2 library, you can enumerate the streams and look up the tags, and the file gives up its structure without any Microsoft code being involved.

Two more conventions matter. Recipients are not a list inside one stream; each one is a sub-storage named __recip_version1.0_#00000000, #00000001 and so on, each containing its own set of property streams. Attachments follow the same pattern under __attach_version1.0_#.... A fixed-size property — a boolean, an integer, a timestamp — is not a stream at all; it is packed into the __properties_version1.0 table alongside the others.

Character encoding, and how it goes wrong

A property stored as 001F is UTF-16LE and unambiguous. One stored as 001E is bytes in some code page, and the file has to tell you which: PidTagInternetCodepage (0x3FDE) or, failing that, PidTagMessageCodepage.

A reader that ignores those and assumes UTF-8 will mangle every message written in Traditional Chinese, Japanese, Korean, Cyrillic or Greek — which is the usual explanation when a message opens but the text is replacement characters. The message is not corrupt; it was decoded with the wrong table.

What it means that this is an OLE2 file

The container being a Compound File has one consequence worth knowing: it is a little filesystem, with a sector allocation table, a directory tree and free space. Editing a .msg in a text editor does not merely garble some text — it breaks the sector chain, and the file becomes unopenable in a way no tool can recover. If you need to inspect one, work on a copy.

It also means a .msg is usually larger than the same message as .eml, sometimes substantially. It stores the body more than once — HTML and RTF and plain text — plus MAPI bookkeeping that the wire format has no place for.

Why other applications will not open it

Microsoft documented the format but never proposed it as an interchange standard, and it encodes Exchange-specific concepts — legacy distinguished names, voting buttons, delegate information, message classes — that have no equivalent in standard internet mail. Supporting it means implementing a Microsoft specification with no benefit to a competitor's own format, so almost nobody does.

The standard alternative is .eml, which is plain RFC 822 text. Compare the two formats to see what you gain and lose by converting.

Open a .msg file right now

No sign-up, no upload, no software to install.

Open the viewer