diff --git a/HrynCo.NotificationService.Services/EmailChannels/TestSmtp/TestSmtpCommand.cs b/HrynCo.NotificationService.Services/EmailChannels/TestSmtp/TestSmtpCommand.cs new file mode 100644 index 0000000..acd5b2a --- /dev/null +++ b/HrynCo.NotificationService.Services/EmailChannels/TestSmtp/TestSmtpCommand.cs @@ -0,0 +1,18 @@ +using HrynCo.NotificationService.Services.Core; +using MediatR; + +namespace HrynCo.NotificationService.Services.EmailChannels.TestSmtp; + +/// +/// Sends a test email using the provided SMTP settings without persisting anything. +/// +public sealed record TestSmtpCommand( + string Host, + int Port, + string Username, + string Password, + bool UseSsl, + string FromEmail, + string FromName, + string ToEmail +) : IRequest>; diff --git a/HrynCo.NotificationService.Services/EmailChannels/TestSmtp/TestSmtpHandler.cs b/HrynCo.NotificationService.Services/EmailChannels/TestSmtp/TestSmtpHandler.cs new file mode 100644 index 0000000..3060906 --- /dev/null +++ b/HrynCo.NotificationService.Services/EmailChannels/TestSmtp/TestSmtpHandler.cs @@ -0,0 +1,52 @@ +using System.Net; +using System.Net.Mail; +using HrynCo.NotificationService.DAL.Abstract; +using HrynCo.NotificationService.Services.Core; +using HrynCo.NotificationService.Services.Logging; +using static HrynCo.NotificationService.Services.Core.ServiceResultHelper; + +namespace HrynCo.NotificationService.Services.EmailChannels.TestSmtp; + +internal sealed class TestSmtpHandler + : RequestHandler> +{ + public TestSmtpHandler( + IContextualSerilogLogger logger, + IUnitOfWork unitOfWork) + : base(logger, unitOfWork) + { + } + + protected override async Task> DoOnHandle( + TestSmtpCommand request, CancellationToken cancellationToken) + { + try + { + using var client = new SmtpClient(request.Host, request.Port) + { + EnableSsl = request.UseSsl, + Credentials = string.IsNullOrWhiteSpace(request.Username) + ? null + : new NetworkCredential(request.Username, request.Password) + }; + + using var mail = new MailMessage + { + From = new MailAddress(request.FromEmail, request.FromName), + Subject = "✅ Test email from Notification Service", + Body = "

This is a test email sent from the Notification Service admin panel to verify the channel settings.

", + IsBodyHtml = true + }; + mail.To.Add(new MailAddress(request.ToEmail)); + + await client.SendMailAsync(mail, cancellationToken); + } + catch (Exception ex) + { + Logger.Error(ex, "Ad-hoc SMTP test failed for host {Host}", request.Host); + return Failure(ex.Message); + } + + return Success(Unit.Value); + } +} diff --git a/HrynCo.NotificationService.Web/Controllers/Admin/AdminChannelsController.cs b/HrynCo.NotificationService.Web/Controllers/Admin/AdminChannelsController.cs index be74a99..6810f58 100644 --- a/HrynCo.NotificationService.Web/Controllers/Admin/AdminChannelsController.cs +++ b/HrynCo.NotificationService.Web/Controllers/Admin/AdminChannelsController.cs @@ -5,6 +5,7 @@ using HrynCo.NotificationService.Services.EmailChannels.Delete; using HrynCo.NotificationService.Services.EmailChannels.Get; using HrynCo.NotificationService.Services.EmailChannels.GetUsageSummary; using HrynCo.NotificationService.Services.EmailChannels.Send; +using HrynCo.NotificationService.Services.EmailChannels.TestSmtp; using HrynCo.NotificationService.Services.EmailChannels.Update; using HrynCo.NotificationService.Web.Controllers.Admin.ViewModels; using MediatR; @@ -133,6 +134,20 @@ public class AdminChannelsController(IMediator mediator) : Controller return RedirectToAction(nameof(Index)); } + // POST /admin/channels/test-smtp + [HttpPost("test-smtp")] + public async Task TestSmtp([FromBody] TestSmtpRequest request, CancellationToken ct) + { + var result = await mediator.Send(new TestSmtpCommand( + request.Host, request.Port, request.Username, request.Password, + request.UseSsl, request.FromEmail, request.FromName, request.ToEmail), ct); + + if (!result.IsSuccess) + return Ok(new { success = false, message = result.Error?.Message }); + + return Ok(new { success = true, message = $"Test email sent to {request.ToEmail}." }); + } + // POST /admin/channels/{id}/test [HttpPost("{id:guid}/test")] public async Task Test(Guid id, [FromBody] TestChannelRequest request, CancellationToken ct) @@ -165,3 +180,6 @@ public class AdminChannelsController(IMediator mediator) : Controller } public record TestChannelRequest(string ToEmail); +public record TestSmtpRequest( + string Host, int Port, string Username, string Password, + bool UseSsl, string FromEmail, string FromName, string ToEmail); diff --git a/HrynCo.NotificationService.Web/Views/AdminChannels/Edit.cshtml b/HrynCo.NotificationService.Web/Views/AdminChannels/Edit.cshtml index 44685df..c91baac 100644 --- a/HrynCo.NotificationService.Web/Views/AdminChannels/Edit.cshtml +++ b/HrynCo.NotificationService.Web/Views/AdminChannels/Edit.cshtml @@ -121,82 +121,90 @@ - @if (!Model.IsNew) - { - - } + Cancel } -@if (!Model.IsNew) -{ -