/** * SMTP service — pure business logic for email send operations. * * No MCP dependency — fully unit-testable. */ import type { IConnectionManager } from '../connections/types.js'; import type RateLimiter from '../safety/rate-limiter.js'; import type { SendResult } from '../types/index.js'; import type { PreparedAttachment } from './attachments.js'; import type ImapService from './imap.service.js'; export default class SmtpService { private connections; private rateLimiter; private imapService; private readonly saveToSent; constructor(connections: IConnectionManager, rateLimiter: RateLimiter, imapService: ImapService, options?: { saveToSent?: boolean; }); /** * File a copy of a just-sent message in the Sent folder. * * SMTP delivers; it files nothing. Gmail and Outlook capture sent mail * server-side, so this is opt-in: doing it unasked would give those users * two copies of everything they send. * * The copy is composed from the same mail options that were just sent, * carrying the Message-ID the transport reported, so a later reply threads * against the message that actually went out. It is deliberately NOT sent as * `raw`: nodemailer does not derive an envelope from raw headers (it reports * `{from: false, to: []}`), so composing once and sending the bytes would * put recipient resolution — the single most dangerous thing in this file — * on an untested path. The bytes therefore differ from the wire copy only in * MIME boundary strings, which no reader cares about. * * Never throws. The mail has already left; reporting a failure here would * tell the user the send failed and invite a duplicate send. */ private fileCopyInSent; sendEmail(accountName: string, options: { to: string[]; subject: string; body: string; cc?: string[]; bcc?: string[]; html?: boolean; attachments?: PreparedAttachment[]; /** Threading headers — a scheduled reply keeps its place in the thread. */ inReplyTo?: string; references?: string[]; }): Promise; replyToEmail(accountName: string, options: { emailId: string; mailbox?: string; body: string; replyAll?: boolean; html?: boolean; attachments?: PreparedAttachment[]; }): Promise; forwardEmail(accountName: string, options: { emailId: string; mailbox?: string; to: string[]; body?: string; cc?: string[]; includeAttachments?: boolean; html?: boolean; }): Promise; private checkRateLimit; sendDraft(accountName: string, draftId: number, mailbox?: string): Promise; } //# sourceMappingURL=smtp.service.d.ts.map