Files
ScadaBridge/src/ZB.MOM.WW.ScadaBridge.NotificationService/Ews/IEwsMailSender.cs
T

81 lines
3.7 KiB
C#

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