@orkestrel/msg
v0.0.1
Published
A zero-dependency Outlook .msg (CFB/OLE2) and .eml (RFC 2822/MIME) email parser — extracts headers, bodies, recipients, and attachments into typed structures, with .msg round-trip rebuild. Part of the @orkestrel line.
Maintainers
Readme
@orkestrel/msg
A zero-dependency Outlook .msg (CFB/OLE2) and .eml (RFC 2822/MIME) email
parser — extracts headers, bodies, recipients, and attachments into typed
structures. Feed it raw file bytes plus an optional file name or MIME hint; the
format is detected automatically and the file is parsed into a structured
EmailChain — sender, recipients, subject, date, text/HTML bodies, and
decoded attachments. .msg files are read via a from-scratch CFB (Compound
File Binary / OLE2) parser that walks the directory tree and extracts MAPI
properties directly; .eml files are read via a from-scratch RFC 2822/MIME
parser that walks the header block and the (possibly nested) MIME part tree.
A lower-level MSGReader / MSGBurner pair is also exposed for readers that
need direct CFB access — MSGReader parses a .msg binary into its raw
directory/property structure, and MSGBurner reconstitutes that structure
back into a valid CFB byte stream (a round-trip "burn"), useful for rebuilding
or re-serializing a .msg file after editing its parsed fields. It never
throws on malformed input, only a typed MSGError returned inside a
Result. Part of the @orkestrel line.
Install
npm install @orkestrel/msgRequirements
- Node.js >= 24
- ESM + CJS (dual-format build)
- No runtime dependencies
Usage
import { createEmailParser, isSuccess } from '@orkestrel/msg'
const parser = createEmailParser()
const result = parser.parse({ bytes, name: 'message.msg' }) // bytes: Uint8Array
if (isSuccess(result)) {
const chain = result.value
console.log(chain.format) // 'msg' or 'eml'
const message = chain.messages[0]
console.log(message.from, message.to, message.subject)
console.log(message.text) // plain-text body (includes quoted reply chain)
console.log(message.html) // HTML body (includes quoted reply chain)
for (const attachment of message.attachments) {
console.log(attachment.name, attachment.mimeType, attachment.size)
}
} else {
console.error(result.error.code, result.error.message) // 'UNSUPPORTED' | 'MALFORMED' | ...
}parse is synchronous and returns a Result<EmailChain, MSGError> — never
throws. Format is inferred from the name / mime hints when supplied, or
detected from the byte content itself (CFB header for .msg, RFC 2822 header
block for .eml) when they are absent.
For direct access to the underlying .msg CFB structure — and to rebuild a
.msg binary after editing its parsed fields — use createMSGReader and
createMSGBurner:
import { createMSGReader, createMSGBurner } from '@orkestrel/msg'
const reader = createMSGReader(buffer) // ArrayBuffer or Uint8Array
const data = reader.parse() // raw directory/property structure
const rebuilt = reader.burn() // round-trip back into a CFB byte stream
const burner = createMSGBurner()
const binary = burner.burn(entries) // build a CFB byte stream from entry descriptorsGuide
For the full surface — the EmailParser, MSGReader, and MSGBurner
classes, their supporting types (EmailChain, EmailMessage,
EmailAttachment, MSGDirectoryEntry, and friends), and the CFB/MIME formats
they implement — see guides/src/msg.md.
Package
Published as a single typed entry point per the exports field in
package.json.
