@remit/mailbox-service 0.0.64 → 0.0.66

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.
Files changed (51) hide show
  1. package/package.json +1 -4
  2. package/src/adversarial-mime.e2e.test.ts +2 -2
  3. package/src/message-move.ts +16 -8
  4. package/test/fixtures/mime/01-flat-text-plain.bodyparts.json +0 -8
  5. package/test/fixtures/mime/01-flat-text-plain.eml +0 -10
  6. package/test/fixtures/mime/01-flat-text-plain.expected.json +0 -10
  7. package/test/fixtures/mime/02-flat-text-html.bodyparts.json +0 -8
  8. package/test/fixtures/mime/02-flat-text-html.eml +0 -10
  9. package/test/fixtures/mime/02-flat-text-html.expected.json +0 -10
  10. package/test/fixtures/mime/03-alternative-text-html.bodyparts.json +0 -20
  11. package/test/fixtures/mime/03-alternative-text-html.eml +0 -19
  12. package/test/fixtures/mime/03-alternative-text-html.expected.json +0 -16
  13. package/test/fixtures/mime/04-mixed-html-pdf-attachment.bodyparts.json +0 -22
  14. package/test/fixtures/mime/04-mixed-html-pdf-attachment.eml +0 -20
  15. package/test/fixtures/mime/04-mixed-html-pdf-attachment.expected.json +0 -16
  16. package/test/fixtures/mime/05-mixed-html-octet-stream-pdf.bodyparts.json +0 -22
  17. package/test/fixtures/mime/05-mixed-html-octet-stream-pdf.eml +0 -21
  18. package/test/fixtures/mime/05-mixed-html-octet-stream-pdf.expected.json +0 -16
  19. package/test/fixtures/mime/06-related-html-cid-image.bodyparts.json +0 -23
  20. package/test/fixtures/mime/06-related-html-cid-image.eml +0 -21
  21. package/test/fixtures/mime/06-related-html-cid-image.expected.json +0 -16
  22. package/test/fixtures/mime/07-mixed-alternative-related-attachment.bodyparts.json +0 -55
  23. package/test/fixtures/mime/07-mixed-alternative-related-attachment.eml +0 -47
  24. package/test/fixtures/mime/07-mixed-alternative-related-attachment.expected.json +0 -34
  25. package/test/fixtures/mime/08-two-pdfs-same-filename.bodyparts.json +0 -30
  26. package/test/fixtures/mime/08-two-pdfs-same-filename.eml +0 -26
  27. package/test/fixtures/mime/08-two-pdfs-same-filename.expected.json +0 -22
  28. package/test/fixtures/mime/09-attachment-no-filename.bodyparts.json +0 -21
  29. package/test/fixtures/mime/09-attachment-no-filename.eml +0 -20
  30. package/test/fixtures/mime/09-attachment-no-filename.expected.json +0 -16
  31. package/test/fixtures/mime/10-calendar-invite.bodyparts.json +0 -22
  32. package/test/fixtures/mime/10-calendar-invite.eml +0 -33
  33. package/test/fixtures/mime/10-calendar-invite.expected.json +0 -16
  34. package/test/fixtures/mime/11-quoted-printable-text.bodyparts.json +0 -8
  35. package/test/fixtures/mime/11-quoted-printable-text.eml +0 -10
  36. package/test/fixtures/mime/11-quoted-printable-text.expected.json +0 -10
  37. package/test/fixtures/mime/12-base64-binary.bodyparts.json +0 -22
  38. package/test/fixtures/mime/12-base64-binary.eml +0 -20
  39. package/test/fixtures/mime/12-base64-binary.expected.json +0 -16
  40. package/test/fixtures/mime/13-message-rfc822-forward.bodyparts.json +0 -22
  41. package/test/fixtures/mime/13-message-rfc822-forward.eml +0 -28
  42. package/test/fixtures/mime/13-message-rfc822-forward.expected.json +0 -16
  43. package/test/fixtures/mime/14-deeply-nested-5-levels.bodyparts.json +0 -38
  44. package/test/fixtures/mime/14-deeply-nested-5-levels.eml +0 -34
  45. package/test/fixtures/mime/14-deeply-nested-5-levels.expected.json +0 -10
  46. package/test/fixtures/mime/15-empty-text-part.bodyparts.json +0 -21
  47. package/test/fixtures/mime/15-empty-text-part.eml +0 -18
  48. package/test/fixtures/mime/15-empty-text-part.expected.json +0 -16
  49. package/test/fixtures/mime/16-empty-non-text-part.bodyparts.json +0 -30
  50. package/test/fixtures/mime/16-empty-non-text-part.eml +0 -24
  51. package/test/fixtures/mime/16-empty-non-text-part.expected.json +0 -22
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remit/mailbox-service",
3
- "version": "0.0.64",
3
+ "version": "0.0.66",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -25,9 +25,6 @@
25
25
  "test:e2e": "RUN_E2E_TESTS=1 node --env-file=../../localhost-test-e2e.env --import tsx --test --test-concurrency=1 'src/**/*.e2e.test.ts'",
26
26
  "test": "npm run test:typecheck && npm run test:run"
27
27
  },
28
- "devDependencies": {
29
- "@types/uuid": "^10.0.0"
30
- },
31
28
  "dependencies": {
32
29
  "imapflow": "^1.3.3",
33
30
  "mailparser": "^3.9.14",
@@ -16,8 +16,8 @@
16
16
  * 8-bit UTF-8 bodies, empty text/plain alternatives) — the same class of shape
17
17
  * that caused the body-sync regression in #394.
18
18
  *
19
- * Mapper unit-level defence lives in `test/fixtures/mime/`; this suite is the
20
- * integration-layer belt-and-braces against the same regression class.
19
+ * Mapper unit-level defence lives in `body-part-mapper.property.test.ts`; this
20
+ * suite is the integration-layer belt-and-braces against the same class.
21
21
  */
