Introduce Yavsc.Interfaces.ISmtpClient and a recording test fake
Narrow ISmtpClient to the four operations MailSender actually uses, behind a Yavsc.Interfaces.ISmtpClientFactory. Production wires MailKitSmtpClient (SmtpClientFactory); tests wire a recording fake (RecordingSmtpClientFactory). The fake is pre-registered in WebServerFixture so SMTP calls are short-circuited; the EMailling test now asserts the Connect -> Authenticate -> Send -> Disconnect sequence. Yavsc.Abstract stays free of MailKit/MimeKit.
This commit is contained in:
parent
16508e9fb2
commit
2dec799d71
13 changed files with 264 additions and 10 deletions
53
src/Yavsc.Server/Services/MailKitSmtpClient.cs
Normal file
53
src/Yavsc.Server/Services/MailKitSmtpClient.cs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
using MailKit.Security;
|
||||
using MimeKit;
|
||||
using Yavsc.Interfaces;
|
||||
|
||||
namespace Yavsc.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Production adapter from <see cref="Yavsc.Interfaces.ISmtpClient"/>
|
||||
/// to MailKit's <c>SmtpClient</c>. Stateless; the underlying
|
||||
/// MailKit client is created per <c>Connect</c> cycle by the
|
||||
/// factory and disposed by <c>MailSender</c>'s <c>using</c>.
|
||||
/// </summary>
|
||||
public sealed class MailKitSmtpClient : ISmtpClient
|
||||
{
|
||||
private readonly MailKit.Net.Smtp.SmtpClient _client;
|
||||
|
||||
public MailKitSmtpClient()
|
||||
{
|
||||
_client = new MailKit.Net.Smtp.SmtpClient();
|
||||
}
|
||||
|
||||
public int Timeout
|
||||
{
|
||||
get => _client.Timeout;
|
||||
set => _client.Timeout = value;
|
||||
}
|
||||
|
||||
public void Connect(string host, int port, SecureSocketOptions options)
|
||||
{
|
||||
_client.Connect(host, port, options);
|
||||
}
|
||||
|
||||
public void Authenticate(string userName, string password)
|
||||
{
|
||||
_client.Authenticate(userName, password);
|
||||
}
|
||||
|
||||
public Task SendAsync(MimeMessage message, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return _client.SendAsync(message, cancellationToken);
|
||||
}
|
||||
|
||||
public void Disconnect(bool quit)
|
||||
{
|
||||
_client.Disconnect(quit);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_client.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
using System.Net;
|
||||
using MailKit.Net.Smtp;
|
||||
using MailKit.Security;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using MimeKit;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Yavsc.Interface;
|
||||
using Yavsc.Interfaces;
|
||||
using Yavsc.Settings;
|
||||
using Yavsc.Models;
|
||||
using Microsoft.AspNetCore.Identity.UI.Services;
|
||||
|
|
@ -16,21 +16,26 @@ namespace Yavsc.Services
|
|||
{
|
||||
public class MailSender : IEmailSender<ApplicationUser>, IEmailSender, ITrueEmailSender
|
||||
{
|
||||
|
||||
private readonly IStringLocalizer<MailSender> localizer;
|
||||
readonly SiteSettings siteSettings;
|
||||
readonly SmtpSettings smtpSettings;
|
||||
private readonly ILogger logger;
|
||||
private readonly ISmtpClientFactory _smtpClientFactory;
|
||||
|
||||
public MailSender(
|
||||
IOptions<SiteSettings> sitesOptions,
|
||||
IOptions<SmtpSettings> smtpOptions,
|
||||
ILoggerFactory loggerFactory,
|
||||
IStringLocalizer<MailSender> localizer
|
||||
IStringLocalizer<MailSender> localizer,
|
||||
ISmtpClientFactory smtpClientFactory
|
||||
)
|
||||
{
|
||||
this.localizer = localizer;
|
||||
siteSettings = sitesOptions.Value;
|
||||
smtpSettings = smtpOptions.Value;
|
||||
logger = loggerFactory.CreateLogger<MailSender>();
|
||||
_smtpClientFactory = smtpClientFactory;
|
||||
}
|
||||
|
||||
public Task SendConfirmationLinkAsync(ApplicationUser user, string email, string confirmationLink)
|
||||
|
|
@ -69,7 +74,7 @@ namespace Yavsc.Services
|
|||
msg.MessageId = MimeKit.Utils.MimeUtils.GenerateMessageId(
|
||||
siteSettings.Authority
|
||||
);
|
||||
using (SmtpClient sc = new())
|
||||
using ISmtpClient sc = _smtpClientFactory.CreateClient();
|
||||
{
|
||||
sc.Timeout = 30000;
|
||||
sc.Connect(
|
||||
|
|
|
|||
14
src/Yavsc.Server/Services/SmtpClientFactory.cs
Normal file
14
src/Yavsc.Server/Services/SmtpClientFactory.cs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
using Yavsc.Interfaces;
|
||||
|
||||
namespace Yavsc.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Production <see cref="ISmtpClientFactory"/>: hands out a
|
||||
/// fresh <see cref="MailKitSmtpClient"/> per call. Stateless;
|
||||
/// safe to register as a singleton.
|
||||
/// </summary>
|
||||
public sealed class SmtpClientFactory : ISmtpClientFactory
|
||||
{
|
||||
public ISmtpClient CreateClient() => new MailKitSmtpClient();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue