/**
 * Server-side email classification and issuer-selection policy.
 *
 * In the v2 split (see docs/multi-tenant-gmail-listener/business-recognition-plan.md)
 * the gateway parses the MIME message and forwards *structural* evidence — header
 * addresses, mailing-list markers, and any quoted `---------- Forwarded message ---------`
 * blocks it found in the body. The policy that decides **what kind of email this is**
 * and **which address identifies the issuing business** lives here, next to the
 * `suggestion_data.emails` lookup it feeds, because it needs tenant-scoped knowledge
 * the gateway does not have: the tenant's own addresses, its own business names, and
 * which senders are invoice-issuing platforms.
 *
 * Replaces the previous `selectIssuerEmail` / `selectIssuerCandidates` /
 * `isSelfIssuedSenderEvidence` trio, whose single-address heuristics collapsed on
 * two real-world shapes:
 *
 *  - **manually forwarded** mail, where the live `From` is a person at the tenant and
 *    the quoted headers are a mailing-list rewrite — every recoverable address then
 *    belonged to the tenant, so recognition matched the tenant's *own* business and
 *    the email was wrongly dropped as self-issued;
 *  - **self-issued** mail, which was only detected because the previous hard-coded
 *    provider list happened to contain one specific tenant's forwarding group.
 */
/** One quoted `---------- Forwarded message ---------` header block from the body. */
export interface ForwardedBlockEvidence {
    /** `From` address of the quoted block, when one could be parsed. */
    from?: string | null;
    /** `From` display name of the quoted block, RFC 2047-decoded. */
    fromDisplayName?: string | null;
    /** `To` addresses of the quoted block. */
    to?: ReadonlyArray<string | null> | null;
    /** `Subject` of the quoted block. */
    subject?: string | null;
}
export interface SenderEvidence {
    /** From header address. */
    from?: string | null;
    /** From header display name, RFC 2047-decoded. */
    fromDisplayName?: string | null;
    /** Reply-To header address. */
    replyTo?: string | null;
    /** X-Original-From address. */
    originalFrom?: string | null;
    /** X-Original-Sender address — the relaying platform, when the message came through one. */
    originalSender?: string | null;
    /** X-Forwarded-To / Envelope-To address. */
    forwardedTo?: string | null;
    /** List-ID / Mailing-list marker, present when the message came through a mailing list. */
    listId?: string | null;
    /** Addresses identifying the mailing list itself (List-Post, Mailing-list, …). */
    listAddresses?: ReadonlyArray<string | null> | null;
    /**
     * Quoted forwarded-header blocks recovered from the body, **outermost first**.
     * The innermost block is closest to the original sender.
     */
    forwardedBlocks?: ReadonlyArray<ForwardedBlockEvidence> | null;
    /** Addresses parsed from `mailto:` links in the body, in document order. */
    issuerCandidates?: ReadonlyArray<string | null> | null;
}
export declare const EmailKind: {
    /** Sent straight to the tenant by the issuer. */
    readonly DIRECT: "DIRECT";
    /** Reached the tenant through a mailing list or an invoice-issuing platform. */
    readonly RELAYED: "RELAYED";
    /** Manually forwarded into the ingest alias by a person at the tenant. */
    readonly FORWARDED: "FORWARDED";
    /** A copy of a document the tenant itself issued — nothing to ingest. */
    readonly SELF_ISSUED: "SELF_ISSUED";
};
export type EmailKind = (typeof EmailKind)[keyof typeof EmailKind];
/**
 * Everything tenant-specific the classifier needs. Assembled by
 * {@link import('../providers/email-ingestion-control.provider.js').EmailIngestionControlProvider.loadTenantMailContext}.
 * All address/domain values are lower-cased by the loader.
 */
export interface TenantMailContext {
    /** The tenant's own addresses: its ingest aliases and its own businesses' registered emails. */
    ownAddresses: ReadonlySet<string>;
    /** Domains the tenant owns; any address on one of these is the tenant's, not an issuer. */
    ownDomains: ReadonlySet<string>;
    /** The tenant's own business names, used to spot a self-issued document by sender name. */
    ownNames: readonly string[];
    /** Invoice-issuing platforms (Morning, Sumit, …) that relay on a business's behalf. */
    invoicePlatformSenders: ReadonlySet<string>;
}
/**
 * Invoice-issuing platforms that relay on a business's behalf, available to every
 * tenant. A tenant billing through something else adds its own via
 * `suggestion_data.emailIngestion.extraPlatformSenders`.
 *
 * TODO(email-ingestion): `ap@the-guild.dev` is one tenant's own forwarding group and
 * does not belong in a global list. It is kept only so behavior is unchanged while
 * that tenant's `emailIngestion.ownDomains` config is populated — remove it once the
 * config is live in production (see docs/multi-tenant-gmail-listener/business-recognition-plan.md).
 */
export declare const GLOBAL_INVOICE_PLATFORM_SENDERS: readonly string[];
export interface EmailClassification {
    kind: EmailKind;
    /**
     * Issuer addresses to try against the `suggestion_data.emails` lookup, most likely
     * first. Never contains the tenant's own addresses, its mailing-list addresses, or
     * the forwarder.
     */
    issuerCandidates: string[];
    /** The person who forwarded the message, when this is a forward. Never an issuer. */
    forwarder: string | null;
    /**
     * The issuer's display name when no usable address survived — the only signal left
     * on mail forwarded out of a mailing list, which rewrites every quoted address to
     * the list's own. Fed to the name-based business matcher.
     */
    issuerNameHint: string | null;
}
/**
 * Lower-cased bare address, or `undefined` when the value is not address-shaped.
 * The shape guard matters: `X-Original-From` is frequently a display name with no
 * address at all, and without it that whole string reached the business lookup.
 */
export declare function normalizeEmail(value: string | null | undefined): string | undefined;
/**
 * Split a mailing-list display name into the original sender and the list, e.g.
 * `'screenly (via Paddle.com)' via Account Payables` → `screenly (via Paddle.com)`.
 *
 * Anchors on the **last** ` via ` rather than the first: vendor names routinely
 * contain their own parenthesised `(via …)`, which a leftmost match would split on.
 */
export declare function splitViaDisplayName(displayName: string | null | undefined): {
    sender: string;
    list: string;
} | null;
/**
 * Decide what kind of email this is and which addresses may identify its issuer.
 *
 * **Kind — first match wins:**
 *
 *  1. a quoted forwarded block exists, or `From` is a person at the tenant → `FORWARDED`
 *  2. the sender's display name is one of the tenant's own business names → `SELF_ISSUED`
 *  3. the message came through an invoice platform and an external address survives → `RELAYED`
 *  4. the message came through an invoice platform and none does → `SELF_ISSUED`
 *  5. a mailing-list marker or a `'X' via Y` display name is present → `RELAYED`
 *  6. otherwise → `DIRECT`
 *
 * Rule 1 outranking rule 4 is the crux: a person deliberately forwarding into the
 * ingest alias signals intent to ingest, whereas self-issued confirmations always
 * arrive by automatic relay and never by hand. Without that ordering, a forwarded
 * supplier invoice whose every quoted address was rewritten to the tenant's own
 * mailing list looks indistinguishable from a self-issued one.
 */
export declare function classifyEmail(evidence: SenderEvidence | null | undefined, ctx: TenantMailContext): EmailClassification;
