namespace ZB.MOM.WW.ScadaBridge.NotificationService.Ews; /// /// One-shot EWS mail submission (CreateItem, SendOnly, BCC-only). /// /// The seam the central Notification Outbox's EmailNotificationDeliveryAdapter calls when a /// SmtpConfiguration selects the EWS transport, mirroring the role /// ISmtpClientWrapper plays for the SMTP transport. /// /// public interface IEwsMailSender { /// /// Sends one message through Exchange Web Services. /// /// The endpoint, credential, sender, recipients and content to submit. /// Token cancelling the send; propagates unwrapped when the caller cancels. /// A task completing when Exchange has accepted the message. /// /// The send failed for a reason retrying cannot fix — authentication (401/403), a wrong URL /// (404), a schema fault, or a recipient rejection. /// /// /// The send failed for an availability-shaped reason — network/DNS/timeout, HTTP 5xx/408/429, /// or an ErrorServerBusy-class response code — and is worth retrying. /// Task SendAsync(EwsSendRequest request, CancellationToken cancellationToken = default); } /// /// Everything one EWS submission needs. Carried per call rather than held on the sender so the /// sender stays a stateless singleton and the credential never outlives the request. /// /// The absolute HTTPS EWS URL (for example https://host/EWS/Exchange.asmx). /// The service account, which may be domain-qualified (domain\user). /// The service account password. /// The sending mailbox address. /// The recipients; all addressed BCC so they cannot see one another. /// The message subject. /// The plain-text message body. /// /// The per-request timeout; a non-positive value leaves the default in force. /// public sealed record EwsSendRequest( Uri Endpoint, string Username, string Password, string FromAddress, IReadOnlyList BccRecipients, string Subject, string Body, int TimeoutSeconds); /// /// Signals an availability-shaped EWS failure that is worth retrying. /// public class EwsTransientException : Exception { /// /// Initializes the exception with a message and optional inner exception. /// /// Message describing the transient EWS failure; never carries the credential. /// Optional underlying transport exception. public EwsTransientException(string message, Exception? innerException = null) : base(message, innerException) { } } /// /// Signals an EWS failure that retrying cannot fix, so the notification parks immediately. /// public class EwsPermanentException : Exception { /// /// Initializes the exception with a message and optional inner exception. /// /// Message describing the permanent EWS failure; never carries the credential. /// Optional underlying transport exception. public EwsPermanentException(string message, Exception? innerException = null) : base(message, innerException) { } }