Skip to main content

Basic Parsing

Examples of common email parsing scenarios.

Simple Text Email

import PostalMime from 'postal-mime';

const rawEmail = `From: alice@example.com
To: bob@example.com
Subject: Hello Bob
Date: Mon, 15 Jan 2024 10:30:00 +0000
Content-Type: text/plain; charset=utf-8

Hi Bob,

Just wanted to say hello!

Best,
Alice`;

const email = await PostalMime.parse(rawEmail);

console.log('From:', email.from);
// { name: '', address: 'alice@example.com' }

console.log('To:', email.to);
// [{ name: '', address: 'bob@example.com' }]

console.log('Subject:', email.subject);
// "Hello Bob"

console.log('Date:', email.date);
// "2024-01-15T10:30:00.000Z"

console.log('Text:', email.text);
// "Hi Bob,\n\nJust wanted to say hello!\n\nBest,\nAlice"

HTML Email

const htmlEmail = `From: newsletter@example.com
To: subscriber@example.com
Subject: Weekly Update
Content-Type: text/html; charset=utf-8
MIME-Version: 1.0

<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: Arial, sans-serif; }
.header { background: #007bff; color: white; padding: 20px; }
</style>
</head>
<body>
<div class="header">
<h1>Weekly Newsletter</h1>
</div>
<p>Here's what happened this week...</p>
</body>
</html>`;

const email = await PostalMime.parse(htmlEmail);

console.log('HTML available:', !!email.html);
// true

console.log('Text available:', !!email.text);
// true (automatically converted from HTML)

// Render the HTML safely (always sanitize first!)
document.getElementById('email-content').innerHTML = email.html;

Multipart Email (Text + HTML)

const multipartEmail = `From: sender@example.com
To: recipient@example.com
Subject: Important Update
MIME-Version: 1.0
Content-Type: multipart/alternative; boundary="boundary123"

--boundary123
Content-Type: text/plain; charset=utf-8

This is the plain text version.

--boundary123
Content-Type: text/html; charset=utf-8

<html>
<body>
<p>This is the <strong>HTML</strong> version.</p>
</body>
</html>

--boundary123--`;

const email = await PostalMime.parse(multipartEmail);

console.log('Text:', email.text);
// "This is the plain text version."

console.log('HTML:', email.html);
// "<html>\n<body>\n<p>This is the <strong>HTML</strong> version.</p>\n</body>\n</html>"

Email with Attachments

const emailWithAttachment = `From: sender@example.com
To: recipient@example.com
Subject: Document Attached
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="boundary456"

--boundary456
Content-Type: text/plain; charset=utf-8

Please find the document attached.

--boundary456
Content-Type: application/pdf; name="document.pdf"
Content-Disposition: attachment; filename="document.pdf"
Content-Transfer-Encoding: base64

JVBERi0xLjQKJeLjz9MKCjEgMCBvYmoKPDwvVHlwZS9DYXRhbG9n
Pj4KZW5kb2JqCgp0cmFpbGVyCjw8L1Jvb3QgMSAwIFI+Pgolh

--boundary456--`;

const email = await PostalMime.parse(emailWithAttachment);

console.log('Text:', email.text);
// "Please find the document attached."

console.log('Attachments:', email.attachments.length);
// 1

const attachment = email.attachments[0];
console.log('Filename:', attachment.filename);
// "document.pdf"
console.log('MIME Type:', attachment.mimeType);
// "application/pdf"
console.log('Size:', attachment.content.byteLength, 'bytes');

Multiple Recipients

const multiRecipientEmail = `From: sender@example.com
To: alice@example.com, bob@example.com
Cc: charlie@example.com
Bcc: admin@example.com
Subject: Team Update

Hello team!`;

const email = await PostalMime.parse(multiRecipientEmail);

console.log('To recipients:');
email.to?.forEach(addr => {
console.log(` - ${addr.address}`);
});
// alice@example.com
// bob@example.com

console.log('CC recipients:');
email.cc?.forEach(addr => {
console.log(` - ${addr.address}`);
});
// charlie@example.com

Encoded Headers

const encodedEmail = `From: =?UTF-8?B?5bGx55Sw5aSq6YOO?= <yamada@example.jp>
To: user@example.com
Subject: =?UTF-8?Q?Caf=C3=A9_Menu?=
Content-Type: text/plain; charset=utf-8

Content here`;

const email = await PostalMime.parse(encodedEmail);

console.log('From name:', email.from?.name);
// "山田太郎" (decoded from Base64)

console.log('Subject:', email.subject);
// "Cafe Menu" (decoded from Quoted-Printable)

Reading from File (Node.js)

import PostalMime from 'postal-mime';
import { readFile } from 'fs/promises';

async function parseEmailFile(filepath) {
const buffer = await readFile(filepath);
const email = await PostalMime.parse(buffer);

console.log('Subject:', email.subject);
console.log('From:', email.from?.address);
console.log('Attachments:', email.attachments.length);

return email;
}

const email = await parseEmailFile('./message.eml');

Reading from Fetch Response

async function parseRemoteEmail(url) {
const response = await fetch(url);
const buffer = await response.arrayBuffer();
const email = await PostalMime.parse(buffer);

return email;
}

const email = await parseRemoteEmail('https://example.com/email.eml');

Reading from File Input (Browser)

const fileInput = document.querySelector('#email-file');

fileInput.addEventListener('change', async (event) => {
const file = event.target.files[0];
if (!file) return;

const email = await PostalMime.parse(file);

console.log('Parsed email:', email.subject);

// Display results
document.getElementById('subject').textContent = email.subject;
document.getElementById('from').textContent = email.from?.address;
document.getElementById('body').innerHTML = email.html || email.text;
});

Error Handling

async function safeParse(rawEmail) {
try {
const email = await PostalMime.parse(rawEmail, {
maxNestingDepth: 50,
maxHeadersSize: 524288 // 512KB
});

return {
success: true,
email
};
} catch (error) {
console.error('Parsing failed:', error.message);

return {
success: false,
error: error.message
};
}
}

const result = await safeParse(rawEmail);

if (result.success) {
console.log('Subject:', result.email.subject);
} else {
console.log('Error:', result.error);
}

Complete Email Parser Function

import PostalMime from 'postal-mime';

async function parseEmail(input, options = {}) {
const defaultOptions = {
attachmentEncoding: 'base64',
maxNestingDepth: 100,
maxHeadersSize: 1048576 // 1MB
};

const email = await PostalMime.parse(input, {
...defaultOptions,
...options
});

return {
// Sender info
from: email.from?.address || null,
fromName: email.from?.name || null,
sender: email.sender?.address || null,

// Recipients
to: email.to?.map(a => a.address) || [],
cc: email.cc?.map(a => a.address) || [],
bcc: email.bcc?.map(a => a.address) || [],
replyTo: email.replyTo?.map(a => a.address) || [],

// Message details
subject: email.subject || '(no subject)',
date: email.date ? new Date(email.date) : null,
messageId: email.messageId || null,

// Content
text: email.text || null,
html: email.html || null,
hasHtml: !!email.html,

// Attachments
attachments: email.attachments.map(att => ({
filename: att.filename,
mimeType: att.mimeType,
size: typeof att.content === 'string'
? Math.floor(att.content.length * 0.75)
: att.content.byteLength,
isInline: att.disposition === 'inline',
contentId: att.contentId || null
})),
attachmentCount: email.attachments.length,

// Raw headers for advanced use
headers: email.headers
};
}

// Usage
const parsed = await parseEmail(rawEmail);
console.log(JSON.stringify(parsed, null, 2));