{"id":15701570,"url":"https://github.com/postalsys/postal-mime","last_synced_at":"2026-03-09T16:56:16.266Z","repository":{"id":39978834,"uuid":"329845570","full_name":"postalsys/postal-mime","owner":"postalsys","description":"Email parser for browser and serverless environments","archived":false,"fork":false,"pushed_at":"2025-10-07T09:04:29.000Z","size":514,"stargazers_count":461,"open_issues_count":0,"forks_count":43,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-10-07T09:15:29.302Z","etag":null,"topics":["attachments","email","mime","parser","serverless"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/postalsys.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2021-01-15T07:56:37.000Z","updated_at":"2025-10-07T09:04:22.000Z","dependencies_parsed_at":"2022-08-09T15:54:48.995Z","dependency_job_id":"73993da5-bf4c-443e-9e68-6a229f730afc","html_url":"https://github.com/postalsys/postal-mime","commit_stats":null,"previous_names":["postalsys/mime"],"tags_count":45,"template":false,"template_full_name":null,"purl":"pkg:github/postalsys/postal-mime","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/postalsys%2Fpostal-mime","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/postalsys%2Fpostal-mime/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/postalsys%2Fpostal-mime/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/postalsys%2Fpostal-mime/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/postalsys","download_url":"https://codeload.github.com/postalsys/postal-mime/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/postalsys%2Fpostal-mime/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279019322,"owners_count":26086711,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-14T02:00:06.444Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["attachments","email","mime","parser","serverless"],"created_at":"2024-10-03T20:00:47.501Z","updated_at":"2026-03-09T16:56:16.252Z","avatar_url":"https://github.com/postalsys.png","language":"JavaScript","funding_links":[],"categories":["JavaScript","Email"],"sub_categories":["Parsers and Tools"],"readme":"# postal-mime\n\n**postal-mime** is an email parsing library for Node.js, browsers (including Web Workers), and serverless environments (like Cloudflare Email Workers). It takes in a raw email message (RFC822 format) and outputs a structured object containing headers, recipients, attachments, and more.\n\n\u003e [!TIP]\n\u003e PostalMime is developed by the makers of [EmailEngine](https://emailengine.app/?utm_source=github\u0026utm_campaign=imapflow\u0026utm_medium=readme-link)—a self-hosted email gateway that provides a REST API for IMAP and SMTP servers and sends webhooks whenever something changes in registered accounts.\n\n## Features\n\n-   **Browser \u0026 Node.js compatible** - Works in browsers, Web Workers, Node.js, and serverless environments\n-   **TypeScript support** - Fully typed with comprehensive type definitions\n-   **Zero dependencies** - No external dependencies\n-   **RFC compliant** - Follows RFC 2822/5322 email standards\n-   **Handles complex MIME structures** - Multipart messages, nested parts, attachments\n-   **Security limits** - Built-in protection against deeply nested messages and oversized headers\n\n\u003e [!NOTE]\n\u003e Full documentation is available at [postal-mime.postalsys.com](https://postal-mime.postalsys.com/).\n\n## Table of Contents\n\n-   [Source](#source)\n-   [Demo](#demo)\n-   [Installation](#installation)\n-   [Usage](#usage)\n    -   [Browser](#browser)\n    -   [Node.js](#nodejs)\n    -   [Cloudflare Email Workers](#cloudflare-email-workers)\n-   [TypeScript Support](#typescript-support)\n-   [API](#api)\n    -   [PostalMime.parse()](#postalmimeparse)\n    -   [Utility Functions](#utility-functions)\n        -   [addressParser()](#addressparser)\n        -   [decodeWords()](#decodewords)\n-   [License](#license)\n\n---\n\n## Source\n\nThe source code is available on [GitHub](https://github.com/postalsys/postal-mime).\n\n## Demo\n\nTry out a live demo using the [example page](https://postal-mime.postalsys.com/demo).\n\n## Installation\n\nInstall the module from npm:\n\n```bash\nnpm install postal-mime\n```\n\n## Usage\n\nYou can import the `PostalMime` class differently depending on your environment:\n\n### Browser\n\nTo use PostalMime in the browser (including Web Workers), import it from the `src` folder:\n\n```js\nimport PostalMime from './node_modules/postal-mime/src/postal-mime.js';\n\nconst email = await PostalMime.parse(`Subject: My awesome email 🤓\nContent-Type: text/html; charset=utf-8\n\n\u003cp\u003eHello world 😵‍💫\u003c/p\u003e`);\n\nconsole.log(email.subject); // \"My awesome email 🤓\"\n```\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eTypeScript\u003c/strong\u003e\u003c/summary\u003e\n\n```typescript\nimport PostalMime from './node_modules/postal-mime/src/postal-mime.js';\nimport type { Email } from 'postal-mime';\n\nconst email: Email = await PostalMime.parse(`Subject: My awesome email 🤓\nContent-Type: text/html; charset=utf-8\n\n\u003cp\u003eHello world 😵‍💫\u003c/p\u003e`);\n\nconsole.log(email.subject); // \"My awesome email 🤓\"\n```\n\n\u003c/details\u003e\n\n### Node.js\n\nIn Node.js (including serverless functions), import it directly from `postal-mime`:\n\n```js\nimport PostalMime from 'postal-mime';\nimport util from 'node:util';\n\nconst email = await PostalMime.parse(`Subject: My awesome email 🤓\nContent-Type: text/html; charset=utf-8\n\n\u003cp\u003eHello world 😵‍💫\u003c/p\u003e`);\n\n// Use 'util.inspect' for pretty-printing\nconsole.log(util.inspect(email, false, 22, true));\n```\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eTypeScript\u003c/strong\u003e\u003c/summary\u003e\n\n```typescript\nimport PostalMime from 'postal-mime';\nimport type { Email, PostalMimeOptions } from 'postal-mime';\nimport util from 'node:util';\n\nconst options: PostalMimeOptions = {\n    attachmentEncoding: 'base64'\n};\n\nconst email: Email = await PostalMime.parse(`Subject: My awesome email 🤓\nContent-Type: text/html; charset=utf-8\n\n\u003cp\u003eHello world 😵‍💫\u003c/p\u003e`, options);\n\n// Use 'util.inspect' for pretty-printing\nconsole.log(util.inspect(email, false, 22, true));\n```\n\n\u003c/details\u003e\n\n### CommonJS\n\nFor projects using CommonJS (with `require()`), postal-mime automatically provides the CommonJS build:\n\n```js\nconst PostalMime = require('postal-mime');\nconst { addressParser, decodeWords } = require('postal-mime');\n\nconst email = await PostalMime.parse(`Subject: My awesome email 🤓\nContent-Type: text/html; charset=utf-8\n\n\u003cp\u003eHello world 😵‍💫\u003c/p\u003e`);\n\nconsole.log(email.subject); // \"My awesome email 🤓\"\n```\n\n\u003e [!NOTE]\n\u003e The CommonJS build is automatically generated from the ESM source code during the build process. The package supports dual module format, so both `import` and `require()` work seamlessly.\n\n### Cloudflare Email Workers\n\nUse the `message.raw` as the raw email data for parsing:\n\n```js\nimport PostalMime from 'postal-mime';\n\nexport default {\n    async email(message, env, ctx) {\n        const email = await PostalMime.parse(message.raw);\n\n        console.log('Subject:', email.subject);\n        console.log('HTML:', email.html);\n        console.log('Text:', email.text);\n    }\n};\n```\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eTypeScript\u003c/strong\u003e\u003c/summary\u003e\n\n```typescript\nimport PostalMime from 'postal-mime';\nimport type { Email } from 'postal-mime';\n\nexport default {\n    async email(message: ForwardableEmailMessage, env: Env, ctx: ExecutionContext): Promise\u003cvoid\u003e {\n        const email: Email = await PostalMime.parse(message.raw);\n\n        console.log('Subject:', email.subject);\n        console.log('HTML:', email.html);\n        console.log('Text:', email.text);\n    }\n};\n```\n\n\u003c/details\u003e\n\n---\n\n## TypeScript Support\n\nPostalMime includes comprehensive TypeScript type definitions. All types are exported and can be imported from the main package:\n\n```typescript\nimport PostalMime, { addressParser, decodeWords } from 'postal-mime';\nimport type {\n    Email,\n    Address,\n    Mailbox,\n    Header,\n    Attachment,\n    PostalMimeOptions,\n    AddressParserOptions,\n    RawEmail\n} from 'postal-mime';\n```\n\n\u003e [!NOTE]\n\u003e PostalMime is written in JavaScript but provides comprehensive TypeScript type definitions. All types are validated through both compile-time type checking and runtime type validation tests to ensure accuracy.\n\n### Available Types\n\n-   **`Email`** - The main parsed email object returned by `PostalMime.parse()`\n-   **`Address`** - Union type representing either a `Mailbox` or an address group\n-   **`Mailbox`** - Individual email address with name and address fields\n-   **`Header`** - Email header with key and value\n-   **`Attachment`** - Email attachment with metadata and content\n-   **`PostalMimeOptions`** - Configuration options for parsing\n-   **`AddressParserOptions`** - Configuration options for address parsing\n-   **`RawEmail`** - Union type for all accepted email input formats\n\n### Type Narrowing\n\nTypeScript users can use type guards to narrow address types:\n\n```typescript\nimport type { Address, Mailbox } from 'postal-mime';\n\nfunction isMailbox(addr: Address): addr is Mailbox {\n    return !('group' in addr) || addr.group === undefined;\n}\n\n// Usage\nif (email.from \u0026\u0026 isMailbox(email.from)) {\n    console.log(email.from.address); // TypeScript knows this is a Mailbox\n}\n```\n\n---\n\n## API\n\n### PostalMime.parse()\n\n```js\nPostalMime.parse(email, options) -\u003e Promise\u003cEmail\u003e\n```\n\n-   **email**: An RFC822 formatted email. This can be a `string`, `ArrayBuffer/Uint8Array`, `Blob`, `Buffer` (Node.js), or a [ReadableStream](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream).\n-   **options**: Optional configuration object:\n    -   **rfc822Attachments** (boolean, default: `false`): Treat `message/rfc822` attachments without a Content-Disposition as attachments.\n    -   **forceRfc822Attachments** (boolean, default: `false`): Treat _all_ `message/rfc822` parts as attachments.\n    -   **attachmentEncoding** (string, default: `\"arraybuffer\"`): Determines how attachment content is decoded in the parsed email:\n        -   `\"base64\"`\n        -   `\"utf8\"`\n        -   `\"arraybuffer\"` (no decoding, returns `ArrayBuffer`)\n    -   **maxNestingDepth** (number, default: `256`): Maximum allowed MIME part nesting depth. Throws an error if exceeded.\n    -   **maxHeadersSize** (number, default: `2097152`): Maximum allowed total header size in bytes (default 2MB). Throws an error if exceeded.\n\n\u003e [!IMPORTANT]\n\u003e The `maxNestingDepth` and `maxHeadersSize` options provide built-in security against malicious emails with deeply nested MIME structures or oversized headers that could cause performance issues or memory exhaustion.\n\n**Returns**: A Promise that resolves to a structured `Email` object with the following properties:\n\n-   **headers**: An array of `Header` objects, each containing:\n    -   `key`: Lowercase header name (e.g., `\"dkim-signature\"`).\n    -   `value`: Unprocessed header value as a string.\n-   **from**, **sender**: Processed `Address` objects (can be a `Mailbox` or address group):\n    -   `name`: Decoded display name, or an empty string if not set.\n    -   `address`: Email address.\n    -   `group`: Array of `Mailbox` objects (only for address groups).\n-   **deliveredTo**, **returnPath**: Single email addresses as strings.\n-   **to**, **cc**, **bcc**, **replyTo**: Arrays of `Address` objects (same structure as `from`).\n-   **subject**: Subject line of the email.\n-   **messageId**, **inReplyTo**, **references**: Values from their corresponding headers.\n-   **date**: The email's sending time in ISO 8601 format (or the original string if parsing fails).\n-   **html**: String containing the HTML content of the email.\n-   **text**: String containing the plain text content of the email.\n-   **attachments**: Array of `Attachment` objects:\n    -   `filename`: String or `null`\n    -   `mimeType`: String\n    -   `disposition`: `\"attachment\"`, `\"inline\"`, or `null`\n    -   `related`: Boolean (optional, `true` if it's an inline image)\n    -   `contentId`: String (optional)\n    -   `content`: `ArrayBuffer` or string, depending on `attachmentEncoding`\n    -   `encoding`: `\"base64\"` or `\"utf8\"` (optional)\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eTypeScript Types\u003c/strong\u003e\u003c/summary\u003e\n\n```typescript\nimport type {\n    Email,\n    Address,\n    Mailbox,\n    Header,\n    Attachment,\n    PostalMimeOptions,\n    RawEmail\n} from 'postal-mime';\n\n// Main email parsing\nconst email: Email = await PostalMime.parse(rawEmail);\n\n// With options\nconst options: PostalMimeOptions = {\n    attachmentEncoding: 'base64',\n    maxNestingDepth: 100\n};\nconst email: Email = await PostalMime.parse(rawEmail, options);\n\n// Working with addresses\nif (email.from) {\n    // Address can be either a Mailbox or a Group\n    if ('group' in email.from \u0026\u0026 email.from.group) {\n        // It's a group\n        email.from.group.forEach((member: Mailbox) =\u003e {\n            console.log(member.address);\n        });\n    } else {\n        // It's a mailbox\n        const mailbox = email.from as Mailbox;\n        console.log(mailbox.address);\n    }\n}\n\n// Working with attachments\nemail.attachments.forEach((att: Attachment) =\u003e {\n    if (att.encoding === 'base64') {\n        // content is a string\n        const base64Content: string = att.content as string;\n    } else {\n        // content is ArrayBuffer (default)\n        const buffer: ArrayBuffer = att.content as ArrayBuffer;\n    }\n});\n```\n\n\u003c/details\u003e\n\n---\n\n### Utility Functions\n\n#### addressParser()\n\n```js\nimport { addressParser } from 'postal-mime';\n\naddressParser(addressStr, opts) -\u003e Address[]\n```\n\n-   **addressStr**: A raw address header string.\n-   **opts**: Optional configuration:\n    -   **flatten** (boolean, default: `false`): If `true`, ignores address groups and returns a flat array of addresses.\n\n**Returns**: An array of `Address` objects, which can be nested if address groups are present.\n\n**Example**:\n\n```js\nimport { addressParser } from 'postal-mime';\n\nconst addressStr = '=?utf-8?B?44Ko44Od44K544Kr44O844OJ?= \u003csupport@example.com\u003e';\nconsole.log(addressParser(addressStr));\n// [ { name: 'エポスカード', address: 'support@example.com' } ]\n```\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eTypeScript\u003c/strong\u003e\u003c/summary\u003e\n\n```typescript\nimport { addressParser } from 'postal-mime';\nimport type { Address, AddressParserOptions } from 'postal-mime';\n\nconst addressStr = '=?utf-8?B?44Ko44Od44K544Kr44O844OJ?= \u003csupport@example.com\u003e';\nconst addresses: Address[] = addressParser(addressStr);\n\n// With options\nconst options: AddressParserOptions = { flatten: true };\nconst flatAddresses: Address[] = addressParser(addressStr, options);\n```\n\n\u003c/details\u003e\n\n#### decodeWords()\n\n```js\nimport { decodeWords } from 'postal-mime';\n\ndecodeWords(encodedStr) -\u003e string\n```\n\n-   **encodedStr**: A string that may contain MIME encoded-words.\n\n**Returns**: A Unicode string with all encoded-words decoded.\n\n**Example**:\n\n```js\nimport { decodeWords } from 'postal-mime';\n\nconst encodedStr = 'Hello, =?utf-8?B?44Ko44Od44K544Kr44O844OJ?=';\nconsole.log(decodeWords(encodedStr));\n// Hello, エポスカード\n```\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eTypeScript\u003c/strong\u003e\u003c/summary\u003e\n\n```typescript\nimport { decodeWords } from 'postal-mime';\n\nconst encodedStr = 'Hello, =?utf-8?B?44Ko44Od44K544Kr44O844OJ?=';\nconst decoded: string = decodeWords(encodedStr);\nconsole.log(decoded); // Hello, エポスカード\n```\n\n\u003c/details\u003e\n\n---\n\n## License\n\n\u0026copy; 2021–2026 Andris Reinman\n\n`postal-mime` is licensed under the **MIT No Attribution license**.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpostalsys%2Fpostal-mime","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpostalsys%2Fpostal-mime","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpostalsys%2Fpostal-mime/lists"}