fix(api): avoid NRE in MailSender on rdv query notifications
The API did not bind the Smtp section and its appsettings lacked Site.Owner, so MailSender threw a NullReferenceException and PostQuery returned 500. Bind Smtp in the API, add Owner/Smtp to the api appsettings template, and log/skip sending when mail configuration is incomplete. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
parent
10d992a07a
commit
0e9f61bd24
5 changed files with 52 additions and 2 deletions
16
CHANGELOG.md
16
CHANGELOG.md
|
|
@ -1,5 +1,13 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [1.0.8-rc30] - unstable
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
## [1.0.8-rc29] - unstable
|
## [1.0.8-rc29] - unstable
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
@ -19,6 +27,14 @@
|
||||||
|
|
||||||
* [PostIt] Mise a jour d'Avalonia vers 12.1.4.
|
* [PostIt] Mise a jour d'Avalonia vers 12.1.4.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
* [Yavsc.Api, Yavsc.Server] Une demande de rendez-vous ne provoque plus
|
||||||
|
d'erreur 500 (NullReferenceException dans MailSender) : l'API lie
|
||||||
|
desormais la section Smtp, le modele appsettings-api fournit Site.Owner
|
||||||
|
et Smtp, et un envoi sans configuration mail complete est journalise
|
||||||
|
puis ignore.
|
||||||
|
|
||||||
|
|
||||||
## [1.0.8-rc28] - unstable
|
## [1.0.8-rc28] - unstable
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,17 @@
|
||||||
"https://preprod-blogs.$DOMAIN"
|
"https://preprod-blogs.$DOMAIN"
|
||||||
],
|
],
|
||||||
"Bills": "bills",
|
"Bills": "bills",
|
||||||
"TempDir": "temp"
|
"TempDir": "temp",
|
||||||
|
"Owner": {
|
||||||
|
"Name": "Paul Schneider",
|
||||||
|
"EMail": "paul@pschneider.fr"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Smtp": {
|
||||||
|
"Host": "mercure.pschneider.fr",
|
||||||
|
"Port": 465,
|
||||||
|
"UserName": "paul",
|
||||||
|
"Password": "$SMTP_PASSWORD"
|
||||||
},
|
},
|
||||||
"Logging": {
|
"Logging": {
|
||||||
"LogLevel": {
|
"LogLevel": {
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ using Yavsc.Models;
|
||||||
using Yavsc;
|
using Yavsc;
|
||||||
using Yavsc.Server.Helpers;
|
using Yavsc.Server.Helpers;
|
||||||
using Yavsc.Services;
|
using Yavsc.Services;
|
||||||
|
using Yavsc.Settings;
|
||||||
using Yavsc.Server.Hubs;
|
using Yavsc.Server.Hubs;
|
||||||
using Yavsc.Api.Services;
|
using Yavsc.Api.Services;
|
||||||
|
|
||||||
|
|
@ -71,6 +72,7 @@ internal class Program
|
||||||
// Binds the "Site" section (Bills, TempDir, Avatars, …) used by
|
// Binds the "Site" section (Bills, TempDir, Avatars, …) used by
|
||||||
// the document-generation flow and BillingController.
|
// the document-generation flow and BillingController.
|
||||||
services.Configure<SiteSettings>(builder.Configuration.GetSection("Site"));
|
services.Configure<SiteSettings>(builder.Configuration.GetSection("Site"));
|
||||||
|
services.Configure<SmtpSettings>(builder.Configuration.GetSection("Smtp"));
|
||||||
services.AddPodcasts(builder.Configuration);
|
services.AddPodcasts(builder.Configuration);
|
||||||
services.AddInvoicing(builder.Configuration);
|
services.AddInvoicing(builder.Configuration);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,12 @@ namespace Yavsc.Services
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
logger.LogInformation($"SendEmail for {email} : {subject}");
|
logger.LogInformation($"SendEmail for {email} : {subject}");
|
||||||
|
if (string.IsNullOrWhiteSpace(siteSettings?.Owner?.EMail)
|
||||||
|
|| string.IsNullOrWhiteSpace(smtpSettings?.Host))
|
||||||
|
{
|
||||||
|
logger.LogError("Email not sent: mail configuration is incomplete (Site:Owner:EMail and Smtp:Host are required). To={To}, Subject={Subject}", email, subject);
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
MimeMessage msg = new();
|
MimeMessage msg = new();
|
||||||
msg.From.Add(BuildMailboxAddress(siteSettings.Owner.Name, siteSettings.Owner.EMail));
|
msg.From.Add(BuildMailboxAddress(siteSettings.Owner.Name, siteSettings.Owner.EMail));
|
||||||
msg.To.Add(BuildMailboxAddress(name, email));
|
msg.To.Add(BuildMailboxAddress(name, email));
|
||||||
|
|
@ -139,7 +145,7 @@ namespace Yavsc.Services
|
||||||
}
|
}
|
||||||
catch (FormatException ex)
|
catch (FormatException ex)
|
||||||
{
|
{
|
||||||
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);
|
||||||
logger.LogError(ex.Message);
|
logger.LogError(ex.Message);
|
||||||
if (ex.InnerException!=null)
|
if (ex.InnerException!=null)
|
||||||
logger.LogError(ex.InnerException.Message);
|
logger.LogError(ex.InnerException.Message);
|
||||||
|
|
|
||||||
|
|
@ -121,6 +121,22 @@ namespace Yavsc.Org.Tests
|
||||||
Assert.Equal(string.Empty, result);
|
Assert.Equal(string.Empty, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task SendEmailAsync_skips_when_owner_is_not_configured()
|
||||||
|
{
|
||||||
|
var factory = new RejectingSmtpClientFactory();
|
||||||
|
var sender = new MailSender(
|
||||||
|
Options.Create(new SiteSettings { Authority = "example.com" }),
|
||||||
|
Options.Create(new SmtpSettings()),
|
||||||
|
NullLoggerFactory.Instance,
|
||||||
|
new TestStringLocalizer(),
|
||||||
|
factory);
|
||||||
|
|
||||||
|
var result = await sender.SendEmailAsync("Alice", "alice@example.com", "Rdv", "hello");
|
||||||
|
|
||||||
|
Assert.Equal(string.Empty, result);
|
||||||
|
}
|
||||||
|
|
||||||
private sealed class RejectingSmtpClientFactory : ISmtpClientFactory
|
private sealed class RejectingSmtpClientFactory : ISmtpClientFactory
|
||||||
{
|
{
|
||||||
public Yavsc.Interfaces.ISmtpClient CreateClient() => new RejectingSmtpClient();
|
public Yavsc.Interfaces.ISmtpClient CreateClient() => new RejectingSmtpClient();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue