postal-mime 2.2.6 → 2.2.7

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,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.2.7](https://github.com/postalsys/postal-mime/compare/v2.2.6...v2.2.7) (2024-07-31)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **rfc822:** Only inline message/rfc822 messages if Content-Disposition is ([53024de](https://github.com/postalsys/postal-mime/commit/53024dec22ea121817913a9cf152bdf60acbdbe7))
9
+
3
10
  ## [2.2.6](https://github.com/postalsys/postal-mime/compare/v2.2.5...v2.2.6) (2024-07-09)
4
11
 
5
12
 
package/README.md CHANGED
@@ -2,14 +2,14 @@
2
2
 
3
3
  Email parser for browser and serverless environments.
4
4
 
5
- PostalMime can be run in the main web thread or from Web Workers. It can also used in serverless functions.
5
+ PostalMime can be run in the main web thread or from Web Workers. It can also be used in serverless functions.
6
6
 
7
7
  > [!TIP]
8
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.
9
9
 
10
10
  ## Source
11
11
 
12
- The source code is available from [Github](https://github.com/postalsys/postal-mime).
12
+ The source code is available on [GitHub](https://github.com/postalsys/postal-mime).
13
13
 
14
14
  ## Demo
15
15
 
@@ -23,13 +23,13 @@ First, install the module from npm:
23
23
  $ npm install postal-mime
24
24
  ```
25
25
 
26
- next import the PostalMime class into your script:
26
+ Next, import the PostalMime class into your script:
27
27
 
28
28
  ```js
29
29
  import PostalMime from './node_modules/postal-mime/src/postal-mime.js';
30
30
  ```
31
31
 
32
- or when using from a Node.js app or in a serverless function:
32
+ Or when using it from a Node.js app or in a serverless function:
33
33
 
34
34
  ```js
35
35
  import PostalMime from 'postal-mime';
@@ -37,7 +37,7 @@ import PostalMime from 'postal-mime';
37
37
 
38
38
  ### Promises
39
39
 
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.
40
+ PostalMime methods use Promises, so you need to wait using `await` or the `then()` method to get the response.
41
41
 
42
42
  #### Browser
43
43
 
@@ -88,62 +88,64 @@ export default {
88
88
 
89
89
  #### PostalMime.parse()
90
90
 
91
- `parse(email)` is a static class method to parse emails
91
+ `parse(email, options)` is a static class method used to parse emails.
92
92
 
93
93
  ```js
94
- PostalMime.parse(email) -> Promise
94
+ PostalMime.parse(email, options) -> Promise
95
95
  ```
96
96
 
97
- Where
97
+ Where:
98
98
 
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)
99
+ - **email**: The RFC822 formatted email. This can be a string, an ArrayBuffer/Uint8Array, a Blob object, a Node.js Buffer, or a [ReadableStream](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream).
100
+ - **options**: An optional object containing configuration options.
101
+ - **rfc822Attachments**: A boolean (defaults to `false`). If set to `true`, it treats `Message/RFC822` attachments without a Content-Disposition declaration as attachments. By default, these messages are treated as inline values.
100
102
 
101
103
  This method parses an email message into a structured object with the following properties:
102
104
 
103
- - **headers** is an array of headers in the same order as found from the message (topmost headers first).
104
- - **headers[].key** is lowercase key of the header line, eg. `"dkim-signature"`
105
- - **headers[].value** is the unprocessed value of the header line
106
- - **from**, **sender** includes a processed object for the corresponding headers
107
- - **from.name** is decoded name (empty string if not set)
108
- - **from.address** is the email address
109
- - **deliveredTo**, **returnPath** is the email address from the corresponding header
110
- - **to**, **cc**, **bcc**, **replyTo** includes an array of processed objects for the corresponding headers
111
- - **to[].name** is decoded name (empty string if not set)
112
- - **to[].address** is the email address
113
- - **subject** is the email subject line
114
- - **messageId**, **inReplyTo**, **references** includes the value as found from the corresponding header without any processing
115
- - **date** is the email sending time formatted as an ISO date string (unless parsing failed and in this case the original value is used)
116
- - **html** is the HTML content of the message as a string
117
- - **text** is the plaintext content of the message as a string
118
- - **attachments** is an array that includes message attachments
119
- - **attachment[].filename** is the file name if provided
120
- - **attachment[].mimeType** is the MIME type of the attachment
121
- - **attachment[].disposition** is either "attachment", "inline" or `null` if disposition was not provided
122
- - **attachment[].related** is a boolean value that indicats if this attachment should be treated as embedded image
123
- - **attachment[].contentId** is the ID from Content-ID header
124
- - **attachment[].content** is an Uint8Array value that contains the attachment file
125
-
126
- ### Utility functions
105
+ - **headers**: An array of headers in the order they appear in the message (topmost headers first).
106
+ - **headers[].key**: The lowercase key of the header line, e.g., `"dkim-signature"`.
107
+ - **headers[].value**: The unprocessed value of the header line.
108
+ - **from**, **sender**: Includes a processed object for the corresponding headers.
109
+ - **from.name**: The decoded name (empty string if not set).
110
+ - **from.address**: The email address.
111
+ - **deliveredTo**, **returnPath**: The email address from the corresponding header.
112
+ - **to**, **cc**, **bcc**, **replyTo**: An array of processed objects for the corresponding headers.
113
+ - **to[].name**: The decoded name (empty string if not set).
114
+ - **to[].address**: The email address.
115
+ - **subject**: The email subject line.
116
+ - **messageId**, **inReplyTo**, **references**: The value as found in the corresponding header without any processing.
117
+ - **date**: The email sending time formatted as an ISO date string (unless parsing failed, in which case the original value is used).
118
+ - **html**: The HTML content of the message as a string.
119
+ - **text**: The plaintext content of the message as a string.
120
+ - **attachments**: An array that includes the message attachments.
121
+ - **attachments[].filename**: The file name if provided.
122
+ - **attachments[].mimeType**: The MIME type of the attachment.
123
+ - **attachments[].disposition**: Either "attachment", "inline", or `null` if disposition was not provided.
124
+ - **attachments[].related**: A boolean value indicating if this attachment should be treated as an embedded image.
125
+ - **attachments[].contentId**: The ID from the Content-ID header.
126
+ - **attachments[].content**: A Uint8Array value that contains the attachment file.
127
+
128
+ ### Utility Functions
127
129
 
128
130
  #### addressParser
129
131
 
130
- Parse email address strings
132
+ Parse email address strings.
131
133
 
132
134
  ```js
133
135
  addressParser(addressStr, opts) -> Array
134
136
  ```
135
137
 
136
- where
138
+ Where:
137
139
 
138
- - **addressStr** is the header value for an address header
139
- - **opts** is an optional options object
140
- - **flatten** is a boolean value. If set to `true`, then ignores address groups and returns a flat array of addresses. By default (`flatten` is `false`) the result might include nested groups
140
+ - **addressStr**: The header value for an address header.
141
+ - **opts**: An optional object containing configuration options.
142
+ - **flatten**: A boolean value. If set to `true`, it ignores address groups and returns a flat array of addresses. By default (`flatten` is `false`), the result might include nested groups.
141
143
 
142
- The result is an array of objects
144
+ The result is an array of objects:
143
145
 
144
- - **name** is the name string. An empty string is used if name value was not set.
145
- - **address** is the email address value
146
- - **group** is an array of nested address objects. This is used when `flatten` is `false` (the default) and the address string contains address group syntax
146
+ - **name**: The name string. An empty string is used if the name value is not set.
147
+ - **address**: The email address value.
148
+ - **group**: An array of nested address objects. This is used when `flatten` is `false` (the default) and the address string contains address group syntax.
147
149
 
148
150
  ```js
149
151
  import { addressParser } from 'postal-mime';
@@ -155,17 +157,17 @@ console.log(addressParser(addressStr));
155
157
 
156
158
  #### decodeWords
157
159
 
158
- Decode MIME encoded-words
160
+ Decode MIME encoded-words.
159
161
 
160
162
  ```js
161
163
  decodeWords(encodedStr) -> String
162
164
  ```
163
165
 
164
- where
166
+ Where:
165
167
 
166
- - **encodedStr** is a string value that _may_ include MIME encoded-words
168
+ - **encodedStr**: A string value that _may_ include MIME encoded-words.
167
169
 
168
- The result is a unicode string
170
+ The result is a Unicode string.
169
171
 
170
172
  ```js
171
173
  import { decodeWords } from 'postal-mime';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "postal-mime",
3
- "version": "2.2.6",
3
+ "version": "2.2.7",
4
4
  "description": "Email parser for browser environments",
5
5
  "main": "./src/postal-mime.js",
6
6
  "exports": {
@@ -27,11 +27,11 @@
27
27
  "author": "Andris Reinman",
28
28
  "license": "MIT-0",
29
29
  "devDependencies": {
30
- "@types/node": "20.14.10",
30
+ "@types/node": "22.0.0",
31
31
  "cross-blob": "3.0.2",
32
32
  "cross-env": "7.0.3",
33
33
  "eslint": "8.57.0",
34
34
  "eslint-cli": "1.1.1",
35
- "iframe-resizer": "4.4.4"
35
+ "iframe-resizer": "4.4.5"
36
36
  }
37
37
  }
package/postal-mime.d.ts CHANGED
@@ -3,40 +3,40 @@ export type RawEmail = string | ArrayBuffer | Uint8Array | Blob | Buffer | Reada
3
3
  export type Header = Record<string, string>;
4
4
 
5
5
  export type Address = {
6
- name: string;
6
+ name: string;
7
7
  address?: string;
8
8
  group?: Address[]
9
9
  };
10
10
 
11
11
  export type Attachment = {
12
- filename: string | null;
13
- mimeType: string;
14
- disposition: "attachment" | "inline" | null;
15
- related?: boolean;
12
+ filename: string | null;
13
+ mimeType: string;
14
+ disposition: "attachment" | "inline" | null;
15
+ related?: boolean;
16
16
  description?: string;
17
- contentId?: string;
17
+ contentId?: string;
18
18
  method?: string;
19
- content: ArrayBuffer;
19
+ content: ArrayBuffer;
20
20
  };
21
21
 
22
22
  export type Email = {
23
- headers: Header[];
24
- from: Address;
25
- sender?: Address;
26
- replyTo?: Address[];
27
- deliveredTo?: string;
28
- returnPath?: string;
29
- to?: Address[];
30
- cc?: Address[];
31
- bcc?: Address[];
32
- subject?: string;
33
- messageId: string;
34
- inReplyTo?: string;
35
- references?: string;
36
- date?: string;
37
- html?: string;
38
- text?: string;
39
- attachments: Attachment[];
23
+ headers: Header[];
24
+ from: Address;
25
+ sender?: Address;
26
+ replyTo?: Address[];
27
+ deliveredTo?: string;
28
+ returnPath?: string;
29
+ to?: Address[];
30
+ cc?: Address[];
31
+ bcc?: Address[];
32
+ subject?: string;
33
+ messageId: string;
34
+ inReplyTo?: string;
35
+ references?: string;
36
+ date?: string;
37
+ html?: string;
38
+ text?: string;
39
+ attachments: Attachment[];
40
40
  };
41
41
 
42
42
  declare type AddressParserOptions = {
@@ -45,16 +45,24 @@ declare type AddressParserOptions = {
45
45
 
46
46
  declare function addressParser (
47
47
  str: string,
48
- opts?: AddressParserOptions
48
+ options?: AddressParserOptions
49
49
  ): Address[];
50
50
 
51
51
  declare function decodeWords (
52
52
  str: string
53
53
  ): string;
54
54
 
55
+ declare type PostalMimeOptions = {
56
+ rfc822Attachments?: boolean
57
+ }
58
+
55
59
  declare class PostalMime {
56
- static parse(email: RawEmail): Promise<Email>;
57
- parse(email: RawEmail): Promise<Email>;
60
+ constructor(options?: PostalMimeOptions);
61
+ static parse(
62
+ email: RawEmail,
63
+ options?: PostalMimeOptions
64
+ ): Promise<Email>;
65
+ parse(email: RawEmail): Promise<Email>;
58
66
  }
59
67
 
60
68
  export { addressParser, decodeWords };
@@ -6,12 +6,14 @@ import { decodeWords, textEncoder, blobToArrayBuffer } from './decode-strings.js
6
6
  export { addressParser, decodeWords };
7
7
 
8
8
  export default class PostalMime {
9
- static parse(buf) {
10
- const parser = new PostalMime();
9
+ static parse(buf, options) {
10
+ const parser = new PostalMime(options);
11
11
  return parser.parse(buf);
12
12
  }
13
13
 
14
- constructor() {
14
+ constructor(options) {
15
+ this.options = options || {};
16
+
15
17
  this.root = this.currentNode = new MimeNode({
16
18
  postalMime: this
17
19
  });
@@ -129,7 +131,7 @@ export default class PostalMime {
129
131
  // regular node
130
132
 
131
133
  // is it inline message/rfc822
132
- if (node.contentType.parsed.value === 'message/rfc822' && node.contentDisposition.parsed.value !== 'attachment') {
134
+ if (this.isInlineMessageRfc822(node)) {
133
135
  const subParser = new PostalMime();
134
136
  node.subMessage = await subParser.parse(node.content);
135
137
 
@@ -339,6 +341,14 @@ export default class PostalMime {
339
341
  }
340
342
  }
341
343
 
344
+ isInlineMessageRfc822(node) {
345
+ if (node.contentType.parsed.value !== 'message/rfc822') {
346
+ return false;
347
+ }
348
+ let disposition = node.contentDisposition.parsed.value || (this.options.rfc822Attachments ? 'attachment' : 'inline');
349
+ return disposition === 'inline';
350
+ }
351
+
342
352
  async resolveStream(stream) {
343
353
  let chunkLen = 0;
344
354
  let chunks = [];