Files
webmail/lib/eml-import.ts
T
Linus Rath cbd23db2fe fix: give mail import and export their own settings section and name the upload limit as the server does
- Settings > Backup & reset gets a Mail files section for Import mail
  and Export all mail, instead of sitting under settings backup.
- The pause message names Stalwart's 50000000-byte quota as 50 MB, not
  48 MB, and the dialog and settings texts mention .ost files.
- The old import's leftovers go: expandImportableEmails and
  EML_IMPORT_ACCEPT in lib/eml-import.ts, and the strings
  email_viewer.import_email, mailbox_context_menu.import_email and
  notifications.import_email_success/_error in all 30 locales.

lib/__tests__/eml-import.test.ts loses the tests of the removed
functions; its #891 checks that an .eml and an .eml in a ZIP keep their
Date header now run against the import's own sources.
2026-11-01 07:05:02 +01:00

28 lines
1.3 KiB
TypeScript

import { MAX_FUTURE_SENT_AT_MS } from "./email-date";
/** Only the header block is needed; don't decode a whole large message. */
const HEADER_SCAN_BYTES = 64 * 1024;
/**
* Read the `Date` header of a raw RFC 5322 message and return it as a JMAP
* UTCDate (no fractional seconds). Returns undefined when the header is
* missing, unparsable, or more than a day in the future.
*/
export async function readMessageDate(blob: Blob, now: number = Date.now()): Promise<string | undefined> {
const head = await blob.slice(0, HEADER_SCAN_BYTES).text();
return dateFromHeaderBlock(head, now);
}
/** `readMessageDate` for header text already read (anything after the header block is ignored). */
export function dateFromHeaderBlock(head: string, now: number = Date.now()): string | undefined {
const end = head.search(/\r?\n\r?\n/);
const headers = (end === -1 ? head : head.slice(0, end)).replace(/\r?\n[ \t]+/g, " ");
const match = /^Date:[ \t]*(.+)$/im.exec(headers);
if (!match) return undefined;
// Drop RFC 5322 comments such as "(CEST)" before parsing.
const value = match[1].replace(/\([^)]*\)/g, " ").trim();
const time = Date.parse(value);
if (Number.isNaN(time) || time - now > MAX_FUTURE_SENT_AT_MS) return undefined;
return new Date(time).toISOString().replace(/\.\d{3}Z$/, "Z");
}