namespace GerbilManagerWebAPI.Inbox { /// A reply to send, with RFC threading headers already computed. public sealed record OutgoingMail( string To, string Subject, string Body, string? InReplyTo, string? References); /// Outcome of a send attempt. Error is null on success; otherwise a stable code /// ("MailNotConfigured", "MailAuthFailed") the UI maps to a German hint. public sealed record SendOutcome(bool Sent, string? Error) { public static readonly SendOutcome Ok = new(true, null); public static SendOutcome Fail(string code) => new(false, code); } /// Sends mail. Abstracted so tests can assert the message/capture it without a live /// SMTP server (the live MailKit/Gmail path is gated on Julian's App Password). public interface IGmailMailSender { /// Sends the reply. Throws /// on bad/revoked credentials (surfaced as "MailAuthFailed"). Task SendAsync(MailConnection connection, OutgoingMail mail, CancellationToken ct = default); } }