ixes invalid registration email formats are still rejected before the user is created
All checks were successful
Dotnet build and test / build (pull_request) Successful in 10m5s
All checks were successful
Dotnet build and test / build (pull_request) Successful in 10m5s
SMTP recipient rejections are logged and treated as a soft failure instead of crashing the request
This commit is contained in:
parent
6a6cc3a967
commit
40437982eb
2 changed files with 85 additions and 1 deletions
|
|
@ -1,9 +1,18 @@
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Globalization;
|
||||||
|
using MailKit.Net.Smtp;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Localization;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using MimeKit;
|
||||||
using Yavsc.Interface;
|
using Yavsc.Interface;
|
||||||
using Yavsc.Interfaces;
|
using Yavsc.Interfaces;
|
||||||
|
using Yavsc.Models.Relationship;
|
||||||
using Yavsc.Org.Tests.Fakes;
|
using Yavsc.Org.Tests.Fakes;
|
||||||
|
using Yavsc.Services;
|
||||||
|
using Yavsc.Settings;
|
||||||
using Yavsc.ViewModels.Account;
|
using Yavsc.ViewModels.Account;
|
||||||
|
|
||||||
namespace Yavsc.Org.Tests
|
namespace Yavsc.Org.Tests
|
||||||
|
|
@ -80,5 +89,74 @@ namespace Yavsc.Org.Tests
|
||||||
Assert.Contains(results, r => r.MemberNames.Contains(nameof(RegisterModel.Email)));
|
Assert.Contains(results, r => r.MemberNames.Contains(nameof(RegisterModel.Email)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task SendEmailAsync_ignores_smtp_recipient_rejection()
|
||||||
|
{
|
||||||
|
var sender = new MailSender(
|
||||||
|
Options.Create(new SiteSettings
|
||||||
|
{
|
||||||
|
Title = "Test",
|
||||||
|
Authority = "example.com",
|
||||||
|
Owner = new StaticContact { Name = "Test Owner", EMail = "owner@example.com" }
|
||||||
|
}),
|
||||||
|
Options.Create(new SmtpSettings
|
||||||
|
{
|
||||||
|
Host = "smtp.test.local",
|
||||||
|
Port = 465,
|
||||||
|
UserName = "test-user",
|
||||||
|
Password = "secret"
|
||||||
|
}),
|
||||||
|
NullLoggerFactory.Instance,
|
||||||
|
new TestStringLocalizer(),
|
||||||
|
new RejectingSmtpClientFactory());
|
||||||
|
|
||||||
|
var result = await sender.SendEmailAsync(
|
||||||
|
"Alice",
|
||||||
|
"contact@pschneider.fr",
|
||||||
|
"Welcome",
|
||||||
|
"hello");
|
||||||
|
|
||||||
|
Assert.Equal(string.Empty, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class RejectingSmtpClientFactory : ISmtpClientFactory
|
||||||
|
{
|
||||||
|
public Yavsc.Interfaces.ISmtpClient CreateClient() => new RejectingSmtpClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class RejectingSmtpClient : Yavsc.Interfaces.ISmtpClient
|
||||||
|
{
|
||||||
|
public int Timeout { get; set; }
|
||||||
|
public void Connect(string host, int port, MailKit.Security.SecureSocketOptions options) { }
|
||||||
|
public void Authenticate(string userName, string password) { }
|
||||||
|
public Task SendAsync(MimeMessage message, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
throw new SmtpCommandException(
|
||||||
|
SmtpErrorCode.RecipientNotAccepted,
|
||||||
|
SmtpStatusCode.MailboxUnavailable,
|
||||||
|
"Recipient address rejected: User unknown in local recipient table");
|
||||||
|
}
|
||||||
|
public void Disconnect(bool quit) { }
|
||||||
|
public void Dispose() { }
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class TestStringLocalizer : IStringLocalizer<MailSender>
|
||||||
|
{
|
||||||
|
public LocalizedString this[string name] => new(name, name);
|
||||||
|
public LocalizedString this[string name, params object[] arguments] => new(name, string.Format(CultureInfo.InvariantCulture, name, arguments));
|
||||||
|
|
||||||
|
public IEnumerable<LocalizedString> GetAllStrings(bool includeParentCultures)
|
||||||
|
=> Enumerable.Empty<LocalizedString>();
|
||||||
|
|
||||||
|
public LocalizedString GetString(string name)
|
||||||
|
=> new(name, name);
|
||||||
|
|
||||||
|
public LocalizedString GetString(string name, params object[] arguments)
|
||||||
|
=> new(name, string.Format(CultureInfo.InvariantCulture, name, arguments));
|
||||||
|
|
||||||
|
public IStringLocalizer WithCulture(CultureInfo culture)
|
||||||
|
=> this;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
using MailKit.Net.Smtp;
|
||||||
using MailKit.Security;
|
using MailKit.Security;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|
@ -114,7 +115,7 @@ namespace Yavsc.Services
|
||||||
msg.MessageId = MimeKit.Utils.MimeUtils.GenerateMessageId(
|
msg.MessageId = MimeKit.Utils.MimeUtils.GenerateMessageId(
|
||||||
siteSettings.Authority
|
siteSettings.Authority
|
||||||
);
|
);
|
||||||
using ISmtpClient sc = _smtpClientFactory.CreateClient();
|
using Yavsc.Interfaces.ISmtpClient sc = _smtpClientFactory.CreateClient();
|
||||||
{
|
{
|
||||||
sc.Timeout = 30000;
|
sc.Timeout = 30000;
|
||||||
sc.Connect(
|
sc.Connect(
|
||||||
|
|
@ -139,6 +140,11 @@ namespace Yavsc.Services
|
||||||
logger.LogError(ex, "Refusing to send email because the recipient or sender address is malformed. To={To}, From={From}", email, siteSettings.Owner.EMail);
|
logger.LogError(ex, "Refusing to send email because the recipient or sender address is malformed. To={To}, From={From}", email, siteSettings.Owner.EMail);
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
catch (SmtpCommandException ex)
|
||||||
|
{
|
||||||
|
logger.LogError(ex, "SMTP rejected the recipient or sender address. To={To}, Subject={Subject}, Status={Status}, Error={Error}", email, subject, ex.StatusCode, ex.Message);
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
logger.LogError(ex, "Failed to send email. To={To}, Subject={Subject}", email, subject);
|
logger.LogError(ex, "Failed to send email. To={To}, Subject={Subject}", email, subject);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue