/** * Writing one draft: header safety, message composition, Drafts discovery. * * Headers are built, not concatenated * ─────────────────────────────────── * `appendDraft` turns caller-supplied strings into real RFC 5322 header lines. * A bare CR or LF anywhere in `to`, `from`, `subject`, `inReplyTo` or * `references` would end the header being written and start one the caller * chose, `Bcc:` being the one that matters, because a draft the owner later * sends would carry it. Every field is REFUSED rather than sanitized: silently * stripping the newline would send something the caller did not ask for, and a * caller that meant to inject learns nothing from a rejection but an attacker * whose payload was quietly trimmed learns which filter to try next. * * The address and subject checks are the SMTP module's own * (`validateSmtpAddress`, `validateSmtpSubject`), reused rather than restated * so that both ways of getting a message out of this module agree on what is * allowed. * * Finding the Drafts folder * ───────────────────────── * `"Drafts"` is a guess that is wrong on the most common mail host there is: * Gmail's is `[Gmail]/Drafts`, and appending to a literal `Drafts` there * creates a new stray folder instead. `selectDraftsMailbox` reads the LIST * reply and prefers the folder the server itself flagged `\Drafts` * (RFC 6154), which is the only answer that is right by construction. */ import type { ImapAppendDraftInput } from './imap-client.js'; /** The fallback when a server tells us nothing about its folders. */ export declare const DEFAULT_DRAFTS_MAILBOX = "Drafts"; /** * Validate a header value that is neither an address nor a subject, * `In-Reply-To` and `References`, both of which hold message ids. * * @throws Error with a plain-language message on invalid input. */ export declare function validateDraftHeaderValue(value: string, field: string): void; /** * Refuse a draft whose fields would forge headers, before anything is sent. * Called by `appendDraft` ahead of any server conversation, and again by * `buildDraftMessage` so the composer is safe on its own. */ export declare function validateDraftInput(input: ImapAppendDraftInput): void; /** `Mon, 27 Jul 2026 14:03:05 +0000`, RFC 5322 §3.3, always in UTC. */ export declare function formatRfc5322Date(date: Date): string; /** * Encode a header value as RFC 2047 encoded-words when it is not plain ASCII. * * A subject in any language other than English is the ordinary case, not an * edge one, and mail clients read `=?UTF-8?B?..?=` everywhere while raw UTF-8 * in a header is only understood by servers that announce RFC 6532 support. * Long values are split on character boundaries and folded, because an * encoded-word longer than 75 characters is not one. */ export declare function encodeHeaderValue(value: string): string; /** * Compose the RFC 5322 message an APPEND uploads. * * The body goes out as UTF-8 with `Content-Transfer-Encoding: 8bit` rather * than being re-encoded, so what the owner later sees in the draft is exactly * the text that was handed in. That is also why the caller must count the * literal in bytes: this string is longer in bytes than in characters for any * body that is not pure ASCII. * * No `Message-ID` is written. The message has not been sent, and the id that * matters is the one the sending path stamps at send time; a second one * invented here would never match it. * * @throws Error when any field would forge a header. */ export declare function buildDraftMessage(input: ImapAppendDraftInput, now: Date): string; interface MailboxEntry { readonly name: string; readonly attributes: readonly string[]; readonly delimiter: string; } /** Parse the mailboxes out of a LIST reply. Unreadable lines are skipped. */ export declare function parseMailboxList(lines: readonly string[]): MailboxEntry[]; /** * Choose the Drafts mailbox from a LIST reply, in descending order of how much * the server actually told us: * * 1. the folder carrying the `\Drafts` special-use attribute (RFC 6154), * the server's own answer, and the only one that survives a mailbox named * in another language; * 2. a folder literally named `drafts`, case-insensitively; * 3. a folder whose last path segment is `drafts`, this is what finds * Gmail's `[Gmail]/Drafts`; * * and null when the reply names none of those, which leaves the caller to fall * back to the plain `Drafts` name. * * `\Noselect` folders are skipped throughout: they are path nodes, and an * APPEND to one fails. */ export declare function selectDraftsMailbox(lines: readonly string[]): string | null; /** * The UID the server assigned the appended message, when it advertises UIDPLUS * (RFC 4315) and says so in its tagged reply. * * Returns null when it does not. Nothing is guessed: a server that reports no * UID leaves the caller with `uid: null`, which is true, rather than with a * number that points at a different message. */ export declare function parseAppendUid(lines: readonly string[]): number | null; export {}; //# sourceMappingURL=imap-draft.d.ts.map