export type EmailProvider = "resend" | "sendgrid" | "dev"; export type EmailReadiness = { status: "ready"; provider: Exclude; } | { status: "not-configured"; provider: "dev"; } | { status: "misconfigured" | "unavailable"; provider: EmailProvider | "unknown"; }; export interface EmailAttachment { filename: string; content: string | Buffer; contentType?: string; contentId?: string; disposition?: "attachment" | "inline"; } export interface SendEmailArgs { to: string; subject: string; html: string; text?: string; disableClickTracking?: boolean; useDeploymentCredentials?: boolean; from?: string; fromName?: string; cc?: string | string[]; bcc?: string | string[]; replyTo?: string; appSender?: { name: string; slug: string; replyTo?: string; }; inReplyTo?: string; references?: string; headers?: Record; idempotencyKey?: string; attachments?: EmailAttachment[]; timeoutMs?: number; templateId?: string; app?: string; orgId?: string; signal?: AbortSignal; /** * Account-access mail: sign-in links, verification, password reset, org * invitations. Delivered to test identities too, since they must still be * able to sign in. Otherwise every recipient line drops its test * identities, and a send left with no `to` or `cc` recipient is suppressed. */ authCritical?: boolean; } export type SendEmailResult = { status: "sent"; provider: EmailProvider; /** Test identities dropped from the recipient lines; absent when none. */ suppressed?: string[]; } | { status: "suppressed"; reason: "test-identity"; }; /** * Auth uses one Better Auth instance per process, so its email policy must * come from deployment configuration rather than a request-scoped secret. * Scoped email keys still support transactional app mail, but cannot safely * configure unauthenticated magic-link or signup-verification flows. */ export declare function getDeploymentEmailReadiness(): EmailReadiness; export declare function isEmailConfigured(): Promise; /** * Auth must only offer magic links when sending can succeed. In particular, * SendGrid needs EMAIL_FROM while Resend can use its sandbox sender. Keep * unreadable credential stores distinct from an unconfigured deployment so * callers can fail closed without claiming setup is absent. */ export declare function getEmailReadiness(): Promise; export declare function getEmailProvider(): Promise; /** * Thrown when a provider request completed (we got an HTTP response) but the * status was not 2xx. Carries the raw request/response so the audit log can * distinguish "the provider rejected it" from a thrown error that never * reached the provider (network failure, timeout, credential resolution). */ export declare class EmailProviderError extends Error { readonly provider: EmailProvider; readonly from: string; readonly requestPayload: string; readonly responseStatus: number; readonly responseBody: string; constructor(message: string, details: { provider: EmailProvider; from: string; requestPayload: string; responseStatus: number; responseBody: string; }); } export declare function sendEmail(args: SendEmailArgs): Promise;