@remit/mailbox-service 0.0.111 → 0.0.113
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/dist/account-credentials.d.ts +83 -0
- package/dist/account-credentials.js +104 -0
- package/dist/attribute-mapper.d.ts +36 -0
- package/dist/attribute-mapper.js +119 -0
- package/dist/body-parse.d.ts +28 -0
- package/{src/body-parse.ts → dist/body-parse.js} +18 -26
- package/dist/body-part-mapper.d.ts +92 -0
- package/dist/body-part-mapper.js +301 -0
- package/dist/body-sync-queue.d.ts +59 -0
- package/dist/body-sync-queue.js +56 -0
- package/dist/body-sync-terminal.d.ts +58 -0
- package/dist/body-sync-terminal.js +95 -0
- package/dist/body-sync.d.ts +351 -0
- package/dist/body-sync.js +1204 -0
- package/dist/calendar-parts.d.ts +23 -0
- package/dist/calendar-parts.js +18 -0
- package/dist/classification-backfill.d.ts +91 -0
- package/dist/classification-backfill.js +180 -0
- package/dist/classify-message.d.ts +31 -0
- package/dist/classify-message.js +89 -0
- package/dist/connection-factory.d.ts +54 -0
- package/dist/connection-factory.js +54 -0
- package/dist/connection-test.d.ts +41 -0
- package/dist/connection-test.js +152 -0
- package/dist/external-move.d.ts +94 -0
- package/dist/external-move.js +173 -0
- package/dist/filter-operations.d.ts +42 -0
- package/dist/filter-operations.js +211 -0
- package/dist/filters/filter-config.d.ts +14 -0
- package/dist/filters/filter-config.js +10 -0
- package/{src/filters/list-id.ts → dist/filters/list-id.d.ts} +2 -16
- package/dist/filters/list-id.js +26 -0
- package/dist/filters/match.d.ts +69 -0
- package/dist/filters/match.js +165 -0
- package/dist/filters/pipeline.d.ts +64 -0
- package/dist/filters/pipeline.js +100 -0
- package/{src/flag-push-terminal.ts → dist/flag-push-terminal.d.ts} +19 -77
- package/dist/flag-push-terminal.js +63 -0
- package/dist/flag-push.d.ts +69 -0
- package/dist/flag-push.js +111 -0
- package/dist/flag-queue.d.ts +175 -0
- package/dist/flag-queue.js +291 -0
- package/dist/folder-operations.d.ts +39 -0
- package/dist/folder-operations.js +112 -0
- package/dist/folder-placement.d.ts +13 -0
- package/dist/folder-placement.js +23 -0
- package/dist/heuristics/authenticationResults.d.ts +10 -0
- package/dist/heuristics/authenticationResults.js +187 -0
- package/dist/heuristics/classifyByHeaders.d.ts +82 -0
- package/dist/heuristics/classifyByHeaders.js +365 -0
- package/dist/heuristics/classifyPlacement.d.ts +67 -0
- package/dist/heuristics/classifyPlacement.js +153 -0
- package/dist/heuristics/machineSenders.d.ts +21 -0
- package/{src/heuristics/machineSenders.ts → dist/heuristics/machineSenders.js} +34 -40
- package/dist/heuristics/senderMismatch.d.ts +81 -0
- package/dist/heuristics/senderMismatch.js +192 -0
- package/dist/heuristics/socialDomains.d.ts +14 -0
- package/{src/heuristics/socialDomains.ts → dist/heuristics/socialDomains.js} +9 -9
- package/dist/heuristics/transactionalDomains.d.ts +18 -0
- package/{src/heuristics/transactionalDomains.ts → dist/heuristics/transactionalDomains.js} +8 -8
- package/dist/imapflow-connection.d.ts +377 -0
- package/dist/imapflow-connection.js +1147 -0
- package/dist/index.d.ts +63 -0
- package/dist/index.js +65 -0
- package/dist/list-id-backfill.d.ts +83 -0
- package/dist/list-id-backfill.js +132 -0
- package/dist/mailbox-cursor-rebuild.d.ts +74 -0
- package/dist/mailbox-cursor-rebuild.js +71 -0
- package/{src/mailbox-cursor.ts → dist/mailbox-cursor.d.ts} +20 -98
- package/dist/mailbox-cursor.js +102 -0
- package/dist/mailbox-intent.d.ts +41 -0
- package/{src/mailbox-intent.ts → dist/mailbox-intent.js} +39 -63
- package/dist/mailbox-management.d.ts +240 -0
- package/dist/mailbox-management.js +576 -0
- package/dist/mailbox-presence.d.ts +52 -0
- package/{src/mailbox-presence.ts → dist/mailbox-presence.js} +19 -30
- package/dist/mailbox-queue.d.ts +126 -0
- package/dist/mailbox-queue.js +214 -0
- package/dist/mailbox-sync.d.ts +93 -0
- package/dist/mailbox-sync.js +490 -0
- package/dist/mailbox-upstream.d.ts +38 -0
- package/{src/mailbox-upstream.ts → dist/mailbox-upstream.js} +37 -47
- package/dist/message-category.d.ts +51 -0
- package/{src/message-category.ts → dist/message-category.js} +28 -71
- package/dist/message-move.d.ts +285 -0
- package/dist/message-move.js +858 -0
- package/dist/message-parser.d.ts +14 -0
- package/dist/message-parser.js +17 -0
- package/{src/message-presence.ts → dist/message-presence.d.ts} +1 -13
- package/dist/message-presence.js +29 -0
- package/dist/message-read.d.ts +51 -0
- package/dist/message-read.js +31 -0
- package/dist/message-sync.d.ts +345 -0
- package/dist/message-sync.js +1358 -0
- package/dist/mime-walker.d.ts +102 -0
- package/dist/mime-walker.js +198 -0
- package/dist/organize-job.d.ts +20 -0
- package/dist/organize-job.js +37 -0
- package/dist/outbox-attachment-content.d.ts +37 -0
- package/dist/outbox-attachment-content.js +50 -0
- package/dist/outbox-attachment-filename.d.ts +19 -0
- package/dist/outbox-attachment-filename.js +64 -0
- package/dist/outbox-attachment.d.ts +148 -0
- package/dist/outbox-attachment.js +273 -0
- package/dist/outbox-queue.d.ts +73 -0
- package/dist/outbox-queue.js +284 -0
- package/{src/outbox-status.ts → dist/outbox-status.d.ts} +1 -6
- package/dist/outbox-status.js +18 -0
- package/dist/ownership.d.ts +24 -0
- package/dist/ownership.js +83 -0
- package/dist/placement-move-terminal.d.ts +67 -0
- package/dist/placement-move-terminal.js +88 -0
- package/dist/placement-move.d.ts +83 -0
- package/dist/placement-move.js +216 -0
- package/{src/placement-settled.ts → dist/placement-settled.d.ts} +19 -50
- package/dist/placement-settled.js +75 -0
- package/dist/quarantine.d.ts +95 -0
- package/dist/quarantine.js +131 -0
- package/dist/refusal.d.ts +31 -0
- package/dist/refusal.js +3 -0
- package/{src/restore-source-placement.ts → dist/restore-source-placement.d.ts} +29 -101
- package/dist/restore-source-placement.js +79 -0
- package/dist/search-text-backfill.d.ts +15 -0
- package/dist/search-text-backfill.js +33 -0
- package/dist/snippet.d.ts +61 -0
- package/dist/snippet.js +129 -0
- package/dist/spam-report.d.ts +86 -0
- package/dist/spam-report.js +241 -0
- package/dist/sync-warning.d.ts +21 -0
- package/dist/sync-warning.js +26 -0
- package/dist/sync-watermarks.d.ts +138 -0
- package/dist/sync-watermarks.js +205 -0
- package/dist/test-helpers/fake-imap.d.ts +151 -0
- package/dist/test-helpers/fake-imap.js +508 -0
- package/dist/test-helpers/folder-roles.d.ts +34 -0
- package/dist/test-helpers/folder-roles.js +47 -0
- package/dist/test-helpers/mime-tree-generator.d.ts +82 -0
- package/dist/test-helpers/mime-tree-generator.js +329 -0
- package/dist/test-helpers/test-store.d.ts +69 -0
- package/dist/test-helpers/test-store.js +193 -0
- package/dist/text/normalizer.d.ts +20 -0
- package/dist/text/normalizer.js +102 -0
- package/dist/thread-message-rows.d.ts +69 -0
- package/dist/thread-message-rows.js +40 -0
- package/dist/thread-root.d.ts +7 -0
- package/dist/thread-root.js +25 -0
- package/dist/types.d.ts +343 -0
- package/dist/types.js +19 -0
- package/package.json +86 -73
- package/src/account-credentials.ts +0 -210
- package/src/adversarial-mime.e2e.test.ts +0 -307
- package/src/attribute-mapper.test.ts +0 -104
- package/src/attribute-mapper.ts +0 -148
- package/src/body-parse.test.ts +0 -55
- package/src/body-part-mapper.property.test.ts +0 -354
- package/src/body-part-mapper.ts +0 -360
- package/src/body-sync-auto-read-writeonce.test.ts +0 -219
- package/src/body-sync-calendar-suggestion.test.ts +0 -433
- package/src/body-sync-category-denormalize.test.ts +0 -352
- package/src/body-sync-category-override.test.ts +0 -501
- package/src/body-sync-category-writeonce.test.ts +0 -234
- package/src/body-sync-filter.test.ts +0 -237
- package/src/body-sync-message-gone.test.ts +0 -139
- package/src/body-sync-placement-flags.test.ts +0 -347
- package/src/body-sync-placement-writeonce.test.ts +0 -337
- package/src/body-sync-quarantine.test.ts +0 -276
- package/src/body-sync-queue.test.ts +0 -124
- package/src/body-sync-queue.ts +0 -131
- package/src/body-sync-resync.test.ts +0 -605
- package/src/body-sync-terminal.test.ts +0 -310
- package/src/body-sync-terminal.ts +0 -176
- package/src/body-sync-unclassifiable-once.test.ts +0 -260
- package/src/body-sync-unsubscribed-auto-read.test.ts +0 -176
- package/src/body-sync.ts +0 -1970
- package/src/calendar-parts.ts +0 -41
- package/src/classification-backfill.test.ts +0 -615
- package/src/classification-backfill.ts +0 -363
- package/src/classify-message.test.ts +0 -205
- package/src/classify-message.ts +0 -116
- package/src/connection-factory.ts +0 -102
- package/src/connection-test.ts +0 -208
- package/src/credentials.test.ts +0 -181
- package/src/external-move.test.ts +0 -369
- package/src/external-move.ts +0 -272
- package/src/filters/anchor-drift.ts +0 -55
- package/src/filters/filter-config.test.ts +0 -229
- package/src/filters/filter-config.ts +0 -69
- package/src/filters/list-id.test.ts +0 -50
- package/src/filters/match.test.ts +0 -429
- package/src/filters/match.ts +0 -274
- package/src/filters/message-embedder.test.ts +0 -39
- package/src/filters/message-embedder.ts +0 -33
- package/src/filters/pipeline.test.ts +0 -330
- package/src/filters/pipeline.ts +0 -284
- package/src/flag-push-terminal.test.ts +0 -209
- package/src/flag-push.test.ts +0 -408
- package/src/flag-push.ts +0 -198
- package/src/flag-queue-stars.test.ts +0 -171
- package/src/flag-queue.ts +0 -509
- package/src/folder-placement.ts +0 -56
- package/src/heuristics/authenticationResults.test.ts +0 -189
- package/src/heuristics/authenticationResults.ts +0 -212
- package/src/heuristics/classifyByHeaders.test.ts +0 -889
- package/src/heuristics/classifyByHeaders.ts +0 -467
- package/src/heuristics/classifyPlacement.test.ts +0 -366
- package/src/heuristics/classifyPlacement.ts +0 -211
- package/src/heuristics/classifyRealMail.test.ts +0 -242
- package/src/heuristics/machineSenders.test.ts +0 -101
- package/src/heuristics/senderMismatch.test.ts +0 -346
- package/src/heuristics/senderMismatch.ts +0 -259
- package/src/imapflow-connect-retry.test.ts +0 -134
- package/src/imapflow-connection.e2e.test.ts +0 -335
- package/src/imapflow-connection.integ.test.ts +0 -316
- package/src/imapflow-connection.test.ts +0 -469
- package/src/imapflow-connection.ts +0 -1475
- package/src/index.ts +0 -350
- package/src/list-id-backfill.test.ts +0 -573
- package/src/list-id-backfill.ts +0 -274
- package/src/mailbox-cursor-rebuild.test.ts +0 -171
- package/src/mailbox-cursor-rebuild.ts +0 -146
- package/src/mailbox-cursor.test.ts +0 -249
- package/src/mailbox-delete-intent.test.ts +0 -246
- package/src/mailbox-management.test.ts +0 -356
- package/src/mailbox-management.ts +0 -839
- package/src/mailbox-presence.test.ts +0 -72
- package/src/mailbox-queue.ts +0 -415
- package/src/mailbox-rename-intent.test.ts +0 -389
- package/src/mailbox-rename-subtree.test.ts +0 -664
- package/src/mailbox-sync.test.ts +0 -848
- package/src/mailbox-sync.ts +0 -724
- package/src/message-delete-junk-reconcile.test.ts +0 -117
- package/src/message-delete-no-trash.test.ts +0 -245
- package/src/message-delete-unsettled-placement.test.ts +0 -396
- package/src/message-move-copy.test.ts +0 -562
- package/src/message-move-empty-trash.test.ts +0 -326
- package/src/message-move-same-mailbox.test.ts +0 -139
- package/src/message-move-unsettled-placement.test.ts +0 -378
- package/src/message-move.ts +0 -1348
- package/src/message-parser.ts +0 -26
- package/src/message-presence.test.ts +0 -50
- package/src/message-sync-address-spoof.test.ts +0 -293
- package/src/message-sync-category.test.ts +0 -142
- package/src/message-sync-changedsince.test.ts +0 -840
- package/src/message-sync-flags.test.ts +0 -158
- package/src/message-sync-junk-harvest.test.ts +0 -244
- package/src/message-sync-quarantine.test.ts +0 -416
- package/src/message-sync-repoint.test.ts +0 -419
- package/src/message-sync.ts +0 -1963
- package/src/mime-walker.test.ts +0 -311
- package/src/mime-walker.ts +0 -305
- package/src/outbox-attachment-content.test.ts +0 -153
- package/src/outbox-attachment-content.ts +0 -104
- package/src/outbox-attachment-filename.test.ts +0 -132
- package/src/outbox-attachment-filename.ts +0 -76
- package/src/outbox-attachment.test.ts +0 -738
- package/src/outbox-attachment.ts +0 -536
- package/src/outbox-failed-recovery.test.ts +0 -370
- package/src/outbox-queue-settled-row.test.ts +0 -140
- package/src/outbox-queue.test.ts +0 -291
- package/src/outbox-queue.ts +0 -508
- package/src/pass-through-unit-of-work.ts +0 -17
- package/src/placement-move-terminal.test.ts +0 -300
- package/src/placement-move-terminal.ts +0 -148
- package/src/placement-move-unsettled.test.ts +0 -275
- package/src/placement-move.ts +0 -336
- package/src/placement-settled.test.ts +0 -147
- package/src/placement-transition-race.test.ts +0 -482
- package/src/quarantine.test.ts +0 -191
- package/src/quarantine.ts +0 -228
- package/src/snippet.test.ts +0 -213
- package/src/snippet.ts +0 -152
- package/src/spam-report.test.ts +0 -801
- package/src/spam-report.ts +0 -357
- package/src/stale-message-reconcile.test.ts +0 -82
- package/src/stale-message-reconcile.ts +0 -55
- package/src/sync-watermarks.test.ts +0 -409
- package/src/sync-watermarks.ts +0 -319
- package/src/system-flag-wire-format.test.ts +0 -77
- package/src/test-helpers/folder-roles.ts +0 -66
- package/src/test-helpers/isolated-mailbox.ts +0 -44
- package/src/test-helpers/mailfuzz-connection.ts +0 -27
- package/src/test-helpers/mime-tree-generator.ts +0 -461
- package/src/text/normalizer.test.ts +0 -223
- package/src/text/normalizer.ts +0 -140
- package/src/thread-message-rows.ts +0 -77
- package/src/types/mailparser-augment.d.ts +0 -15
- package/src/types/natural-porter-stemmer.d.ts +0 -50
- package/src/types/stopword.d.ts +0 -69
- package/src/types.ts +0 -371
- package/test/fixtures/mime-adversarial-e2e/01-octet-stream-pdf.eml +0 -21
- package/test/fixtures/mime-adversarial-e2e/02-nested-related-cid-image.eml +0 -31
- package/test/fixtures/mime-adversarial-e2e/03-calendar-invite.eml +0 -33
- package/test/fixtures/mime-adversarial-e2e/04-forwarded-rfc822-with-attachments.eml +0 -42
- package/test/fixtures/mime-adversarial-e2e/05-tnef-winmail.eml +0 -25
- package/test/fixtures/mime-adversarial-e2e/06-8bit-non-ascii.eml +0 -15
- package/test/fixtures/mime-adversarial-e2e/07-quoted-printable-soft-breaks.eml +0 -17
- package/test/fixtures/mime-adversarial-e2e/08-alternative-empty-text.eml +0 -18
- package/tsconfig.json +0 -8
package/src/types.ts
DELETED
|
@@ -1,371 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Types for the remit-mailbox-service
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import type { Readable } from "node:stream";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Discriminated union of mail authentication credentials.
|
|
9
|
-
*
|
|
10
|
-
* Exactly one credential kind can be present at a time — the union makes
|
|
11
|
-
* "both password and accessToken simultaneously" unrepresentable.
|
|
12
|
-
*/
|
|
13
|
-
export type MailCredentials =
|
|
14
|
-
| { kind: "password"; password: string }
|
|
15
|
-
| { kind: "accessToken"; accessToken: string };
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Classification of mail connection errors.
|
|
19
|
-
*/
|
|
20
|
-
export type MailConnectionErrorKind = "auth" | "network";
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Typed error for IMAP/SMTP connection failures.
|
|
24
|
-
*
|
|
25
|
-
* `kind: "auth"` — authentication rejected (bad credentials / token expired).
|
|
26
|
-
* `kind: "network"` — transport-level failure (ECONNREFUSED, ETIMEDOUT, etc.).
|
|
27
|
-
*
|
|
28
|
-
* IMPORTANT: access tokens must NEVER appear in error messages or causes.
|
|
29
|
-
*/
|
|
30
|
-
export class MailConnectionError extends Error {
|
|
31
|
-
readonly kind: MailConnectionErrorKind;
|
|
32
|
-
|
|
33
|
-
constructor(kind: MailConnectionErrorKind, message: string, cause?: unknown) {
|
|
34
|
-
super(message, { cause });
|
|
35
|
-
this.name = "MailConnectionError";
|
|
36
|
-
this.kind = kind;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* IMAP connection configuration
|
|
42
|
-
*/
|
|
43
|
-
export interface ImapConnectionConfig {
|
|
44
|
-
host: string;
|
|
45
|
-
port: number;
|
|
46
|
-
user: string;
|
|
47
|
-
credentials: MailCredentials;
|
|
48
|
-
tls: boolean;
|
|
49
|
-
tlsOptions?: {
|
|
50
|
-
rejectUnauthorized?: boolean;
|
|
51
|
-
servername?: string;
|
|
52
|
-
};
|
|
53
|
-
/** Connection timeout in milliseconds */
|
|
54
|
-
connTimeout?: number;
|
|
55
|
-
/** Authentication timeout in milliseconds */
|
|
56
|
-
authTimeout?: number;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* IMAP connection state
|
|
61
|
-
*/
|
|
62
|
-
export type ImapConnectionState =
|
|
63
|
-
| "disconnected"
|
|
64
|
-
| "connecting"
|
|
65
|
-
| "connected"
|
|
66
|
-
| "authenticated"
|
|
67
|
-
| "error";
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Namespace structure from IMAP NAMESPACE command
|
|
71
|
-
*/
|
|
72
|
-
export interface ImapNamespace {
|
|
73
|
-
prefix: string;
|
|
74
|
-
delimiter: string | false;
|
|
75
|
-
extensions?: Array<{
|
|
76
|
-
name: string;
|
|
77
|
-
params: string[] | null;
|
|
78
|
-
}>;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* IMAP namespaces grouped by type
|
|
83
|
-
*/
|
|
84
|
-
export interface ImapNamespaces {
|
|
85
|
-
personal: ImapNamespace[];
|
|
86
|
-
other: ImapNamespace[];
|
|
87
|
-
shared: ImapNamespace[];
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* IMAP mailbox status after opening
|
|
92
|
-
*/
|
|
93
|
-
export interface ImapBoxStatus {
|
|
94
|
-
name: string;
|
|
95
|
-
readOnly: boolean;
|
|
96
|
-
uidvalidity: number;
|
|
97
|
-
uidnext: number;
|
|
98
|
-
flags: string[];
|
|
99
|
-
permFlags: string[];
|
|
100
|
-
persistentUIDs: boolean;
|
|
101
|
-
messages: {
|
|
102
|
-
total: number;
|
|
103
|
-
new: number;
|
|
104
|
-
};
|
|
105
|
-
newKeywords: boolean;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* IMAP mailbox status from STATUS command
|
|
110
|
-
*/
|
|
111
|
-
export interface ImapMailboxStatus {
|
|
112
|
-
messages: number;
|
|
113
|
-
recent: number;
|
|
114
|
-
unseen: number;
|
|
115
|
-
uidNext: number;
|
|
116
|
-
uidValidity: number;
|
|
117
|
-
/** Highest modification sequence (CONDSTORE) as decimal digits of an unsigned 64-bit value. "0" if the server does not support CONDSTORE. */
|
|
118
|
-
highestModseq: string;
|
|
119
|
-
/** Count of messages flagged \Deleted but not yet expunged. */
|
|
120
|
-
deletedCount: number;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Flattened mailbox info for processing
|
|
125
|
-
*/
|
|
126
|
-
export interface FlatMailboxInfo {
|
|
127
|
-
fullPath: string;
|
|
128
|
-
name: string;
|
|
129
|
-
delimiter: string;
|
|
130
|
-
attributes: string[];
|
|
131
|
-
parentPath: string | null;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
export interface ImapAddress {
|
|
135
|
-
name?: string;
|
|
136
|
-
mailbox: string;
|
|
137
|
-
host: string;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
export interface ImapEnvelope {
|
|
141
|
-
date: string;
|
|
142
|
-
subject: string;
|
|
143
|
-
from: ImapAddress[];
|
|
144
|
-
sender: ImapAddress[];
|
|
145
|
-
replyTo: ImapAddress[];
|
|
146
|
-
to: ImapAddress[];
|
|
147
|
-
cc: ImapAddress[];
|
|
148
|
-
bcc: ImapAddress[];
|
|
149
|
-
inReplyTo: string;
|
|
150
|
-
messageId: string;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Subset of imapflow's `MessageStructureObject` we depend on. Restated
|
|
155
|
-
* here so non-imapflow code (and tests) can build fixtures without pulling
|
|
156
|
-
* the imapflow types in.
|
|
157
|
-
*/
|
|
158
|
-
export interface ImapBodyStructure {
|
|
159
|
-
/** Dot-numbered MIME path; absent on the root node. */
|
|
160
|
-
part?: string;
|
|
161
|
-
/** Full Content-Type, e.g. "text/plain" or "multipart/mixed". */
|
|
162
|
-
type: string;
|
|
163
|
-
parameters?: Record<string, string>;
|
|
164
|
-
id?: string;
|
|
165
|
-
description?: string;
|
|
166
|
-
encoding?: string;
|
|
167
|
-
size?: number;
|
|
168
|
-
lineCount?: number;
|
|
169
|
-
md5?: string;
|
|
170
|
-
disposition?: string;
|
|
171
|
-
dispositionParameters?: Record<string, string>;
|
|
172
|
-
language?: string[];
|
|
173
|
-
location?: string;
|
|
174
|
-
childNodes?: ImapBodyStructure[];
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* One server message from the cheap envelope-only FETCH the UIDVALIDITY
|
|
179
|
-
* cursor rebuild uses (#1272): UID + Message-ID + INTERNALDATE, nothing
|
|
180
|
-
* else — no flags, no BODYSTRUCTURE, no body fetch.
|
|
181
|
-
*/
|
|
182
|
-
export interface ImapEnvelopeSnapshot {
|
|
183
|
-
uid: number;
|
|
184
|
-
/** Raw RFC 822 Message-ID header; empty string when absent/unparseable. */
|
|
185
|
-
messageId: string;
|
|
186
|
-
internalDate: Date;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
export interface ImapMessage {
|
|
190
|
-
uid: number;
|
|
191
|
-
seq: number;
|
|
192
|
-
flags: string[];
|
|
193
|
-
internalDate: Date;
|
|
194
|
-
size: number;
|
|
195
|
-
envelope?: ImapEnvelope;
|
|
196
|
-
/**
|
|
197
|
-
* References header from RFC 2822.
|
|
198
|
-
* Contains Message-IDs of ancestor messages, with the first being the thread root.
|
|
199
|
-
*/
|
|
200
|
-
references?: string[];
|
|
201
|
-
/** Parsed BODYSTRUCTURE tree (RFC 9051 Section 7.5.2). */
|
|
202
|
-
bodyStructure?: ImapBodyStructure;
|
|
203
|
-
/**
|
|
204
|
-
* Per-message MODSEQ (RFC 7162) as decimal digits of an unsigned 64-bit
|
|
205
|
-
* value. Absent when the session has no CONDSTORE.
|
|
206
|
-
*/
|
|
207
|
-
modseq?: string;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Result of a mailbox sync operation
|
|
212
|
-
*/
|
|
213
|
-
export interface MailboxSyncResult {
|
|
214
|
-
created: number;
|
|
215
|
-
updated: number;
|
|
216
|
-
deleted: number;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* Common interface for IMAP connections
|
|
221
|
-
*/
|
|
222
|
-
export interface IImapConnection {
|
|
223
|
-
readonly state: ImapConnectionState;
|
|
224
|
-
readonly isConnected: boolean;
|
|
225
|
-
connect(): Promise<void>;
|
|
226
|
-
disconnect(): Promise<void>;
|
|
227
|
-
getNamespaces(): Promise<ImapNamespaces>;
|
|
228
|
-
listMailboxes(nsPrefix?: string): Promise<FlatMailboxInfo[]>;
|
|
229
|
-
openBox(mailboxPath: string, readOnly?: boolean): Promise<ImapBoxStatus>;
|
|
230
|
-
closeBox(expunge?: boolean): Promise<void>;
|
|
231
|
-
search(criteria: unknown[]): Promise<number[]>;
|
|
232
|
-
fetchMessages(uids: number[]): Promise<ImapMessage[]>;
|
|
233
|
-
/**
|
|
234
|
-
* True when the session negotiated CONDSTORE (RFC 7162) AND the currently
|
|
235
|
-
* open mailbox keeps persistent mod-sequences. A mailbox that answered
|
|
236
|
-
* NOMODSEQ on SELECT reports false, as does any server that never
|
|
237
|
-
* advertised the extension. Requires a mailbox to be open.
|
|
238
|
-
*/
|
|
239
|
-
supportsCondstore(): boolean;
|
|
240
|
-
/**
|
|
241
|
-
* FETCH every message in the open mailbox whose MODSEQ is strictly greater
|
|
242
|
-
* than `sinceModseq` (RFC 7162 CHANGEDSINCE) — both messages that arrived
|
|
243
|
-
* and messages whose metadata changed. Requires a mailbox to be open.
|
|
244
|
-
*
|
|
245
|
-
* Throws when CONDSTORE is unavailable: the underlying client drops the
|
|
246
|
-
* modifier in that case, which would silently turn the call into a fetch of
|
|
247
|
-
* the entire mailbox.
|
|
248
|
-
*/
|
|
249
|
-
fetchMessagesChangedSince(sinceModseq: bigint): Promise<ImapMessage[]>;
|
|
250
|
-
/**
|
|
251
|
-
* Cheap envelope-only pass for the UIDVALIDITY cursor rebuild (#1272): UID
|
|
252
|
-
* + Message-ID + INTERNALDATE for every UID, no BODYSTRUCTURE, no flags,
|
|
253
|
-
* no body. Requires a mailbox to be open.
|
|
254
|
-
*/
|
|
255
|
-
fetchEnvelopeSnapshots(uids: number[]): Promise<ImapEnvelopeSnapshot[]>;
|
|
256
|
-
fetchMessageBody(uid: number): Promise<Buffer | null>;
|
|
257
|
-
/**
|
|
258
|
-
* Fetch full message bodies for many UIDs in ONE pipelined ranged UID FETCH.
|
|
259
|
-
* Yields `{ uid, source }` per message; `source` is a readable stream the
|
|
260
|
-
* caller must consume before requesting the next item. Requires a mailbox to
|
|
261
|
-
* be open (one SELECT for the whole batch).
|
|
262
|
-
*/
|
|
263
|
-
fetchMessageBodies(
|
|
264
|
-
uids: number[],
|
|
265
|
-
): AsyncGenerator<{ uid: number; source: Readable }>;
|
|
266
|
-
/**
|
|
267
|
-
* Add flags to messages by UID.
|
|
268
|
-
* Requires mailbox to be open.
|
|
269
|
-
*/
|
|
270
|
-
addFlags(uids: number[], flags: string[]): Promise<void>;
|
|
271
|
-
/**
|
|
272
|
-
* Remove flags from messages by UID.
|
|
273
|
-
* Requires mailbox to be open.
|
|
274
|
-
*/
|
|
275
|
-
removeFlags(uids: number[], flags: string[]): Promise<void>;
|
|
276
|
-
/**
|
|
277
|
-
* Replace all flags on messages by UID.
|
|
278
|
-
* Requires mailbox to be open.
|
|
279
|
-
*/
|
|
280
|
-
setFlags(uids: number[], flags: string[]): Promise<void>;
|
|
281
|
-
/**
|
|
282
|
-
* Create a new mailbox.
|
|
283
|
-
*/
|
|
284
|
-
createMailbox(path: string): Promise<{ path: string; created: boolean }>;
|
|
285
|
-
/**
|
|
286
|
-
* Delete a mailbox.
|
|
287
|
-
*/
|
|
288
|
-
deleteMailbox(path: string): Promise<{ path: string }>;
|
|
289
|
-
/**
|
|
290
|
-
* Rename a mailbox.
|
|
291
|
-
*/
|
|
292
|
-
renameMailbox(
|
|
293
|
-
oldPath: string,
|
|
294
|
-
newPath: string,
|
|
295
|
-
): Promise<{ path: string; newPath: string }>;
|
|
296
|
-
/**
|
|
297
|
-
* Subscribe to a mailbox.
|
|
298
|
-
*/
|
|
299
|
-
subscribeMailbox(path: string): Promise<void>;
|
|
300
|
-
/**
|
|
301
|
-
* Unsubscribe from a mailbox.
|
|
302
|
-
*/
|
|
303
|
-
unsubscribeMailbox(path: string): Promise<void>;
|
|
304
|
-
/**
|
|
305
|
-
* Move messages to another mailbox.
|
|
306
|
-
* Returns mapping of source UIDs to destination UIDs.
|
|
307
|
-
* Requires mailbox to be open.
|
|
308
|
-
*
|
|
309
|
-
* @param uids - Array of message UIDs to move
|
|
310
|
-
* @param destination - Destination mailbox path
|
|
311
|
-
* @returns Object with destination path, uidValidity, and uidMap
|
|
312
|
-
*/
|
|
313
|
-
moveMessages(
|
|
314
|
-
uids: number[],
|
|
315
|
-
destination: string,
|
|
316
|
-
): Promise<{
|
|
317
|
-
destination: string;
|
|
318
|
-
uidValidity: number;
|
|
319
|
-
uidMap: Map<number, number>;
|
|
320
|
-
}>;
|
|
321
|
-
/**
|
|
322
|
-
* Copy messages to another mailbox.
|
|
323
|
-
* Returns mapping of source UIDs to destination UIDs.
|
|
324
|
-
* Requires mailbox to be open.
|
|
325
|
-
*
|
|
326
|
-
* @param uids - Array of message UIDs to copy
|
|
327
|
-
* @param destination - Destination mailbox path
|
|
328
|
-
* @returns Object with destination path, uidValidity, and uidMap
|
|
329
|
-
*/
|
|
330
|
-
copyMessages(
|
|
331
|
-
uids: number[],
|
|
332
|
-
destination: string,
|
|
333
|
-
): Promise<{
|
|
334
|
-
destination: string;
|
|
335
|
-
uidValidity: number;
|
|
336
|
-
uidMap: Map<number, number>;
|
|
337
|
-
}>;
|
|
338
|
-
/**
|
|
339
|
-
* Permanently delete messages (mark \Deleted + expunge).
|
|
340
|
-
* Requires mailbox to be open.
|
|
341
|
-
*
|
|
342
|
-
* @param uids - Array of message UIDs to delete
|
|
343
|
-
* @returns Number of messages deleted
|
|
344
|
-
*/
|
|
345
|
-
deleteMessages(uids: number[]): Promise<number>;
|
|
346
|
-
/**
|
|
347
|
-
* Get mailbox status without opening it.
|
|
348
|
-
* Uses IMAP STATUS command to get message counts.
|
|
349
|
-
*
|
|
350
|
-
* @param mailboxPath - Full path to the mailbox
|
|
351
|
-
* @returns Mailbox status including unseen count
|
|
352
|
-
*/
|
|
353
|
-
getMailboxStatus(mailboxPath: string): Promise<ImapMailboxStatus>;
|
|
354
|
-
/**
|
|
355
|
-
* Append a message to a mailbox via IMAP APPEND command.
|
|
356
|
-
*
|
|
357
|
-
* @param mailbox - Full path of the target mailbox
|
|
358
|
-
* @param message - RFC 822 message content
|
|
359
|
-
* @param flags - Optional flags to set on the message
|
|
360
|
-
* @returns Object with destination path, uidValidity, and uid of the appended message
|
|
361
|
-
*/
|
|
362
|
-
append(
|
|
363
|
-
mailbox: string,
|
|
364
|
-
message: string | Buffer,
|
|
365
|
-
flags?: string[],
|
|
366
|
-
): Promise<{
|
|
367
|
-
destination: string;
|
|
368
|
-
uidValidity: number;
|
|
369
|
-
uid: number;
|
|
370
|
-
}>;
|
|
371
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
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_=--
|
|
@@ -1,31 +0,0 @@
|
|
|
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_=--
|
|
@@ -1,33 +0,0 @@
|
|
|
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_=--
|
|
@@ -1,42 +0,0 @@
|
|
|
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_=--
|
|
@@ -1,25 +0,0 @@
|
|
|
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_=--
|
|
@@ -1,15 +0,0 @@
|
|
|
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
|
|
@@ -1,17 +0,0 @@
|
|
|
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
|
|
@@ -1,18 +0,0 @@
|
|
|
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_=--
|