diff --git a/src/Yavsc.Org.Tests/Directory.Packages.props b/src/Yavsc.Org.Tests/Directory.Packages.props
index b267eafe..5927d2b5 100644
--- a/src/Yavsc.Org.Tests/Directory.Packages.props
+++ b/src/Yavsc.Org.Tests/Directory.Packages.props
@@ -7,7 +7,5 @@
-
-
diff --git a/src/Yavsc.Org.Tests/NonRegression/EMailling.cs b/src/Yavsc.Org.Tests/NonRegression/EMailling.cs
index 743dbbc1..5b1b33e9 100644
--- a/src/Yavsc.Org.Tests/NonRegression/EMailling.cs
+++ b/src/Yavsc.Org.Tests/NonRegression/EMailling.cs
@@ -55,5 +55,6 @@ namespace Yavsc.Org.Tests
client.Calls.Select(c => c.Kind).ToArray());
Assert.Equal(_serverFixture.SiteSettings.Owner.EMail, client.LastSentMessage?.To.Mailboxes.First().Address);
}
+
}
}
diff --git a/src/Yavsc.Org/Directory.Packages.props b/src/Yavsc.Org/Directory.Packages.props
index fd16374b..d9925e02 100644
--- a/src/Yavsc.Org/Directory.Packages.props
+++ b/src/Yavsc.Org/Directory.Packages.props
@@ -20,6 +20,5 @@
-
diff --git a/src/Yavsc.Server/Services/MailSender.cs b/src/Yavsc.Server/Services/MailSender.cs
index 3192d4c7..d8b3c46c 100644
--- a/src/Yavsc.Server/Services/MailSender.cs
+++ b/src/Yavsc.Server/Services/MailSender.cs
@@ -9,6 +9,7 @@ using Yavsc.Settings;
using Yavsc.Models;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.Extensions.Localization;
+using System.Text.RegularExpressions;
using System.Web;
namespace Yavsc.Services
@@ -56,42 +57,93 @@ namespace Yavsc.Services
return SendEmailAsync(null, email, subject, htmlMessage);
}
+ internal static MailboxAddress BuildMailboxAddress(string? displayName, string? rawAddress)
+ {
+ if (string.IsNullOrWhiteSpace(rawAddress))
+ {
+ throw new FormatException("Email address is empty.");
+ }
+
+ var candidate = rawAddress.Trim();
+ if (candidate.Contains('<') || candidate.Contains('>'))
+ {
+ var emailMatch = Regex.Match(candidate,
+ @"[A-Za-z0-9.!#$%&'*+/=?^_`{|}~-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}",
+ RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
+
+ if (emailMatch.Success)
+ {
+ candidate = emailMatch.Value;
+ }
+ else
+ {
+ candidate = candidate.Trim('<', '>', '"', '\'');
+ }
+ }
+
+ candidate = candidate.Trim('"', '\'', '<', '>', ' ');
+ candidate = candidate.Replace(" ", string.Empty);
+
+ if (!MailboxAddress.TryParse(candidate, out var parsedAddress))
+ {
+ throw new FormatException($"Invalid email address '{rawAddress}'.");
+ }
+
+ var safeName = string.IsNullOrWhiteSpace(displayName)
+ ? parsedAddress.Name
+ : displayName.Trim();
+
+ return new MailboxAddress(safeName ?? string.Empty, parsedAddress.Address);
+ }
+
public async Task SendEmailAsync(string name, string email, string subject, string htmlMessage)
{
- logger.LogInformation($"SendEmail for {email} : {subject}");
- MimeMessage msg = new();
- msg.From.Add(new MailboxAddress(siteSettings.Owner.Name,
- siteSettings.Owner.EMail));
- msg.To.Add(new MailboxAddress(name, email));
- TextPart text;
- msg.Body = text = new TextPart("html")
+ try
{
- Text = $"{htmlMessage}"
- };
-
- msg.Subject = subject;
- msg.MessageId = MimeKit.Utils.MimeUtils.GenerateMessageId(
- siteSettings.Authority
- );
- using ISmtpClient sc = _smtpClientFactory.CreateClient();
- {
- sc.Timeout = 30000;
- sc.Connect(
- smtpSettings.Host,
- smtpSettings.Port,
- SecureSocketOptions.Auto
- );
-
- if (smtpSettings.UserName != null)
+ logger.LogInformation($"SendEmail for {email} : {subject}");
+ MimeMessage msg = new();
+ msg.From.Add(BuildMailboxAddress(siteSettings.Owner.Name, siteSettings.Owner.EMail));
+ msg.To.Add(BuildMailboxAddress(name, email));
+ TextPart text;
+ msg.Body = text = new TextPart("html")
{
- sc.Authenticate(smtpSettings.UserName, smtpSettings.Password);
- }
+ Text = $"{htmlMessage}"
+ };
- await sc.SendAsync(msg);
- logger.LogInformation($"Sent : {msg.MessageId}");
- sc.Disconnect(true);
+ msg.Subject = subject;
+ msg.MessageId = MimeKit.Utils.MimeUtils.GenerateMessageId(
+ siteSettings.Authority
+ );
+ using ISmtpClient sc = _smtpClientFactory.CreateClient();
+ {
+ sc.Timeout = 30000;
+ sc.Connect(
+ smtpSettings.Host,
+ smtpSettings.Port,
+ SecureSocketOptions.Auto
+ );
+
+ if (smtpSettings.UserName != null)
+ {
+ sc.Authenticate(smtpSettings.UserName, smtpSettings.Password);
+ }
+
+ await sc.SendAsync(msg);
+ logger.LogInformation($"Sent : {msg.MessageId}");
+ sc.Disconnect(true);
+ }
+ return msg.MessageId;
+ }
+ 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);
+ return string.Empty;
+ }
+ catch (Exception ex)
+ {
+ logger.LogError(ex, "Failed to send email. To={To}, Subject={Subject}", email, subject);
+ throw;
}
- return msg.MessageId;
}
public void SendEmailFromCriteria(string Criteria)