/**
 * Pure IMAP projection/formatting helpers — the shared backbone the IMAP
 * service builds on. Kept dependency-free (no `this`, no IMAP client, no I/O) so
 * they're trivially unit-testable and reusable across getEmailById /
 * searchSingleFolder / get_thread without duplicating the parse→shape mapping.
 */
import type { ParsedMail, AddressObject } from "mailparser";
import type { SearchObject } from "imapflow";
import type { EmailMessage, SearchEmailOptions } from "../types/index.js";
/** Strip IMAP search-unsafe characters before they reach the SEARCH command:
 *  quote/backslash (would break imapflow's quoted strings) and CR/LF/NUL (could
 *  smuggle a command line into the IMAP stream — VALID-002 / IMAP-004). */
export declare function sanitizeImapSearchValue(s: string): string;
/**
 * Map a validated SearchEmailOptions to an imapflow SearchObject — all values
 * sanitized, the header field-name held to the RFC 5322 grammar. Pure; throws
 * only on an invalid header field name. (Was inlined in searchSingleFolder.)
 */
export declare function buildSearchCriteria(options: SearchEmailOptions): SearchObject;
/** Per-source-folder record of a bulk move/copy: which UIDs the server accepted,
 *  their captured Message-IDs, the UIDs UIDPLUS confirmed relocated, and whether
 *  the server returned a COPYUID map at all. */
export interface RelocationJob {
    accepted: string[];
    midMap: Map<string, string>;
    relocated: Set<string>;
    uidplus: boolean;
    /** Source folder (move only) — woven into the failure message. */
    folder?: string;
}
/**
 * Honest verified-landing check for bulk move/copy. A relocation counts as
 * success ONLY if the server's UIDPLUS COPYUID map confirmed it, or (no UIDPLUS)
 * the message's Message-ID is found in the target. Anything else is a failure —
 * never an assumed success — which is what catches the silent All-Mail-union
 * no-op (Bug A). Was duplicated verbatim in bulkMoveEmails + bulkCopyToFolder.
 */
export declare function verifyRelocatedMessages(jobs: RelocationJob[], targetFolder: string, findMessageIdsInFolder: (folder: string, mids: string[]) => Promise<Set<string>>, makeError: (uid: string, sourceFolder: string | undefined) => string): Promise<{
    success: number;
    failed: number;
    errors: string[];
}>;
/** Strip HTML to plain text. Decodes entities BEFORE stripping tags (PARSE-008)
 *  so encoded `&lt;script&gt;…` can't survive as literal markup, and drops HTML
 *  comments up front (PARSE-009) so their inner text doesn't leak as prose. */
export declare function stripHtml(html: string): string;
/** Truncate a body to `maxLength`, breaking on a word boundary when close. */
export declare function truncateBody(body: string, maxLength?: number): string;
/** Flatten a mailparser address field into display strings. IMAP-007: the field
 *  can be a single AddressObject OR an array (multiple `To:` header lines, legal
 *  per RFC 5322 §3.6.3 and emitted by Proton on bridged forwards). */
export declare function normalizeAddressList(field: AddressObject | AddressObject[] | undefined): string[];
/** The minimal shape of an imapflow fetch result `buildEmailMessage` reads. */
export interface FetchedMessageShape {
    uid: number;
    flags?: Set<string>;
}
/**
 * Project a fully-parsed message (mailparser `ParsedMail` + the imapflow fetch
 * envelope's uid/flags) into the canonical `EmailMessage`. This is the single
 * source of truth for the parse→shape mapping used by getEmailById and
 * searchSingleFolder (was duplicated verbatim in both).
 */
export declare function buildEmailMessage(message: FetchedMessageShape, parsed: ParsedMail, folderPath: string): EmailMessage;
//# sourceMappingURL=imap-helpers.d.ts.map