postal-mime 2.1.2 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.2.1](https://github.com/postalsys/postal-mime/compare/v2.2.0...v2.2.1) (2024-03-31)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **parser:** Reply-To value must be an array, not a single address object ([280bd8d](https://github.com/postalsys/postal-mime/commit/280bd8dc1626315e1a43f35641415453c434716e))
9
+
10
+ ## [2.2.0](https://github.com/postalsys/postal-mime/compare/v2.1.2...v2.2.0) (2024-03-26)
11
+
12
+
13
+ ### Features
14
+
15
+ * **interface:** Added statis parse() method to simplify usage (`await PostalMime.parse(email)`) ([c2faa27](https://github.com/postalsys/postal-mime/commit/c2faa276520d6551df640abe008986eebc6d99d3))
16
+
3
17
  ## [2.1.2](https://github.com/postalsys/postal-mime/compare/v2.1.1...v2.1.2) (2024-02-29)
4
18
 
5
19
 
package/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2021-2023 Andris Reinman
1
+ Copyright (c) 2021-2024 Andris Reinman
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,12 +1,15 @@
1
1
  # postal-mime
2
2
 
3
- Email parser for browser environments.
3
+ Email parser for browser and serverless environments.
4
4
 
5
- PostalMime can be run in the main web thread or from Web Workers.
5
+ PostalMime can be run in the main web thread or from Web Workers. It can also used in serverless functions.
6
+
7
+ > [!TIP]
8
+ > PostalMime is developed by the makers of **[EmailEngine](https://emailengine.app/?utm_source=github&utm_campaign=imapflow&utm_medium=readme-link)** – a self-hosted email gateway that allows making **REST requests against IMAP and SMTP servers**. EmailEngine also sends webhooks whenever something changes on the registered accounts.
6
9
 
7
10
  ## Source
8
11
 
9
- Source code is available from [Github](https://github.com/postalsys/postal-mime).
12
+ The source code is available from [Github](https://github.com/postalsys/postal-mime).
10
13
 
11
14
  ## Demo
12
15
 
@@ -14,7 +17,7 @@ See this [example](https://kreata.ee/postal-mime/example/).
14
17
 
15
18
  ## Usage
16
19
 
17
- First install the module from npm:
20
+ First, install the module from npm:
18
21
 
19
22
  ```
20
23
  $ npm install postal-mime
@@ -26,7 +29,7 @@ next import the PostalMime class into your script:
26
29
  import PostalMime from './node_modules/postal-mime/src/postal-mime.js';
27
30
  ```
28
31
 
29
- or when using from a Node.js app
32
+ or when using from a Node.js app or in a serverless function:
30
33
 
31
34
  ```js
32
35
  import PostalMime from 'postal-mime';
@@ -34,15 +37,14 @@ import PostalMime from 'postal-mime';
34
37
 
35
38
  ### Promises
36
39
 
37
- All postal-mime methods use Promises, so you need to wait using `await` or wait for the `then()` method to fire until you get the response.
40
+ PostalMime methods use Promises, so you need to wait using `await` or wait for the `then()` method to fire until you get the response.
38
41
 
39
42
  #### Browser
40
43
 
41
44
  ```js
42
45
  import PostalMime from './node_modules/postal-mime/src/postal-mime.js';
43
46
 
44
- const parser = new PostalMime();
45
- const email = await parser.parse(`Subject: My awesome email 🤓
47
+ const email = await PostalMime.parse(`Subject: My awesome email 🤓
46
48
  Content-Type: text/html; charset=utf-8
47
49
 
48
50
  <p>Hello world 😵‍💫</p>`);
@@ -58,8 +60,7 @@ It is pretty much the same as in the browser.
58
60
  import PostalMime from 'postal-mime';
59
61
  import util from 'node:util';
60
62
 
61
- const parser = new PostalMime();
62
- const email = await parser.parse(`Subject: My awesome email 🤓
63
+ const email = await PostalMime.parse(`Subject: My awesome email 🤓
63
64
  Content-Type: text/html; charset=utf-8
64
65
 
65
66
  <p>Hello world 😵‍💫</p>`);
@@ -76,8 +77,7 @@ import PostalMime from 'postal-mime';
76
77
 
77
78
  export default {
78
79
  async email(message, env, ctx) {
79
- const parser = new PostalMime();
80
- const email = await parser.parse(message.raw);
80
+ const email = await PostalMime.parse(message.raw);
81
81
 
82
82
  console.log('Subject: ', email.subject);
83
83
  console.log('HTML: ', email.html);
@@ -86,28 +86,28 @@ export default {
86
86
  };
87
87
  ```
88
88
 
89
- #### parser.parse()
89
+ #### PostalMime.parse()
90
+
91
+ `parse(email)` is a static class method to parse emails
90
92
 
91
93
  ```js
92
- parser.parse(email) -> Promise
94
+ PostalMime.parse(email) -> Promise
93
95
  ```
94
96
 
95
97
  Where
96
98
 
97
- - **email** is the rfc822 formatted email. Either a string, an ArrayBuffer, a Blob object or a Node.js Buffer
98
-
99
- > **NB** you can call `parse()` only once. If you need to parse another message, create a new _PostalMime_ object.
99
+ - **email** is the rfc822 formatted email. Either a string, an ArrayBuffer/Uint8Array value, a Blob object, a Node.js Buffer, or a [ReadableStream](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream)
100
100
 
101
101
  This method parses an email message into a structured object with the following properties:
102
102
 
103
103
  - **headers** is an array of headers in the same order as found from the message (topmost headers first).
104
104
  - **headers[].key** is lowercase key of the header line, eg. `"dkim-signature"`
105
105
  - **headers[].value** is the unprocessed value of the header line
106
- - **from**, **sender**, **replyTo** includes a processed object for the corresponding headers
106
+ - **from**, **sender** includes a processed object for the corresponding headers
107
107
  - **from.name** is decoded name (empty string if not set)
108
108
  - **from.address** is the email address
109
109
  - **deliveredTo**, **returnPath** is the email address from the corresponding header
110
- - **to**, **cc**, **bcc** includes an array of processed objects for the corresponding headers
110
+ - **to**, **cc**, **bcc**, **replyTo** includes an array of processed objects for the corresponding headers
111
111
  - **to[].name** is decoded name (empty string if not set)
112
112
  - **to[].address** is the email address
113
113
  - **subject** is the email subject line
@@ -121,10 +121,10 @@ This method parses an email message into a structured object with the following
121
121
  - **attachment[].disposition** is either "attachment", "inline" or `null` if disposition was not provided
122
122
  - **attachment[].related** is a boolean value that indicats if this attachment should be treated as embedded image
123
123
  - **attachment[].contentId** is the ID from Content-ID header
124
- - **attachment[].content** is an ArrayBuffer that contains the attachment file
124
+ - **attachment[].content** is an Uint8Array value that contains the attachment file
125
125
 
126
126
  ## License
127
127
 
128
- &copy; 2021-2023 Andris Reinman
128
+ &copy; 2021-2024 Andris Reinman
129
129
 
130
130
  `postal-mime` is licensed under the **MIT No Attribution license**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "postal-mime",
3
- "version": "2.1.2",
3
+ "version": "2.2.1",
4
4
  "description": "Email parser for browser environments",
5
5
  "main": "./src/postal-mime.js",
6
6
  "exports": {
@@ -27,7 +27,7 @@
27
27
  "author": "Andris Reinman",
28
28
  "license": "MIT-0",
29
29
  "devDependencies": {
30
- "@types/node": "20.11.22",
30
+ "@types/node": "20.11.30",
31
31
  "cross-blob": "3.0.2",
32
32
  "cross-env": "7.0.3",
33
33
  "eslint": "8.57.0",
package/postal-mime.d.ts CHANGED
@@ -37,6 +37,7 @@ export type Email = {
37
37
  };
38
38
 
39
39
  declare class PostalMime {
40
+ static parse(email: RawEmail): Promise<Email>;
40
41
  parse(email: RawEmail): Promise<Email>;
41
42
  }
42
43
 
@@ -4,6 +4,11 @@ import addressParser from './address-parser.js';
4
4
  import { decodeWords, textEncoder, blobToArrayBuffer } from './decode-strings.js';
5
5
 
6
6
  export default class PostalMime {
7
+ static parse(buf) {
8
+ const parser = new PostalMime();
9
+ return parser.parse(buf);
10
+ }
11
+
7
12
  constructor() {
8
13
  this.root = this.currentNode = new MimeNode({
9
14
  postalMime: this
@@ -353,32 +358,33 @@ export default class PostalMime {
353
358
 
354
359
  await this.processNodeTree();
355
360
 
356
- let message = {
361
+ const message = {
357
362
  headers: this.root.headers.map(entry => ({ key: entry.key, value: entry.value })).reverse()
358
363
  };
359
364
 
360
- for (let key of ['from', 'sender', 'reply-to']) {
361
- let addressHeader = this.root.headers.find(line => line.key === key);
365
+ for (const key of ['from', 'sender']) {
366
+ const addressHeader = this.root.headers.find(line => line.key === key);
362
367
  if (addressHeader && addressHeader.value) {
363
- let addresses = addressParser(addressHeader.value);
368
+ const addresses = addressParser(addressHeader.value);
364
369
  if (addresses && addresses.length) {
365
- message[key.replace(/\-(.)/g, (o, c) => c.toUpperCase())] = addresses[0];
370
+ message[key] = addresses[0];
366
371
  }
367
372
  }
368
373
  }
369
374
 
370
- for (let key of ['delivered-to', 'return-path']) {
371
- let addressHeader = this.root.headers.find(line => line.key === key);
375
+ for (const key of ['delivered-to', 'return-path']) {
376
+ const addressHeader = this.root.headers.find(line => line.key === key);
372
377
  if (addressHeader && addressHeader.value) {
373
- let addresses = addressParser(addressHeader.value);
378
+ const addresses = addressParser(addressHeader.value);
374
379
  if (addresses && addresses.length && addresses[0].address) {
375
- message[key.replace(/\-(.)/g, (o, c) => c.toUpperCase())] = addresses[0].address;
380
+ const camelKey = key.replace(/\-(.)/g, (o, c) => c.toUpperCase());
381
+ message[camelKey] = addresses[0].address;
376
382
  }
377
383
  }
378
384
  }
379
385
 
380
- for (let key of ['to', 'cc', 'bcc']) {
381
- let addressHeaders = this.root.headers.filter(line => line.key === key);
386
+ for (const key of ['to', 'cc', 'bcc', 'reply-to']) {
387
+ const addressHeaders = this.root.headers.filter(line => line.key === key);
382
388
  let addresses = [];
383
389
 
384
390
  addressHeaders
@@ -387,14 +393,16 @@ export default class PostalMime {
387
393
  .forEach(parsed => (addresses = addresses.concat(parsed || [])));
388
394
 
389
395
  if (addresses && addresses.length) {
390
- message[key] = addresses;
396
+ const camelKey = key.replace(/\-(.)/g, (o, c) => c.toUpperCase());
397
+ message[camelKey] = addresses;
391
398
  }
392
399
  }
393
400
 
394
- for (let key of ['subject', 'message-id', 'in-reply-to', 'references']) {
395
- let header = this.root.headers.find(line => line.key === key);
401
+ for (const key of ['subject', 'message-id', 'in-reply-to', 'references']) {
402
+ const header = this.root.headers.find(line => line.key === key);
396
403
  if (header && header.value) {
397
- message[key.replace(/\-(.)/g, (o, c) => c.toUpperCase())] = decodeWords(header.value);
404
+ const camelKey = key.replace(/\-(.)/g, (o, c) => c.toUpperCase());
405
+ message[camelKey] = decodeWords(header.value);
398
406
  }
399
407
  }
400
408