namespace HrynCo.NotificationService.Worker.Services.EmailProcessing; using System.Net.Mail; using System.Net.Sockets; public static class NotificationDeliveryErrorFormatter { private const int MaximumErrorLength = 2000; private const string FallbackError = "Notification delivery failed after all retry attempts."; public static string Format(Exception exception) { string technicalMessage = Normalize(exception.GetBaseException().Message); if (string.IsNullOrWhiteSpace(technicalMessage)) { return FallbackError; } string contextualMessage = CreateContextualMessage(exception, technicalMessage); return contextualMessage.Length <= MaximumErrorLength ? contextualMessage : contextualMessage[..MaximumErrorLength]; } private static string CreateContextualMessage(Exception exception, string technicalMessage) { if (FindException(exception) is not null) { return "SMTP delivery failed after all retry attempts: " + "the SMTP server rejected the recipient address."; } SocketException? socketException = FindException(exception); if (socketException is not null) { string reason = socketException.SocketErrorCode switch { SocketError.HostNotFound or SocketError.NoData => "the configured SMTP server host could not be resolved", SocketError.ConnectionRefused => "the configured SMTP server refused the connection", SocketError.TimedOut => "the connection to the configured SMTP server timed out", _ when technicalMessage.Contains( "Name or service not known", StringComparison.OrdinalIgnoreCase) => "the configured SMTP server host could not be resolved", _ => "the configured SMTP server could not be reached" }; return $"SMTP delivery failed after all retry attempts: {reason} ({technicalMessage})."; } if (FindException(exception) is not null) { return $"SMTP delivery failed after all retry attempts ({technicalMessage})."; } return $"Notification delivery failed after all retry attempts ({technicalMessage})."; } private static TException? FindException(Exception exception) where TException : Exception { for (Exception? current = exception; current is not null; current = current.InnerException) { if (current is TException typedException) { return typedException; } } return null; } private static string Normalize(string message) { return message.ReplaceLineEndings(" ").Trim(); } }