@bobfrankston/rmfmail 1.2.252 → 1.2.253
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/client/android-bootstrap.bundle.js +27 -30
- package/client/android-bootstrap.bundle.js.map +2 -2
- package/client/app.bundle.js +23 -0
- package/client/app.bundle.js.map +3 -3
- package/client/app.js +26 -0
- package/client/app.js.map +1 -1
- package/client/app.ts +24 -0
- package/client/compose/compose.bundle.js +37 -3
- package/client/compose/compose.bundle.js.map +3 -3
- package/client/compose/compose.css +13 -0
- package/client/compose/compose.js +41 -1
- package/client/compose/compose.js.map +1 -1
- package/client/compose/compose.ts +38 -1
- package/client/lib/api-client.js +7 -0
- package/client/lib/api-client.js.map +1 -1
- package/client/lib/api-client.ts +8 -0
- package/client/lib/mailxapi.js +10 -2
- package/package.json +3 -3
- package/packages/mailx-imap/package-lock.json +2 -2
- package/packages/mailx-imap/package.json +1 -1
- package/packages/mailx-service/index.d.ts +19 -1
- package/packages/mailx-service/index.d.ts.map +1 -1
- package/packages/mailx-service/index.js +27 -2
- package/packages/mailx-service/index.js.map +1 -1
- package/packages/mailx-service/index.ts +28 -2
- package/packages/mailx-service/jsonrpc.js +3 -1
- package/packages/mailx-service/jsonrpc.js.map +1 -1
- package/packages/mailx-service/jsonrpc.ts +3 -1
- package/packages/mailx-service/package.json +1 -1
- package/packages/mailx-settings/package.json +1 -1
- package/packages/mailx-store/package.json +1 -1
- package/packages/mailx-store-web/android-bootstrap.js +1 -1
- package/packages/mailx-store-web/android-bootstrap.js.map +1 -1
- package/packages/mailx-store-web/android-bootstrap.ts +1 -1
- package/packages/mailx-store-web/package.json +1 -1
- package/packages/mailx-store-web/web-service.d.ts +5 -1
- package/packages/mailx-store-web/web-service.d.ts.map +1 -1
- package/packages/mailx-store-web/web-service.js +5 -1
- package/packages/mailx-store-web/web-service.js.map +1 -1
- package/packages/mailx-store-web/web-service.ts +5 -1
- package/packages/mailx-types/mailx-api.d.ts +17 -1
- package/packages/mailx-types/mailx-api.d.ts.map +1 -1
- package/packages/mailx-types/mailx-api.ts +10 -1
- package/packages/mailx-types/mime-build.d.ts.map +1 -1
- package/packages/mailx-types/mime-build.js +35 -30
- package/packages/mailx-types/mime-build.js.map +1 -1
- package/packages/mailx-types/mime-build.ts +44 -32
- package/packages/mailx-types/package.json +1 -1
- /package/packages/mailx-imap/{node_modules.npmglobalize-stash-85680 → node_modules.npmglobalize-stash-54924}/.package-lock.json +0 -0
|
@@ -116,14 +116,18 @@ export function buildMimeMessage(opts: BuildMimeOptions): BuiltMime {
|
|
|
116
116
|
];
|
|
117
117
|
const commonHeaders = headers.filter((h): h is string => h !== null);
|
|
118
118
|
|
|
119
|
-
// ── draft: a single text/html part
|
|
119
|
+
// ── draft: a single text/html part, plus attachments if there are any ──
|
|
120
|
+
// "Simple" means no alternative and no inline-image extraction — it does
|
|
121
|
+
// NOT mean "drop the user's files". This branch used to `return` before
|
|
122
|
+
// ever reading opts.attachments, so a draft saved with a 65KB image was
|
|
123
|
+
// written body-only and the file was gone on reopen (Bob 2026-08-11).
|
|
120
124
|
if (opts.simpleHtml) {
|
|
121
125
|
const body = opts.bodyHtml || opts.bodyText || "";
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
126
|
+
const htmlPart = {
|
|
127
|
+
headers: [`Content-Type: text/html; charset=UTF-8`, `Content-Transfer-Encoding: quoted-printable`],
|
|
128
|
+
body: encodeQuotedPrintable(body),
|
|
129
|
+
};
|
|
130
|
+
const raw = wrapWithAttachments(commonHeaders, htmlPart, opts.attachments || [], newBoundary);
|
|
127
131
|
return { raw, messageId, inlineImageCount: 0 };
|
|
128
132
|
}
|
|
129
133
|
|
|
@@ -186,32 +190,40 @@ export function buildMimeMessage(opts: BuildMimeOptions): BuiltMime {
|
|
|
186
190
|
};
|
|
187
191
|
};
|
|
188
192
|
|
|
189
|
-
const
|
|
190
|
-
let raw: string;
|
|
191
|
-
if (attachments.length > 0) {
|
|
192
|
-
const mixedBoundary = newBoundary();
|
|
193
|
-
const inner = makeInner();
|
|
194
|
-
const parts: string[] = [
|
|
195
|
-
`--${mixedBoundary}\r\n` + inner.headers.join("\r\n") + `\r\n\r\n` + inner.body,
|
|
196
|
-
];
|
|
197
|
-
for (const att of attachments) {
|
|
198
|
-
// A quote or newline in a filename would break out of the header.
|
|
199
|
-
const filename = (att.filename || "attachment").replace(/[\r\n"]/g, "_");
|
|
200
|
-
const mime = att.mimeType || "application/octet-stream";
|
|
201
|
-
parts.push(
|
|
202
|
-
`--${mixedBoundary}\r\n` +
|
|
203
|
-
`Content-Type: ${mime}; name="${filename}"\r\n` +
|
|
204
|
-
`Content-Disposition: attachment; filename="${filename}"\r\n` +
|
|
205
|
-
`Content-Transfer-Encoding: base64\r\n\r\n` +
|
|
206
|
-
`${wrap76(att.dataBase64 || "")}\r\n`
|
|
207
|
-
);
|
|
208
|
-
}
|
|
209
|
-
raw = [...commonHeaders, `Content-Type: multipart/mixed; boundary="${mixedBoundary}"`].join("\r\n")
|
|
210
|
-
+ `\r\n\r\n` + parts.join("") + `--${mixedBoundary}--\r\n`;
|
|
211
|
-
} else {
|
|
212
|
-
const inner = makeInner();
|
|
213
|
-
raw = [...commonHeaders, ...inner.headers].join("\r\n") + `\r\n\r\n` + inner.body;
|
|
214
|
-
}
|
|
193
|
+
const raw = wrapWithAttachments(commonHeaders, makeInner(), opts.attachments || [], newBoundary);
|
|
215
194
|
|
|
216
195
|
return { raw, messageId, inlineImageCount: inlineImages.length };
|
|
217
196
|
}
|
|
197
|
+
|
|
198
|
+
/** Emit `inner` as the whole body, or — when there are attachments — as the
|
|
199
|
+
* first part of a multipart/mixed followed by one base64 part per file.
|
|
200
|
+
* Shared by the draft and send paths so a file can never be dropped by one
|
|
201
|
+
* of them alone. */
|
|
202
|
+
function wrapWithAttachments(
|
|
203
|
+
commonHeaders: string[],
|
|
204
|
+
inner: { headers: string[]; body: string },
|
|
205
|
+
attachments: MimeAttachment[],
|
|
206
|
+
newBoundary: () => string,
|
|
207
|
+
): string {
|
|
208
|
+
if (attachments.length === 0) {
|
|
209
|
+
return [...commonHeaders, ...inner.headers].join("\r\n") + `\r\n\r\n` + inner.body;
|
|
210
|
+
}
|
|
211
|
+
const mixedBoundary = newBoundary();
|
|
212
|
+
const parts: string[] = [
|
|
213
|
+
`--${mixedBoundary}\r\n` + inner.headers.join("\r\n") + `\r\n\r\n` + inner.body,
|
|
214
|
+
];
|
|
215
|
+
for (const att of attachments) {
|
|
216
|
+
// A quote or newline in a filename would break out of the header.
|
|
217
|
+
const filename = (att.filename || "attachment").replace(/[\r\n"]/g, "_");
|
|
218
|
+
const mime = att.mimeType || "application/octet-stream";
|
|
219
|
+
parts.push(
|
|
220
|
+
`--${mixedBoundary}\r\n` +
|
|
221
|
+
`Content-Type: ${mime}; name="${filename}"\r\n` +
|
|
222
|
+
`Content-Disposition: attachment; filename="${filename}"\r\n` +
|
|
223
|
+
`Content-Transfer-Encoding: base64\r\n\r\n` +
|
|
224
|
+
`${wrap76(att.dataBase64 || "")}\r\n`
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
return [...commonHeaders, `Content-Type: multipart/mixed; boundary="${mixedBoundary}"`].join("\r\n")
|
|
228
|
+
+ `\r\n\r\n` + parts.join("") + `--${mixedBoundary}--\r\n`;
|
|
229
|
+
}
|