@remit/mailbox-service 0.0.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/README.md +147 -0
- package/package.json +65 -0
- package/src/account-credentials.ts +128 -0
- package/src/adversarial-mime.e2e.test.ts +311 -0
- package/src/attribute-mapper.test.ts +78 -0
- package/src/attribute-mapper.ts +147 -0
- package/src/body-part-mapper.property.test.ts +354 -0
- package/src/body-part-mapper.ts +360 -0
- package/src/body-sync-queue.test.ts +124 -0
- package/src/body-sync-queue.ts +131 -0
- package/src/body-sync-terminal.test.ts +265 -0
- package/src/body-sync-terminal.ts +172 -0
- package/src/body-sync.ts +1202 -0
- package/src/connection-factory.ts +102 -0
- package/src/connection-test.ts +208 -0
- package/src/credentials.test.ts +181 -0
- package/src/filters/match.test.ts +181 -0
- package/src/filters/match.ts +143 -0
- package/src/filters/pipeline.ts +243 -0
- package/src/flag-push-terminal.test.ts +156 -0
- package/src/flag-push-terminal.ts +106 -0
- package/src/flag-push.test.ts +408 -0
- package/src/flag-push.ts +198 -0
- package/src/flag-queue.ts +500 -0
- package/src/heuristics/classifyByHeaders.test.ts +578 -0
- package/src/heuristics/classifyByHeaders.ts +369 -0
- package/src/heuristics/classifyPlacement.ts +96 -0
- package/src/heuristics/socialDomains.ts +23 -0
- package/src/heuristics/transactionalDomains.ts +26 -0
- package/src/imapflow-connect-retry.test.ts +108 -0
- package/src/imapflow-connection.e2e.test.ts +355 -0
- package/src/imapflow-connection.integ.test.ts +327 -0
- package/src/imapflow-connection.test.ts +161 -0
- package/src/imapflow-connection.ts +1374 -0
- package/src/index.ts +214 -0
- package/src/mailbox-cursor-rebuild.test.ts +171 -0
- package/src/mailbox-cursor-rebuild.ts +146 -0
- package/src/mailbox-cursor.test.ts +249 -0
- package/src/mailbox-cursor.ts +177 -0
- package/src/mailbox-management.test.ts +103 -0
- package/src/mailbox-management.ts +235 -0
- package/src/mailbox-queue.ts +258 -0
- package/src/mailbox-sync.test.ts +153 -0
- package/src/mailbox-sync.ts +590 -0
- package/src/message-move.ts +825 -0
- package/src/message-parser.ts +26 -0
- package/src/message-sync.ts +1021 -0
- package/src/mime-walker.test.ts +311 -0
- package/src/mime-walker.ts +305 -0
- package/src/outbox-queue.ts +294 -0
- package/src/pass-through-unit-of-work.ts +17 -0
- package/src/placement-move-terminal.test.ts +179 -0
- package/src/placement-move-terminal.ts +104 -0
- package/src/placement-move.ts +224 -0
- package/src/snippet.test.ts +213 -0
- package/src/snippet.ts +152 -0
- package/src/stale-message-reconcile.test.ts +82 -0
- package/src/stale-message-reconcile.ts +55 -0
- package/src/test-helpers/isolated-mailbox.ts +44 -0
- package/src/test-helpers/mailfuzz-connection.ts +27 -0
- package/src/test-helpers/mime-tree-generator.ts +461 -0
- package/src/text/normalizer.test.ts +223 -0
- package/src/text/normalizer.ts +140 -0
- package/src/types/mailparser-augment.d.ts +15 -0
- package/src/types/natural-porter-stemmer.d.ts +50 -0
- package/src/types/stopword.d.ts +69 -0
- package/src/types.ts +349 -0
- package/test/fixtures/mime/01-flat-text-plain.bodyparts.json +8 -0
- package/test/fixtures/mime/01-flat-text-plain.eml +10 -0
- package/test/fixtures/mime/01-flat-text-plain.expected.json +10 -0
- package/test/fixtures/mime/02-flat-text-html.bodyparts.json +8 -0
- package/test/fixtures/mime/02-flat-text-html.eml +10 -0
- package/test/fixtures/mime/02-flat-text-html.expected.json +10 -0
- package/test/fixtures/mime/03-alternative-text-html.bodyparts.json +20 -0
- package/test/fixtures/mime/03-alternative-text-html.eml +19 -0
- package/test/fixtures/mime/03-alternative-text-html.expected.json +16 -0
- package/test/fixtures/mime/04-mixed-html-pdf-attachment.bodyparts.json +22 -0
- package/test/fixtures/mime/04-mixed-html-pdf-attachment.eml +20 -0
- package/test/fixtures/mime/04-mixed-html-pdf-attachment.expected.json +16 -0
- package/test/fixtures/mime/05-mixed-html-octet-stream-pdf.bodyparts.json +22 -0
- package/test/fixtures/mime/05-mixed-html-octet-stream-pdf.eml +21 -0
- package/test/fixtures/mime/05-mixed-html-octet-stream-pdf.expected.json +16 -0
- package/test/fixtures/mime/06-related-html-cid-image.bodyparts.json +23 -0
- package/test/fixtures/mime/06-related-html-cid-image.eml +21 -0
- package/test/fixtures/mime/06-related-html-cid-image.expected.json +16 -0
- package/test/fixtures/mime/07-mixed-alternative-related-attachment.bodyparts.json +55 -0
- package/test/fixtures/mime/07-mixed-alternative-related-attachment.eml +47 -0
- package/test/fixtures/mime/07-mixed-alternative-related-attachment.expected.json +34 -0
- package/test/fixtures/mime/08-two-pdfs-same-filename.bodyparts.json +30 -0
- package/test/fixtures/mime/08-two-pdfs-same-filename.eml +26 -0
- package/test/fixtures/mime/08-two-pdfs-same-filename.expected.json +22 -0
- package/test/fixtures/mime/09-attachment-no-filename.bodyparts.json +21 -0
- package/test/fixtures/mime/09-attachment-no-filename.eml +20 -0
- package/test/fixtures/mime/09-attachment-no-filename.expected.json +16 -0
- package/test/fixtures/mime/10-calendar-invite.bodyparts.json +22 -0
- package/test/fixtures/mime/10-calendar-invite.eml +33 -0
- package/test/fixtures/mime/10-calendar-invite.expected.json +16 -0
- package/test/fixtures/mime/11-quoted-printable-text.bodyparts.json +8 -0
- package/test/fixtures/mime/11-quoted-printable-text.eml +10 -0
- package/test/fixtures/mime/11-quoted-printable-text.expected.json +10 -0
- package/test/fixtures/mime/12-base64-binary.bodyparts.json +22 -0
- package/test/fixtures/mime/12-base64-binary.eml +20 -0
- package/test/fixtures/mime/12-base64-binary.expected.json +16 -0
- package/test/fixtures/mime/13-message-rfc822-forward.bodyparts.json +22 -0
- package/test/fixtures/mime/13-message-rfc822-forward.eml +28 -0
- package/test/fixtures/mime/13-message-rfc822-forward.expected.json +16 -0
- package/test/fixtures/mime/14-deeply-nested-5-levels.bodyparts.json +38 -0
- package/test/fixtures/mime/14-deeply-nested-5-levels.eml +34 -0
- package/test/fixtures/mime/14-deeply-nested-5-levels.expected.json +10 -0
- package/test/fixtures/mime/15-empty-text-part.bodyparts.json +21 -0
- package/test/fixtures/mime/15-empty-text-part.eml +18 -0
- package/test/fixtures/mime/15-empty-text-part.expected.json +16 -0
- package/test/fixtures/mime/16-empty-non-text-part.bodyparts.json +30 -0
- package/test/fixtures/mime/16-empty-non-text-part.eml +24 -0
- package/test/fixtures/mime/16-empty-non-text-part.expected.json +22 -0
- package/test/fixtures/mime-adversarial-e2e/01-octet-stream-pdf.eml +21 -0
- package/test/fixtures/mime-adversarial-e2e/02-nested-related-cid-image.eml +31 -0
- package/test/fixtures/mime-adversarial-e2e/03-calendar-invite.eml +33 -0
- package/test/fixtures/mime-adversarial-e2e/04-forwarded-rfc822-with-attachments.eml +42 -0
- package/test/fixtures/mime-adversarial-e2e/05-tnef-winmail.eml +25 -0
- package/test/fixtures/mime-adversarial-e2e/06-8bit-non-ascii.eml +15 -0
- package/test/fixtures/mime-adversarial-e2e/07-quoted-printable-soft-breaks.eml +17 -0
- package/test/fixtures/mime-adversarial-e2e/08-alternative-empty-text.eml +18 -0
- package/tsconfig.json +8 -0
|
@@ -0,0 +1,30 @@
|
|
|
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
|
+
]
|
|
@@ -0,0 +1,24 @@
|
|
|
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_=--
|
|
@@ -0,0 +1,22 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
From: alice@example.com
|
|
2
|
+
To: bob@example.com
|
|
3
|
+
Subject: Adversarial fixture 01 octet-stream PDF (Odido shape, #394)
|
|
4
|
+
Date: Fri, 29 May 2026 09:00:00 +0000
|
|
5
|
+
Message-Id: <adv-01-octet-stream-pdf@example.com>
|
|
6
|
+
MIME-Version: 1.0
|
|
7
|
+
Content-Type: multipart/mixed; boundary="=_adv01_="
|
|
8
|
+
|
|
9
|
+
--=_adv01_=
|
|
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
|
+
--=_adv01_=
|
|
15
|
+
Content-Type: application/octet-stream; name="contract.pdf"
|
|
16
|
+
Content-Transfer-Encoding: base64
|
|
17
|
+
Content-Disposition: attachment; filename="contract.pdf"
|
|
18
|
+
|
|
19
|
+
JVBERi0xLjQKJWZha2UgcGRmIGZvciBhZHZlcnNhcmlhbCBmaXh0dXJlIDAxIG9j
|
|
20
|
+
dGV0LXN0cmVhbQolRU9GCg==
|
|
21
|
+
--=_adv01_=--
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
From: alice@example.com
|
|
2
|
+
To: bob@example.com
|
|
3
|
+
Subject: Adversarial fixture 02 nested related html + cid image
|
|
4
|
+
Date: Fri, 29 May 2026 09:00:00 +0000
|
|
5
|
+
Message-Id: <adv-02-nested-related@example.com>
|
|
6
|
+
MIME-Version: 1.0
|
|
7
|
+
Content-Type: multipart/mixed; boundary="=_adv02_outer_="
|
|
8
|
+
|
|
9
|
+
--=_adv02_outer_=
|
|
10
|
+
Content-Type: multipart/related; boundary="=_adv02_inner_="; type="text/html"
|
|
11
|
+
|
|
12
|
+
--=_adv02_inner_=
|
|
13
|
+
Content-Type: text/html; charset=us-ascii
|
|
14
|
+
Content-Transfer-Encoding: 7bit
|
|
15
|
+
|
|
16
|
+
<html><body><p>Hi bob,</p><p>Inline logo: <img src="cid:logo@example.com" alt="logo"></p><p>-- alice</p></body></html>
|
|
17
|
+
--=_adv02_inner_=
|
|
18
|
+
Content-Type: image/png; name="logo.png"
|
|
19
|
+
Content-Transfer-Encoding: base64
|
|
20
|
+
Content-Disposition: inline; filename="logo.png"
|
|
21
|
+
Content-ID: <logo@example.com>
|
|
22
|
+
|
|
23
|
+
iVBORw0KGgpmaXh0dXJlMDJjaWRpbWFnZWJ5dGVz
|
|
24
|
+
--=_adv02_inner_=--
|
|
25
|
+
--=_adv02_outer_=
|
|
26
|
+
Content-Type: application/pdf; name="invoice.pdf"
|
|
27
|
+
Content-Transfer-Encoding: base64
|
|
28
|
+
Content-Disposition: attachment; filename="invoice.pdf"
|
|
29
|
+
|
|
30
|
+
JVBERi0xLjQKJWFkdiAwMiBmaXh0dXJlIGludm9pY2UKJUVPRgo=
|
|
31
|
+
--=_adv02_outer_=--
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
From: alice@example.com
|
|
2
|
+
To: bob@example.com
|
|
3
|
+
Subject: Adversarial fixture 03 calendar invite + html
|
|
4
|
+
Date: Fri, 29 May 2026 09:00:00 +0000
|
|
5
|
+
Message-Id: <adv-03-calendar@example.com>
|
|
6
|
+
MIME-Version: 1.0
|
|
7
|
+
Content-Type: multipart/mixed; boundary="=_adv03_="
|
|
8
|
+
|
|
9
|
+
--=_adv03_=
|
|
10
|
+
Content-Type: text/html; charset=us-ascii
|
|
11
|
+
Content-Transfer-Encoding: 7bit
|
|
12
|
+
|
|
13
|
+
<html><body><p>Hi bob,</p><p>Meeting invite for our sync on Monday is attached.</p><p>-- alice</p></body></html>
|
|
14
|
+
--=_adv03_=
|
|
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//Adversarial Fixture 03//EN
|
|
22
|
+
METHOD:REQUEST
|
|
23
|
+
BEGIN:VEVENT
|
|
24
|
+
UID:adv-03-event@example.com
|
|
25
|
+
DTSTAMP:20260529T090000Z
|
|
26
|
+
DTSTART:20260601T140000Z
|
|
27
|
+
DTEND:20260601T150000Z
|
|
28
|
+
SUMMARY:Adversarial fixture 03 sync
|
|
29
|
+
ORGANIZER:mailto:alice@example.com
|
|
30
|
+
ATTENDEE:mailto:bob@example.com
|
|
31
|
+
END:VEVENT
|
|
32
|
+
END:VCALENDAR
|
|
33
|
+
--=_adv03_=--
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
From: alice@example.com
|
|
2
|
+
To: bob@example.com
|
|
3
|
+
Subject: Adversarial fixture 04 forwarded rfc822 with inner attachment
|
|
4
|
+
Date: Fri, 29 May 2026 09:00:00 +0000
|
|
5
|
+
Message-Id: <adv-04-forwarded@example.com>
|
|
6
|
+
MIME-Version: 1.0
|
|
7
|
+
Content-Type: multipart/mixed; boundary="=_adv04_outer_="
|
|
8
|
+
|
|
9
|
+
--=_adv04_outer_=
|
|
10
|
+
Content-Type: text/plain; charset=us-ascii
|
|
11
|
+
Content-Transfer-Encoding: 7bit
|
|
12
|
+
|
|
13
|
+
Hi bob,
|
|
14
|
+
|
|
15
|
+
Forwarding the message below for your records. Note the original carries its own attachment.
|
|
16
|
+
|
|
17
|
+
-- alice
|
|
18
|
+
--=_adv04_outer_=
|
|
19
|
+
Content-Type: message/rfc822
|
|
20
|
+
Content-Disposition: attachment; filename="forwarded.eml"
|
|
21
|
+
|
|
22
|
+
From: carol@example.com
|
|
23
|
+
To: alice@example.com
|
|
24
|
+
Subject: Original message with attachment for fixture 04
|
|
25
|
+
Date: Thu, 28 May 2026 12:00:00 +0000
|
|
26
|
+
Message-Id: <adv-04-inner@example.com>
|
|
27
|
+
MIME-Version: 1.0
|
|
28
|
+
Content-Type: multipart/mixed; boundary="=_adv04_inner_="
|
|
29
|
+
|
|
30
|
+
--=_adv04_inner_=
|
|
31
|
+
Content-Type: text/plain; charset=us-ascii
|
|
32
|
+
Content-Transfer-Encoding: 7bit
|
|
33
|
+
|
|
34
|
+
Original message body before forwarding.
|
|
35
|
+
--=_adv04_inner_=
|
|
36
|
+
Content-Type: application/pdf; name="original.pdf"
|
|
37
|
+
Content-Transfer-Encoding: base64
|
|
38
|
+
Content-Disposition: attachment; filename="original.pdf"
|
|
39
|
+
|
|
40
|
+
JVBERi0xLjQKJWFkdiAwNCBpbm5lciBwZGYKJUVPRgo=
|
|
41
|
+
--=_adv04_inner_=--
|
|
42
|
+
--=_adv04_outer_=--
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
X-Remit-Fixture-Note: Synthetic TNEF stub for fixture 05. mailparser surfaces this as an application/ms-tnef attachment with filename "winmail.dat" — which is the #402 contract. The trailing BODYSTRUCTURE round-trip via imapflow is skipped for this shape (see EXPECTATIONS in adversarial-mime.e2e.test.ts). TODO(#402): replace with a real-world winmail.dat capture once we have one to ship.
|
|
2
|
+
From: alice@example.com
|
|
3
|
+
To: bob@example.com
|
|
4
|
+
Subject: Adversarial fixture 05 Outlook TNEF winmail.dat
|
|
5
|
+
Date: Fri, 29 May 2026 09:00:00 +0000
|
|
6
|
+
Message-Id: <adv-05-tnef@example.com>
|
|
7
|
+
MIME-Version: 1.0
|
|
8
|
+
Content-Type: multipart/mixed; boundary="=_adv05_="
|
|
9
|
+
|
|
10
|
+
--=_adv05_=
|
|
11
|
+
Content-Type: text/plain; charset=us-ascii
|
|
12
|
+
Content-Transfer-Encoding: 7bit
|
|
13
|
+
|
|
14
|
+
Hi bob,
|
|
15
|
+
|
|
16
|
+
This message carries the Microsoft TNEF (winmail.dat) shape that some Outlook senders still produce. Remit should list the attachment without crashing the body sync.
|
|
17
|
+
|
|
18
|
+
-- alice
|
|
19
|
+
--=_adv05_=
|
|
20
|
+
Content-Type: application/ms-tnef; name="winmail.dat"
|
|
21
|
+
Content-Transfer-Encoding: base64
|
|
22
|
+
Content-Disposition: attachment; filename="winmail.dat"
|
|
23
|
+
|
|
24
|
+
eJ8+IgEAAAABAAAACAAAAAAAAAA=
|
|
25
|
+
--=_adv05_=--
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
From: alice@example.com
|
|
2
|
+
To: bob@example.com
|
|
3
|
+
Subject: =?UTF-8?B?Q2Fmw6kgZmHDp2FkZSAtIGFkdmVyc2FyaWFsIGZpeHR1cmUgMDY=?=
|
|
4
|
+
Date: Fri, 29 May 2026 09:00:00 +0000
|
|
5
|
+
Message-Id: <adv-06-8bit@example.com>
|
|
6
|
+
MIME-Version: 1.0
|
|
7
|
+
Content-Type: text/plain; charset=utf-8
|
|
8
|
+
Content-Transfer-Encoding: 8bit
|
|
9
|
+
|
|
10
|
+
Hallo bob,
|
|
11
|
+
|
|
12
|
+
De café op de hoek heeft een prachtige façade. We’ll meet there — ben je vrij?
|
|
13
|
+
|
|
14
|
+
Groetjes,
|
|
15
|
+
alice
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
From: alice@example.com
|
|
2
|
+
To: bob@example.com
|
|
3
|
+
Subject: Adversarial fixture 07 quoted-printable with soft line breaks
|
|
4
|
+
Date: Fri, 29 May 2026 09:00:00 +0000
|
|
5
|
+
Message-Id: <adv-07-qp@example.com>
|
|
6
|
+
MIME-Version: 1.0
|
|
7
|
+
Content-Type: text/plain; charset=utf-8
|
|
8
|
+
Content-Transfer-Encoding: quoted-printable
|
|
9
|
+
|
|
10
|
+
Hi bob,
|
|
11
|
+
|
|
12
|
+
This paragraph deliberately uses quoted-printable soft line breaks so a sing=
|
|
13
|
+
le logical line is wrapped across multiple physical lines without inserting=
|
|
14
|
+
a real newline. The body-sync pipeline must reassemble it back into one l=
|
|
15
|
+
ogical line when rendering.
|
|
16
|
+
|
|
17
|
+
Also includes a non-ASCII token: caf=C3=A9 r=C3=A9union =E2=80=94 alice
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
From: alice@example.com
|
|
2
|
+
To: bob@example.com
|
|
3
|
+
Subject: Adversarial fixture 08 alternative with empty text/plain
|
|
4
|
+
Date: Fri, 29 May 2026 09:00:00 +0000
|
|
5
|
+
Message-Id: <adv-08-empty-text-alt@example.com>
|
|
6
|
+
MIME-Version: 1.0
|
|
7
|
+
Content-Type: multipart/alternative; boundary="=_adv08_="
|
|
8
|
+
|
|
9
|
+
--=_adv08_=
|
|
10
|
+
Content-Type: text/plain; charset=us-ascii
|
|
11
|
+
Content-Transfer-Encoding: 7bit
|
|
12
|
+
|
|
13
|
+
--=_adv08_=
|
|
14
|
+
Content-Type: text/html; charset=us-ascii
|
|
15
|
+
Content-Transfer-Encoding: 7bit
|
|
16
|
+
|
|
17
|
+
<html><body><p>Hi bob,</p><p>The text/plain sibling of this multipart/alternative is intentionally empty. The HTML part must still render.</p><p>-- alice</p></body></html>
|
|
18
|
+
--=_adv08_=--
|