22
22
 
23
23
  import assert from "node:assert/strict";
@@ -11,10 +11,14 @@ import type {
11
11
  IMessageRepository,
12
12
  IThreadMessageRepository,
13
13
  } from "@remit/data-ports";
14
- import { HTTPError } from "@remit/data-ports/errors";
14
+ import { FolderRoleUnresolvedError } from "@remit/data-ports/errors";
15
15
  import { NO_TRASH_FOLDER_REASON } from "@remit/data-ports/folder-role";
16
16
  import { deriveCopyMessageId } from "@remit/data-ports/id";
17
- import { MessageStatus, MessageSyncStatus } from "@remit/domain-enums";
17
+ import {
18
+ CanonicalMailboxRole,
19
+ MessageStatus,
20
+ MessageSyncStatus,
21
+ } from "@remit/domain-enums";
18
22
  import { createQueueProducer } from "@remit/sqs-client/producer";
19
23
 
20
24
  /**
@@ -112,12 +116,16 @@ export interface MessageMoveConfig {
112
116
  * verbatim: the absence of a Trash folder is a blocker the user resolves by
113
117
  * appointing one, never a licence to expunge.
114
118
  */
115
- export class NoTrashMailboxError extends HTTPError {
119
+ export class NoTrashMailboxError extends FolderRoleUnresolvedError {
116
120
  name = "NoTrashMailboxError";
117
- statusCode = 409;
118
121
 
119
- constructor() {
120
- super(NO_TRASH_FOLDER_REASON);
122
+ constructor(accountId: string) {
123
+ super(
124
+ NO_TRASH_FOLDER_REASON,
125
+ CanonicalMailboxRole.Trash,
126
+ "none",
127
+ accountId,
128
+ );
121
129
  }
122
130
  }
123
131
 
@@ -227,7 +235,7 @@ export class MessageMoveService {
227
235
  { accountId, messageCount: messages.length },
228
236
  "Refused to delete: account resolves no Trash mailbox",
229
237
  );
230
- throw new NoTrashMailboxError();
238
+ throw new NoTrashMailboxError(accountId);
231
239
  }
232
240
 
233
241
  // Group messages by operation type
@@ -667,7 +675,7 @@ export class MessageMoveService {
667
675
  await this.mailboxSpecialUseService.findConfirmedTrashMailbox(accountId);
668
676
 
669
677
  if (!trashMailbox) {
670
- throw new NoTrashMailboxError();
678
+ throw new NoTrashMailboxError(accountId);
671
679
  }
672
680
 
673
681
  // Get all messages in Trash
@@ -1,8 +0,0 @@
1
- [
2
- {
3
- "partPath": "0",
4
- "isMultipart": false,
5
- "mediaType": "TEXT",
6
- "mediaSubtype": "plain"
7
- }
8
- ]
@@ -1,10 +0,0 @@
1
- From: alice@example.org
2
- To: bob@example.org
3
- Subject: Flat text/plain fixture 01
4
- Date: Thu, 28 May 2026 09:00:00 +0000
5
- Message-Id: <fixture-01@example.org>
6
- MIME-Version: 1.0
7
- Content-Type: text/plain; charset=us-ascii
8
- Content-Transfer-Encoding: 7bit
9
-
10
- Hello bob, this is a flat text/plain message.
@@ -1,10 +0,0 @@
1
- {
2
- "pairs": [
3
- {
4
- "partPath": "0",
5
- "contentType": "text/plain",
6
- "contentSha256": "55ac4ab155dd2b05e3d4ffb422c6fc2539484dfb07c7b5b5fac1d0035ac1f6db",
7
- "contentLength": 46
8
- }
9
- ]
10
- }
@@ -1,8 +0,0 @@
1
- [
2
- {
3
- "partPath": "0",
4
- "isMultipart": false,
5
- "mediaType": "TEXT",
6
- "mediaSubtype": "html"
7
- }
8
- ]
@@ -1,10 +0,0 @@
1
- From: alice@example.org
2
- To: bob@example.org
3
- Subject: Flat text/html fixture 02
4
- Date: Thu, 28 May 2026 09:00:00 +0000
5
- Message-Id: <fixture-02@example.org>
6
- MIME-Version: 1.0
7
- Content-Type: text/html; charset=us-ascii
8
- Content-Transfer-Encoding: 7bit
9
-
10
- <html><body><p>Hello bob, this is a flat <b>text/html</b> message.</p></body></html>
@@ -1,10 +0,0 @@
1
- {
2
- "pairs": [
3
- {
4
- "partPath": "0",
5
- "contentType": "text/html",
6
- "contentSha256": "4484f960dbbb61e252b8ac3dd516a3c651a90ed666781befe67c6e13d30f3b4e",
7
- "contentLength": 85
8
- }
9
- ]
10
- }
@@ -1,20 +0,0 @@
1
- [
2
- {
3
- "partPath": "0",
4
- "isMultipart": true,
5
- "mediaType": "MULTIPART",
6
- "mediaSubtype": "alternative"
7
- },
8
- {
9
- "partPath": "1",
10
- "isMultipart": false,
11
- "mediaType": "TEXT",
12
- "mediaSubtype": "plain"
13
- },
14
- {
15
- "partPath": "2",
16
- "isMultipart": false,
17
- "mediaType": "TEXT",
18
- "mediaSubtype": "html"
19
- }
20
- ]
@@ -1,19 +0,0 @@
1
- From: alice@example.org
2
- To: bob@example.org
3
- Subject: Alternative text+html fixture 03
4
- Date: Thu, 28 May 2026 09:00:00 +0000
5
- Message-Id: <fixture-03@example.org>
6
- MIME-Version: 1.0
7
- Content-Type: multipart/alternative; boundary="=_boundary_03_="
8
-
9
- --=_boundary_03_=
10
- Content-Type: text/plain; charset=us-ascii
11
- Content-Transfer-Encoding: 7bit
12
-
13
- Hello bob, plain text body.
14
- --=_boundary_03_=
15
- Content-Type: text/html; charset=us-ascii
16
- Content-Transfer-Encoding: 7bit
17
-
18
- <html><body><p>Hello bob, html body.</p></body></html>
19
- --=_boundary_03_=--
@@ -1,16 +0,0 @@
1
- {
2
- "pairs": [
3
- {
4
- "partPath": "1",
5
- "contentType": "text/plain",
6
- "contentSha256": "54178e683cea517723189e2851efd8449bac73f2b57c50bd81a0c8a6df4ce7c8",
7
- "contentLength": 27
8
- },
9
- {
10
- "partPath": "2",
11
- "contentType": "text/html",
12
- "contentSha256": "71744f8d83087de2acde32d5b9ec93ecfe1b5ba677f760655643dabfd0ce661d",
13
- "contentLength": 54
14
- }
15
- ]
16
- }
@@ -1,22 +0,0 @@
1
- [
2
- {
3
- "partPath": "0",
4
- "isMultipart": true,
5
- "mediaType": "MULTIPART",
6
- "mediaSubtype": "mixed"
7
- },
8
- {
9
- "partPath": "1",
10
- "isMultipart": false,
11
- "mediaType": "TEXT",
12
- "mediaSubtype": "html"
13
- },
14
- {
15
- "partPath": "2",
16
- "isMultipart": false,
17
- "mediaType": "APPLICATION",
18
- "mediaSubtype": "pdf",
19
- "dispositionFilename": "invoice.pdf",
20
- "disposition": "attachment"
21
- }
22
- ]
@@ -1,20 +0,0 @@
1
- From: alice@example.org
2
- To: bob@example.org
3
- Subject: Mixed html + pdf fixture 04
4
- Date: Thu, 28 May 2026 09:00:00 +0000
5
- Message-Id: <fixture-04@example.org>
6
- MIME-Version: 1.0
7
- Content-Type: multipart/mixed; boundary="=_boundary_04_="
8
-
9
- --=_boundary_04_=
10
- Content-Type: text/html; charset=us-ascii
11
- Content-Transfer-Encoding: 7bit
12
-
13
- <html><body><p>See attached invoice.</p></body></html>
14
- --=_boundary_04_=
15
- Content-Type: application/pdf; name="invoice.pdf"
16
- Content-Transfer-Encoding: base64
17
- Content-Disposition: attachment; filename="invoice.pdf"
18
-
19
- JVBERi0xLjQKJWZha2UgcGRmIGZvciBmaXh0dXJlIDA0CiVFT0YK
20
- --=_boundary_04_=--
@@ -1,16 +0,0 @@
1
- {
2
- "pairs": [
3
- {
4
- "partPath": "1",
5
- "contentType": "text/html",
6
- "contentSha256": "d8d4d207e4f8d121a1d60fe74922da8b562ebada6a4a58b2d0f2b1bcac2ae5d7",
7
- "contentLength": 54
8
- },
9
- {
10
- "partPath": "2",
11
- "contentType": "application/pdf",
12
- "contentSha256": "1e82c5ee13ccddf36b4abc368c682a08ed1bc5671101c76062183c8e9914fb41",
13
- "contentLength": 39
14
- }
15
- ]
16
- }
@@ -1,22 +0,0 @@
1
- [
2
- {
3
- "partPath": "0",
4
- "isMultipart": true,
5
- "mediaType": "MULTIPART",
6
- "mediaSubtype": "mixed"
7
- },
8
- {
9
- "partPath": "1",
10
- "isMultipart": false,
11
- "mediaType": "TEXT",
12
- "mediaSubtype": "html"
13
- },
14
- {
15
- "partPath": "2",
16
- "isMultipart": false,
17
- "mediaType": "APPLICATION",
18
- "mediaSubtype": "octet-stream",
19
- "dispositionFilename": "contract.pdf",
20
- "disposition": "attachment"
21
- }
22
- ]
@@ -1,21 +0,0 @@
1
- From: alice@example.org
2
- To: bob@example.org
3
- Subject: Mixed html + octet-stream PDF fixture 05 (Odido bug)
4
- Date: Thu, 28 May 2026 09:00:00 +0000
5
- Message-Id: <fixture-05@example.org>
6
- MIME-Version: 1.0
7
- Content-Type: multipart/mixed; boundary="=_boundary_05_="
8
-
9
- --=_boundary_05_=
10
- Content-Type: text/html; charset=us-ascii
11
- Content-Transfer-Encoding: 7bit
12
-
13
- <html><body><p>Your contract PDF is attached.</p></body></html>
14
- --=_boundary_05_=
15
- Content-Type: application/octet-stream; name="contract.pdf"
16
- Content-Transfer-Encoding: base64
17
- Content-Disposition: attachment; filename="contract.pdf"
18
-
19
- JVBERi0xLjQKJWZha2UgcGRmIGZvciBmaXh0dXJlIDA1IG9jdGV0LXN0cmVhbQol
20
- RU9GCg==
21
- --=_boundary_05_=--
@@ -1,16 +0,0 @@
1
- {
2
- "pairs": [
3
- {
4
- "partPath": "1",
5
- "contentType": "text/html",
6
- "contentSha256": "9fd8608290b5e5c88848e336235fbcf48d4797290c631b9f73bb9f13c7ce3515",
7
- "contentLength": 63
8
- },
9
- {
10
- "partPath": "2",
11
- "contentType": "application/octet-stream",
12
- "contentSha256": "649331fa0bcf7487ba5529a34be1b2629f76e7906548321283d9255ad4ef53eb",
13
- "contentLength": 52
14
- }
15
- ]
16
- }
@@ -1,23 +0,0 @@
1
- [
2
- {
3
- "partPath": "0",
4
- "isMultipart": true,
5
- "mediaType": "MULTIPART",
6
- "mediaSubtype": "related"
7
- },
8
- {
9
- "partPath": "1",
10
- "isMultipart": false,
11
- "mediaType": "TEXT",
12
- "mediaSubtype": "html"
13
- },
14
- {
15
- "partPath": "2",
16
- "isMultipart": false,
17
- "mediaType": "IMAGE",
18
- "mediaSubtype": "png",
19
- "contentId": "logo@example.org",
20
- "dispositionFilename": "logo.png",
21
- "disposition": "inline"
22
- }
23
- ]
@@ -1,21 +0,0 @@
1
- From: alice@example.org
2
- To: bob@example.org
3
- Subject: Related html + cid image fixture 06
4
- Date: Thu, 28 May 2026 09:00:00 +0000
5
- Message-Id: <fixture-06@example.org>
6
- MIME-Version: 1.0
7
- Content-Type: multipart/related; boundary="=_boundary_06_="; type="text/html"
8
-
9
- --=_boundary_06_=
10
- Content-Type: text/html; charset=us-ascii
11
- Content-Transfer-Encoding: 7bit
12
-
13
- <html><body><p>Inline image: <img src="cid:logo@example.org"></p></body></html>
14
- --=_boundary_06_=
15
- Content-Type: image/png; name="logo.png"
16
- Content-Transfer-Encoding: base64
17
- Content-Disposition: inline; filename="logo.png"
18
- Content-ID: <logo@example.org>
19
-
20
- iVBORw0KGgpmaXh0dXJlMDZwbmdieXRlcw==
21
- --=_boundary_06_=--
@@ -1,16 +0,0 @@
1
- {
2
- "pairs": [
3
- {
4
- "partPath": "1",
5
- "contentType": "text/html",
6
- "contentSha256": "212c7f36413be9efaf441c588da97719f947a2210f76c98d05f21ad7480f1c8a",
7
- "contentLength": 117
8
- },
9
- {
10
- "partPath": "2",
11
- "contentType": "image/png",
12
- "contentSha256": "c5a79659b71cb6866a73f688ef63a29e163065f6dbb6aba3da932bc872e475d6",
13
- "contentLength": 25
14
- }
15
- ]
16
- }
@@ -1,55 +0,0 @@
1
- [
2
- {
3
- "partPath": "0",
4
- "isMultipart": true,
5
- "mediaType": "MULTIPART",
6
- "mediaSubtype": "mixed"
7
- },
8
- {
9
- "partPath": "1",
10
- "isMultipart": true,
11
- "mediaType": "MULTIPART",
12
- "mediaSubtype": "alternative"
13
- },
14
- {
15
- "partPath": "1.1",
16
- "isMultipart": false,
17
- "mediaType": "TEXT",
18
- "mediaSubtype": "plain"
19
- },
20
- {
21
- "partPath": "1.2",
22
- "isMultipart": false,
23
- "mediaType": "TEXT",
24
- "mediaSubtype": "html"
25
- },
26
- {
27
- "partPath": "2",
28
- "isMultipart": true,
29
- "mediaType": "MULTIPART",
30
- "mediaSubtype": "related"
31
- },
32
- {
33
- "partPath": "2.1",
34
- "isMultipart": false,
35
- "mediaType": "TEXT",
36
- "mediaSubtype": "html"
37
- },
38
- {
39
- "partPath": "2.2",
40
- "isMultipart": false,
41
- "mediaType": "IMAGE",
42
- "mediaSubtype": "png",
43
- "contentId": "hero@example.org",
44
- "dispositionFilename": "hero.png",
45
- "disposition": "inline"
46
- },
47
- {
48
- "partPath": "3",
49
- "isMultipart": false,
50
- "mediaType": "APPLICATION",
51
- "mediaSubtype": "pdf",
52
- "dispositionFilename": "report.pdf",
53
- "disposition": "attachment"
54
- }
55
- ]
@@ -1,47 +0,0 @@
1
- From: alice@example.org
2
- To: bob@example.org
3
- Subject: Mixed/alternative/related/attachment fixture 07
4
- Date: Thu, 28 May 2026 09:00:00 +0000
5
- Message-Id: <fixture-07@example.org>
6
- MIME-Version: 1.0
7
- Content-Type: multipart/mixed; boundary="=_outer_07_="
8
-
9
- --=_outer_07_=
10
- Content-Type: multipart/alternative; boundary="=_alt_07_="
11
-
12
- --=_alt_07_=
13
- Content-Type: text/plain; charset=us-ascii
14
- Content-Transfer-Encoding: 7bit
15
-
16
- Plain alternative for fixture 07.
17
- --=_alt_07_=
18
- Content-Type: text/html; charset=us-ascii
19
- Content-Transfer-Encoding: 7bit
20
-
21
- <html><body><p>Html alternative for fixture 07.</p></body></html>
22
- --=_alt_07_=--
23
-
24
- --=_outer_07_=
25
- Content-Type: multipart/related; boundary="=_rel_07_="; type="text/html"
26
-
27
- --=_rel_07_=
28
- Content-Type: text/html; charset=us-ascii
29
- Content-Transfer-Encoding: 7bit
30
-
31
- <html><body><p>Related html: <img src="cid:hero@example.org"></p></body></html>
32
- --=_rel_07_=
33
- Content-Type: image/png; name="hero.png"
34
- Content-Transfer-Encoding: base64
35
- Content-Disposition: inline; filename="hero.png"
36
- Content-ID: <hero@example.org>
37
-
38
- iVBORw0KGgpmaXh0dXJlMDdpbm5lcnBuZw==
39
- --=_rel_07_=--
40
-
41
- --=_outer_07_=
42
- Content-Type: application/pdf; name="report.pdf"
43
- Content-Transfer-Encoding: base64
44
- Content-Disposition: attachment; filename="report.pdf"
45
-
46
- JVBERi0xLjQKZml4dHVyZSAwNyBhdHRhY2htZW50CiVFT0YK
47
- --=_outer_07_=--
@@ -1,34 +0,0 @@
1
- {
2
- "pairs": [
3
- {
4
- "partPath": "1.1",
5
- "contentType": "text/plain",
6
- "contentSha256": "73d2f53c47d2e0800ecf20fc755eaa66fe07fe966b5f39b99eaa71457c6f003d",
7
- "contentLength": 70
8
- },
9
- {
10
- "partPath": "1.2",
11
- "contentType": "text/html",
12
- "contentSha256": "1ec6301aa1799989189e5af46096890d8901d5a6cc6c0242b229a1be6dab9598",
13
- "contentLength": 188
14
- },
15
- {
16
- "partPath": "2.1",
17
- "contentType": "text/html",
18
- "contentSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
19
- "contentLength": 0
20
- },
21
- {
22
- "partPath": "2.2",
23
- "contentType": "image/png",
24
- "contentSha256": "2d5748c3ed720a90b433f5840b2dc9f3ca82187f93c71b6f132bb6048a816f06",
25
- "contentLength": 25
26
- },
27
- {
28
- "partPath": "3",
29
- "contentType": "application/pdf",
30
- "contentSha256": "636032d95796536ee2cbbe0db1b5bab0be628fdde66dc5ca9ebfb8c566055f26",
31
- "contentLength": 36
32
- }
33
- ]
34
- }
@@ -1,30 +0,0 @@
1
- [
2
- {
3
- "partPath": "0",
4
- "isMultipart": true,
5
- "mediaType": "MULTIPART",
6
- "mediaSubtype": "mixed"
7
- },
8
- {
9
- "partPath": "1",
10
- "isMultipart": false,
11
- "mediaType": "TEXT",
12
- "mediaSubtype": "plain"
13
- },
14
- {
15
- "partPath": "2",
16
- "isMultipart": false,
17
- "mediaType": "APPLICATION",
18
- "mediaSubtype": "pdf",
19
- "dispositionFilename": "invoice.pdf",
20
- "disposition": "attachment"
21
- },
22
- {
23
- "partPath": "3",
24
- "isMultipart": false,
25
- "mediaType": "APPLICATION",
26
- "mediaSubtype": "pdf",
27
- "dispositionFilename": "invoice.pdf",
28
- "disposition": "attachment"
29
- }
30
- ]
@@ -1,26 +0,0 @@
1
- From: alice@example.org
2
- To: bob@example.org
3
- Subject: Two PDFs same filename fixture 08
4
- Date: Thu, 28 May 2026 09:00:00 +0000
5
- Message-Id: <fixture-08@example.org>
6
- MIME-Version: 1.0
7
- Content-Type: multipart/mixed; boundary="=_boundary_08_="
8
-
9
- --=_boundary_08_=
10
- Content-Type: text/plain; charset=us-ascii
11
- Content-Transfer-Encoding: 7bit
12
-
13
- Two invoices attached, both named invoice.pdf.
14
- --=_boundary_08_=
15
- Content-Type: application/pdf; name="invoice.pdf"
16
- Content-Transfer-Encoding: base64
17
- Content-Disposition: attachment; filename="invoice.pdf"
18
-
19
- JVBERi0xLjQKaW52b2ljZSBBCiVFT0YK
20
- --=_boundary_08_=
21
- Content-Type: application/pdf; name="invoice.pdf"
22
- Content-Transfer-Encoding: base64
23
- Content-Disposition: attachment; filename="invoice.pdf"
24
-
25
- JVBERi0xLjQKaW52b2ljZSBCCiVFT0YK
26
- --=_boundary_08_=--
@@ -1,22 +0,0 @@
1
- {
2
- "pairs": [
3
- {
4
- "partPath": "1",
5
- "contentType": "text/plain",
6
- "contentSha256": "3e69e89d5b45b9e73ee4e9523c80e8e41b6e7f347cce8538844d2b14500549dc",
7
- "contentLength": 46
8
- },
9
- {
10
- "partPath": "2",
11
- "contentType": "application/pdf",
12
- "contentSha256": "0d05c2ebe744a02a1c40e1e56b030f9be4259489924df20bf3f6fbab476f2a1c",
13
- "contentLength": 24
14
- },
15
- {
16
- "partPath": "3",
17
- "contentType": "application/pdf",
18
- "contentSha256": "48ca00b9647ec2babe7d09dbef1ff41f2135a3a03f7e28605eb0c810380b74ab",
19
- "contentLength": 24
20
- }
21
- ]
22
- }
@@ -1,21 +0,0 @@
1
- [
2
- {
3
- "partPath": "0",
4
- "isMultipart": true,
5
- "mediaType": "MULTIPART",
6
- "mediaSubtype": "mixed"
7
- },
8
- {
9
- "partPath": "1",
10
- "isMultipart": false,
11
- "mediaType": "TEXT",
12
- "mediaSubtype": "plain"
13
- },
14
- {
15
- "partPath": "2",
16
- "isMultipart": false,
17
- "mediaType": "APPLICATION",
18
- "mediaSubtype": "octet-stream",
19
- "disposition": "attachment"
20
- }
21
- ]
@@ -1,20 +0,0 @@
1
- From: alice@example.org
2
- To: bob@example.org
3
- Subject: Attachment no filename fixture 09
4
- Date: Thu, 28 May 2026 09:00:00 +0000
5
- Message-Id: <fixture-09@example.org>
6
- MIME-Version: 1.0
7
- Content-Type: multipart/mixed; boundary="=_boundary_09_="
8
-
9
- --=_boundary_09_=
10
- Content-Type: text/plain; charset=us-ascii
11
- Content-Transfer-Encoding: 7bit
12
-
13
- Anonymous blob attached, no Content-Disposition filename.
14
- --=_boundary_09_=
15
- Content-Type: application/octet-stream
16
- Content-Transfer-Encoding: base64
17
- Content-Disposition: attachment
18
-
19
- Zml4dHVyZSAwOSBiaW5hcnkgYmxvYg==
20
- --=_boundary_09_=--
@@ -1,16 +0,0 @@
1
- {
2
- "pairs": [
3
- {
4
- "partPath": "1",
5
- "contentType": "text/plain",
6
- "contentSha256": "3fc90ec4092c7c00da07e9ad8dfc93575db26a51f9193f074d3e41958e144b61",
7
- "contentLength": 57
8
- },
9
- {
10
- "partPath": "2",
11
- "contentType": "application/octet-stream",
12
- "contentSha256": "6b76fec0e7b743629249550cb0b24f37d8772b8c2b05c0c2ed11733e6b4a280a",
13
- "contentLength": 22
14
- }
15
- ]
16
- }
@@ -1,22 +0,0 @@
1
- [
2
- {
3
- "partPath": "0",
4
- "isMultipart": true,
5
- "mediaType": "MULTIPART",
6
- "mediaSubtype": "mixed"
7
- },
8
- {
9
- "partPath": "1",
10
- "isMultipart": false,
11
- "mediaType": "TEXT",
12
- "mediaSubtype": "html"
13
- },
14
- {
15
- "partPath": "2",
16
- "isMultipart": false,
17
- "mediaType": "TEXT",
18
- "mediaSubtype": "calendar",
19
- "dispositionFilename": "invite.ics",
20
- "disposition": "attachment"
21
- }
22
- ]
@@ -1,33 +0,0 @@
1
- From: alice@example.org
2
- To: bob@example.org
3
- Subject: Calendar invite fixture 10
4
- Date: Thu, 28 May 2026 09:00:00 +0000
5
- Message-Id: <fixture-10@example.org>
6
- MIME-Version: 1.0
7
- Content-Type: multipart/mixed; boundary="=_boundary_10_="
8
-
9
- --=_boundary_10_=
10
- Content-Type: text/html; charset=us-ascii
11
- Content-Transfer-Encoding: 7bit
12
-
13
- <html><body><p>Meeting invite attached.</p></body></html>
14
- --=_boundary_10_=
15
- Content-Type: text/calendar; method=REQUEST; charset=us-ascii; name="invite.ics"
16
- Content-Transfer-Encoding: 7bit
17
- Content-Disposition: attachment; filename="invite.ics"
18
-
19
- BEGIN:VCALENDAR
20
- VERSION:2.0
21
- PRODID:-//Remit//Fixture 10//EN
22
- METHOD:REQUEST
23
- BEGIN:VEVENT
24
- UID:fixture-10-event@example.org
25
- DTSTAMP:20260528T090000Z
26
- DTSTART:20260601T140000Z
27
- DTEND:20260601T150000Z
28
- SUMMARY:Fixture 10 sync
29
- ORGANIZER:mailto:alice@example.org
30
- ATTENDEE:mailto:bob@example.org
31
- END:VEVENT
32
- END:VCALENDAR
33
- --=_boundary_10_=--
@@ -1,16 +0,0 @@
1
- {
2
- "pairs": [
3
- {
4
- "partPath": "1",
5
- "contentType": "text/html",
6
- "contentSha256": "c42f526dfc9035c9fa9afa4185c12900f57667d3dbcf02c29393f2745da33c8b",
7
- "contentLength": 57
8
- },
9
- {
10
- "partPath": "2",
11
- "contentType": "text/calendar",
12
- "contentSha256": "73e7b9931e4fc42e7a835219212b822797e9e593af3a4a7143d0cba00c6c19e6",
13
- "contentLength": 309
14
- }
15
- ]
16
- }
@@ -1,8 +0,0 @@
1
- [
2
- {
3
- "partPath": "0",
4
- "isMultipart": false,
5
- "mediaType": "TEXT",
6
- "mediaSubtype": "plain"
7
- }
8
- ]
@@ -1,10 +0,0 @@
1
- From: alice@example.org
2
- To: bob@example.org
3
- Subject: Quoted-printable fixture 11
4
- Date: Thu, 28 May 2026 09:00:00 +0000
5
- Message-Id: <fixture-11@example.org>
6
- MIME-Version: 1.0
7
- Content-Type: text/plain; charset=utf-8
8
- Content-Transfer-Encoding: quoted-printable
9
-
10
- Caf=C3=A9 r=C3=A9union: hello bob! =E2=80=94 alice
@@ -1,10 +0,0 @@
1
- {
2
- "pairs": [
3
- {
4
- "partPath": "0",
5
- "contentType": "text/plain",
6
- "contentSha256": "8dbbfbce0a6fd87eafe2e649176413bae060e65240fc9bb3b90e95e734695553",
7
- "contentLength": 37
8
- }
9
- ]
10
- }
@@ -1,22 +0,0 @@
1
- [
2
- {
3
- "partPath": "0",
4
- "isMultipart": true,
5
- "mediaType": "MULTIPART",
6
- "mediaSubtype": "mixed"
7
- },
8
- {
9
- "partPath": "1",
10
- "isMultipart": false,
11
- "mediaType": "TEXT",
12
- "mediaSubtype": "plain"
13
- },
14
- {
15
- "partPath": "2",
16
- "isMultipart": false,
17
- "mediaType": "IMAGE",
18
- "mediaSubtype": "jpeg",
19
- "dispositionFilename": "photo.jpg",
20
- "disposition": "attachment"
21
- }
22
- ]
@@ -1,20 +0,0 @@
1
- From: alice@example.org
2
- To: bob@example.org
3
- Subject: Base64 binary jpeg fixture 12
4
- Date: Thu, 28 May 2026 09:00:00 +0000
5
- Message-Id: <fixture-12@example.org>
6
- MIME-Version: 1.0
7
- Content-Type: multipart/mixed; boundary="=_boundary_12_="
8
-
9
- --=_boundary_12_=
10
- Content-Type: text/plain; charset=us-ascii
11
- Content-Transfer-Encoding: 7bit
12
-
13
- Photo attached.
14
- --=_boundary_12_=
15
- Content-Type: image/jpeg; name="photo.jpg"
16
- Content-Transfer-Encoding: base64
17
- Content-Disposition: attachment; filename="photo.jpg"
18
-
19
- /9j/4AAQSkZJRmZpeHR1cmUxMg==
20
- --=_boundary_12_=--
@@ -1,16 +0,0 @@
1
- {
2
- "pairs": [
3
- {
4
- "partPath": "1",
5
- "contentType": "text/plain",
6
- "contentSha256": "4ac0cf36cab465e1536842bffdccde687fdf161754077c715280ff5c1038c4a6",
7
- "contentLength": 15
8
- },
9
- {
10
- "partPath": "2",
11
- "contentType": "image/jpeg",
12
- "contentSha256": "2cdd8c64ba22f9a5954d3d82433e72398d74d464cca016a17cde50da60204242",
13
- "contentLength": 19
14
- }
15
- ]
16
- }
@@ -1,22 +0,0 @@
1
- [
2
- {
3
- "partPath": "0",
4
- "isMultipart": true,
5
- "mediaType": "MULTIPART",
6
- "mediaSubtype": "mixed"
7
- },
8
- {
9
- "partPath": "1",
10
- "isMultipart": false,
11
- "mediaType": "TEXT",
12
- "mediaSubtype": "plain"
13
- },
14
- {
15
- "partPath": "2",
16
- "isMultipart": false,
17
- "mediaType": "MESSAGE",
18
- "mediaSubtype": "rfc822",
19
- "dispositionFilename": "forwarded.eml",
20
- "disposition": "attachment"
21
- }
22
- ]
@@ -1,28 +0,0 @@
1
- From: alice@example.org
2
- To: bob@example.org
3
- Subject: Forwarded message fixture 13
4
- Date: Thu, 28 May 2026 09:00:00 +0000
5
- Message-Id: <fixture-13@example.org>
6
- MIME-Version: 1.0
7
- Content-Type: multipart/mixed; boundary="=_boundary_13_="
8
-
9
- --=_boundary_13_=
10
- Content-Type: text/plain; charset=us-ascii
11
- Content-Transfer-Encoding: 7bit
12
-
13
- Forwarding the message below.
14
- --=_boundary_13_=
15
- Content-Type: message/rfc822
16
- Content-Disposition: attachment; filename="forwarded.eml"
17
-
18
- From: carol@example.org
19
- To: alice@example.org
20
- Subject: Original forwarded fixture 13
21
- Date: Wed, 27 May 2026 12:00:00 +0000
22
- Message-Id: <fixture-13-inner@example.org>
23
- MIME-Version: 1.0
24
- Content-Type: text/plain; charset=us-ascii
25
- Content-Transfer-Encoding: 7bit
26
-
27
- Original message body that ends up forwarded.
28
- --=_boundary_13_=--
@@ -1,16 +0,0 @@
1
- {
2
- "pairs": [
3
- {
4
- "partPath": "1",
5
- "contentType": "text/plain",
6
- "contentSha256": "2f45158866c85f8fccc88d7d2f96cf29efb6bfa86091a46a3db2f346202ce1a7",
7
- "contentLength": 29
8
- },
9
- {
10
- "partPath": "2",
11
- "contentType": "message/rfc822",
12
- "contentSha256": "73adfff6626c2ce287ce6b21e9860e3ad0a18ca068d36759674931bcc7a3d2a6",
13
- "contentLength": 305
14
- }
15
- ]
16
- }
@@ -1,38 +0,0 @@
1
- [
2
- {
3
- "partPath": "0",
4
- "isMultipart": true,
5
- "mediaType": "MULTIPART",
6
- "mediaSubtype": "mixed"
7
- },
8
- {
9
- "partPath": "1",
10
- "isMultipart": true,
11
- "mediaType": "MULTIPART",
12
- "mediaSubtype": "mixed"
13
- },
14
- {
15
- "partPath": "1.1",
16
- "isMultipart": true,
17
- "mediaType": "MULTIPART",
18
- "mediaSubtype": "mixed"
19
- },
20
- {
21
- "partPath": "1.1.1",
22
- "isMultipart": true,
23
- "mediaType": "MULTIPART",
24
- "mediaSubtype": "mixed"
25
- },
26
- {
27
- "partPath": "1.1.1.1",
28
- "isMultipart": true,
29
- "mediaType": "MULTIPART",
30
- "mediaSubtype": "mixed"
31
- },
32
- {
33
- "partPath": "1.1.1.1.1",
34
- "isMultipart": false,
35
- "mediaType": "TEXT",
36
- "mediaSubtype": "plain"
37
- }
38
- ]
@@ -1,34 +0,0 @@
1
- From: alice@example.org
2
- To: bob@example.org
3
- Subject: Deeply nested 5 levels fixture 14
4
- Date: Thu, 28 May 2026 09:00:00 +0000
5
- Message-Id: <fixture-14@example.org>
6
- MIME-Version: 1.0
7
- Content-Type: multipart/mixed; boundary="=_lvl1_14_="
8
-
9
- --=_lvl1_14_=
10
- Content-Type: multipart/mixed; boundary="=_lvl2_14_="
11
-
12
- --=_lvl2_14_=
13
- Content-Type: multipart/mixed; boundary="=_lvl3_14_="
14
-
15
- --=_lvl3_14_=
16
- Content-Type: multipart/mixed; boundary="=_lvl4_14_="
17
-
18
- --=_lvl4_14_=
19
- Content-Type: multipart/mixed; boundary="=_lvl5_14_="
20
-
21
- --=_lvl5_14_=
22
- Content-Type: text/plain; charset=us-ascii
23
- Content-Transfer-Encoding: 7bit
24
-
25
- Bottom of the five-level nest.
26
- --=_lvl5_14_=--
27
-
28
- --=_lvl4_14_=--
29
-
30
- --=_lvl3_14_=--
31
-
32
- --=_lvl2_14_=--
33
-
34
- --=_lvl1_14_=--
@@ -1,10 +0,0 @@
1
- {
2
- "pairs": [
3
- {
4
- "partPath": "1.1.1.1.1",
5
- "contentType": "text/plain",
6
- "contentSha256": "4b6a9602966807e33af23de0d6f227ea17c802c4883ca54c8479a59af5bb1d6a",
7
- "contentLength": 30
8
- }
9
- ]
10
- }
@@ -1,21 +0,0 @@
1
- [
2
- {
3
- "partPath": "0",
4
- "isMultipart": true,
5
- "mediaType": "MULTIPART",
6
- "mediaSubtype": "mixed"
7
- },
8
- {
9
- "partPath": "1",
10
- "isMultipart": false,
11
- "mediaType": "TEXT",
12
- "mediaSubtype": "plain",
13
- "sizeOctets": 0
14
- },
15
- {
16
- "partPath": "2",
17
- "isMultipart": false,
18
- "mediaType": "TEXT",
19
- "mediaSubtype": "html"
20
- }
21
- ]
@@ -1,18 +0,0 @@
1
- From: alice@example.org
2
- To: bob@example.org
3
- Subject: Empty text part fixture 15
4
- Date: Thu, 28 May 2026 09:00:00 +0000
5
- Message-Id: <fixture-15@example.org>
6
- MIME-Version: 1.0
7
- Content-Type: multipart/mixed; boundary="=_boundary_15_="
8
-
9
- --=_boundary_15_=
10
- Content-Type: text/plain; charset=us-ascii
11
- Content-Transfer-Encoding: 7bit
12
-
13
- --=_boundary_15_=
14
- Content-Type: text/html; charset=us-ascii
15
- Content-Transfer-Encoding: 7bit
16
-
17
- <html><body><p>HTML part with non-empty content; text/plain sibling is empty.</p></body></html>
18
- --=_boundary_15_=--
@@ -1,16 +0,0 @@
1
- {
2
- "pairs": [
3
- {
4
- "partPath": "1",
5
- "contentType": "text/plain",
6
- "contentSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
7
- "contentLength": 0
8
- },
9
- {
10
- "partPath": "2",
11
- "contentType": "text/html",
12
- "contentSha256": "7bdf108bcc691f01bec50cf4d094ed4e5d0fa0b2a542aeecc4e3018759ddb557",
13
- "contentLength": 95
14
- }
15
- ]
16
- }
@@ -1,30 +0,0 @@
1
- [
2
- {
3
- "partPath": "0",
4
- "isMultipart": true,
5
- "mediaType": "MULTIPART",
6
- "mediaSubtype": "mixed"
7
- },
8
- {
9
- "partPath": "1",
10
- "isMultipart": false,
11
- "mediaType": "TEXT",
12
- "mediaSubtype": "html"
13
- },
14
- {
15
- "partPath": "2",
16
- "isMultipart": false,
17
- "mediaType": "APPLICATION",
18
- "mediaSubtype": "octet-stream",
19
- "sizeOctets": 0
20
- },
21
- {
22
- "partPath": "3",
23
- "isMultipart": false,
24
- "mediaType": "APPLICATION",
25
- "mediaSubtype": "pdf",
26
- "disposition": "attachment",
27
- "dispositionFilename": "real.pdf",
28
- "sizeOctets": 9
29
- }
30
- ]
@@ -1,24 +0,0 @@
1
- From: alice@example.org
2
- To: bob@example.org
3
- Subject: Empty non-text part fixture 16
4
- Date: Thu, 29 May 2026 09:00:00 +0000
5
- Message-Id: <fixture-16@example.org>
6
- MIME-Version: 1.0
7
- Content-Type: multipart/mixed; boundary="=_boundary_16_="
8
-
9
- --=_boundary_16_=
10
- Content-Type: text/html; charset=us-ascii
11
- Content-Transfer-Encoding: 7bit
12
-
13
- <html><body><p>HTML body alongside an empty octet-stream part and one real PDF.</p></body></html>
14
- --=_boundary_16_=
15
- Content-Type: application/octet-stream
16
- Content-Transfer-Encoding: 7bit
17
-
18
- --=_boundary_16_=
19
- Content-Type: application/pdf; name=real.pdf
20
- Content-Transfer-Encoding: base64
21
- Content-Disposition: attachment; filename=real.pdf
22
-
23
- JVBERi0xLjQK
24
- --=_boundary_16_=--
@@ -1,22 +0,0 @@
1
- {
2
- "pairs": [
3
- {
4
- "partPath": "1",
5
- "contentType": "text/html",
6
- "contentSha256": "d7608876ac9c289794b8690e2979fba30e6451c7b5dd7337b34d4f4d577e3185",
7
- "contentLength": 97
8
- },
9
- {
10
- "partPath": "2",
11
- "contentType": "application/octet-stream",
12
- "contentSha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
13
- "contentLength": 0
14
- },
15
- {
16
- "partPath": "3",
17
- "contentType": "application/pdf",
18
- "contentSha256": "e5c62df5dab5c87b6a015ef3d43597074d1eec433b15f51aec63b8582d0e4ab4",
19
- "contentLength": 9
20
- }
21
- ]
22
- }