npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

xiaodao-email-parser

v1.0.5

Published

Node.js and TypeScript email parser with auto-detection for Outlook MSG and RFC 5322/MIME EML files

Downloads

166

Readme

xiaodao-email-parser

English | 简体中文

A Node.js and TypeScript email file parser that automatically detects and parses:

  • Outlook .msg files (Compound File Binary / OLE2 + MAPI)
  • RFC 5322 / MIME .eml files

The default EmailParser export detects the format from the file content and returns a consistent ParsedEmail object. Dedicated MsgParser and EmlParser exports are also available for format-specific use cases and for migrating existing synchronous MSG integrations.

Features

  • Detect MSG and EML from their content instead of relying on file extensions
  • Parse senders, reply-to addresses, recipients, subjects, dates, importance, and Message-ID values
  • Extract plain text, HTML, and MSG compressed RTF bodies
  • Handle multipart messages, base64, quoted-printable, RFC 2047 encoded words, and RFC 2231 filenames
  • Extract regular and inline attachments with MIME type and Content-ID metadata
  • Preserve raw headers, parsed headers, and format-specific low-level properties
  • Enforce MIME nesting, header-size, and input-size limits
  • Ship complete TypeScript declarations

Installation

npm install xiaodao-email-parser

Node.js 18 or later is required.

Quick start: auto-detect MSG or EML

import EmailParser from 'xiaodao-email-parser';

const parser = new EmailParser();
const email = await parser.parseFile('message.eml'); // message.msg also works

console.log(email.format); // 'eml' or 'msg'
console.log(email.subject);
console.log(email.from);
console.log(email.to);
console.log(email.attachments);

You can also parse a Buffer:

import fs from 'node:fs/promises';
import EmailParser from 'xiaodao-email-parser';

const source = await fs.readFile('message.msg');
const email = await new EmailParser().parse(source);

The unified parser always uses an asynchronous API, including when the detected input is MSG.

Dedicated parsers

Parse MSG synchronously

import { MsgParser } from 'xiaodao-email-parser';

const email = new MsgParser().parseFile('message.msg');
console.log(email.body, email.bodyHtml, email.bodyRtf);

MsgParser.parse() and MsgParser.parseFile() remain synchronous for existing MSG integrations.

Parse EML

import { EmlParser } from 'xiaodao-email-parser';

const parser = new EmlParser({
  maxInputSize: 50 * 1024 * 1024,
  maxNestingDepth: 50,
  maxHeadersSize: 2 * 1024 * 1024,
  maxRfc822NestingDepth: 5,
});

const email = await parser.parseFile('message.eml');

EmlParser accepts inputs up to 100 MiB by default. MIME parsing also includes aggregate header-size and nesting-depth protection.

API

Package exports:

import EmailParser, {
  EmailParser as NamedEmailParser,
  MsgParser,
  EmlParser,
  detectEmailFormat,
} from 'xiaodao-email-parser';

EmailParser

new EmailParser(options?: EmailParserOptions)
parser.parse(buffer: Buffer, options?: ParseOptions): Promise<ParsedEmail>
parser.parseFile(filePath: string, options?: ParseOptions): Promise<ParsedEmail>

Content-based auto-detection is used by default. You can also force a format:

await parser.parse(buffer, { format: 'eml' });
await parser.parseFile(filePath, { format: 'msg' });

MsgParser

new MsgParser()
parser.parse(buffer: Buffer): ParsedEmail
parser.parseFile(filePath: string): ParsedEmail

Parses Outlook MSG only. Both methods are synchronous and throw a descriptive error when the input is not a valid CFB/MAPI message.

EmlParser

new EmlParser(options?: EmlParserOptions)
parser.parse(buffer: Buffer): Promise<ParsedEmail>
parser.parseFile(filePath: string): Promise<ParsedEmail>

Parses RFC 5322/MIME EML only. The following limits can be configured:

interface EmlParserOptions {
  maxInputSize?: number;
  rfc822Attachments?: boolean;
  forceRfc822Attachments?: boolean;
  maxNestingDepth?: number;
  maxHeadersSize?: number;
  maxRfc822NestingDepth?: number;
}

detectEmailFormat

import { detectEmailFormat } from 'xiaodao-email-parser';

const format = detectEmailFormat(buffer); // 'msg' | 'eml' | null

MSG detection uses the CFB signature. EML detection checks the header structure and known email headers. The function returns null when it cannot determine the format reliably; the unified parser throws a descriptive error in that case.

ParsedEmail

interface ParsedEmail {
  format: 'msg' | 'eml';
  subject: string | null;
  from: EmailRecipient | null;
  replyTo: EmailRecipient[];
  to: EmailRecipient[];
  cc: EmailRecipient[];
  bcc: EmailRecipient[];
  body: string | null;
  bodyHtml: string | null;
  bodyRtf: string | null;
  attachments: EmailAttachment[];
  sentDate: Date | null;
  receivedDate: Date | null;
  createdDate: Date | null;
  modifiedDate: Date | null;
  messageClass: string | null;
  importance: 'low' | 'normal' | 'high' | null;
  messageSize: number | null;
  conversationTopic: string | null;
  normalizedSubject: string | null;
  messageId: string | null;
  headers: string | null;
  parsedHeaders: Record<string, string> | null;
  preview: string | null;
  _rawProperties: Record<string, unknown>;
}

For EML, _rawProperties contains sender, return-path, references, and the unfolded header array. For MSG, it contains the resolved low-level MAPI properties.

Attachments

interface EmailAttachment {
  filename: string | null;
  content: Buffer | null;
  contentType: string;
  contentId: string | null;
  contentLocation: string | null;
  size: number;
}

Example: save all named attachments.

import fs from 'node:fs/promises';

for (const attachment of email.attachments) {
  if (attachment.filename && attachment.content) {
    await fs.writeFile(attachment.filename, attachment.content);
  }
}

Architecture

EmailParser (asynchronous, auto-detecting)
├── MsgParser (synchronous, CFB/MAPI)
└── EmlParser (asynchronous, RFC 5322/MIME)

Each dedicated parser owns its format-specific decoding. Shared utilities normalize addresses, headers, subjects, previews, dates, and Content-ID values before both implementations map their output to the same result type.

Development

npm run build
npm test
node --import tsx examples/parse.ts path/to/message.msg
node --import tsx examples/parse.ts path/to/message.eml

Limitations

  • Encrypted and password-protected messages are not decrypted.
  • MSG custom named properties and embedded MSG attachments are not fully expanded yet.
  • For backward compatibility, parsedHeaders is a key-value object and repeated headers are merged. The original EML header array is available at _rawProperties.headers.
  • The parser only extracts content; it never executes HTML, scripts, or attachments.

License

MIT