From 6381885d00ad4c60640f03478f4306fa9eaf3d4d Mon Sep 17 00:00:00 2001 From: Benedek Farkas Date: Tue, 15 Oct 2024 14:25:32 +0200 Subject: [PATCH 1/5] Email.Azure: Deconstructing email addresses that include a display name (#16888) --- .../Services/AzureEmailProviderBase.cs | 41 ++++++++++++++++--- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Email.Azure/Services/AzureEmailProviderBase.cs b/src/OrchardCore.Modules/OrchardCore.Email.Azure/Services/AzureEmailProviderBase.cs index ae02404f1f1..42c0c2fca6f 100644 --- a/src/OrchardCore.Modules/OrchardCore.Email.Azure/Services/AzureEmailProviderBase.cs +++ b/src/OrchardCore.Modules/OrchardCore.Email.Azure/Services/AzureEmailProviderBase.cs @@ -1,3 +1,4 @@ +using System.Text.RegularExpressions; using Azure; using Azure.Communication.Email; using Microsoft.Extensions.Localization; @@ -161,19 +162,19 @@ private EmailMessage FromMailMessage(MailMessage message, Dictionary toRecipients = null; if (recipients.To.Count > 0) { - toRecipients = [.. recipients.To.Select(r => new EmailAddress(r))]; + toRecipients = [.. recipients.To.Select(ToAzureEmailAddress)]; } List ccRecipients = null; if (recipients.Cc.Count > 0) { - ccRecipients = [.. recipients.Cc.Select(r => new EmailAddress(r))]; + ccRecipients = [.. recipients.Cc.Select(ToAzureEmailAddress)]; } List bccRecipients = null; if (recipients.Bcc.Count > 0) { - bccRecipients = [.. recipients.Bcc.Select(r => new EmailAddress(r))]; + bccRecipients = [.. recipients.Bcc.Select(ToAzureEmailAddress)]; } var content = new EmailContent(message.Subject); @@ -187,13 +188,14 @@ private EmailMessage FromMailMessage(MailMessage message, Dictionary[^<]*)\s)?<(?[^>]+)>$")] + public static partial Regex ParseEmailAddressWithDisplayNameRegex(); } From e0478e89c067e8edf61e8b668efe82e69fb7533a Mon Sep 17 00:00:00 2001 From: Benedek Farkas Date: Tue, 15 Oct 2024 17:02:27 +0200 Subject: [PATCH 2/5] Renaming ToAzureEmailAddress to ConvertEmailAddressToAzureEmailAddress --- .../Services/AzureEmailProviderBase.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Email.Azure/Services/AzureEmailProviderBase.cs b/src/OrchardCore.Modules/OrchardCore.Email.Azure/Services/AzureEmailProviderBase.cs index 42c0c2fca6f..adc6f562ccf 100644 --- a/src/OrchardCore.Modules/OrchardCore.Email.Azure/Services/AzureEmailProviderBase.cs +++ b/src/OrchardCore.Modules/OrchardCore.Email.Azure/Services/AzureEmailProviderBase.cs @@ -162,19 +162,19 @@ private EmailMessage FromMailMessage(MailMessage message, Dictionary toRecipients = null; if (recipients.To.Count > 0) { - toRecipients = [.. recipients.To.Select(ToAzureEmailAddress)]; + toRecipients = [.. recipients.To.Select(ConvertEmailAddressToAzureEmailAddress)]; } List ccRecipients = null; if (recipients.Cc.Count > 0) { - ccRecipients = [.. recipients.Cc.Select(ToAzureEmailAddress)]; + ccRecipients = [.. recipients.Cc.Select(ConvertEmailAddressToAzureEmailAddress)]; } List bccRecipients = null; if (recipients.Bcc.Count > 0) { - bccRecipients = [.. recipients.Bcc.Select(ToAzureEmailAddress)]; + bccRecipients = [.. recipients.Bcc.Select(ConvertEmailAddressToAzureEmailAddress)]; } var content = new EmailContent(message.Subject); @@ -195,7 +195,7 @@ private EmailMessage FromMailMessage(MailMessage message, Dictionary Date: Tue, 15 Oct 2024 19:23:46 +0200 Subject: [PATCH 3/5] Using MailAddress.TryParse to deconstruct the email string Co-authored-by: Georg von Kries --- .../Services/AzureEmailProviderBase.cs | 26 +++++-------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Email.Azure/Services/AzureEmailProviderBase.cs b/src/OrchardCore.Modules/OrchardCore.Email.Azure/Services/AzureEmailProviderBase.cs index adc6f562ccf..0c974abfa49 100644 --- a/src/OrchardCore.Modules/OrchardCore.Email.Azure/Services/AzureEmailProviderBase.cs +++ b/src/OrchardCore.Modules/OrchardCore.Email.Azure/Services/AzureEmailProviderBase.cs @@ -1,4 +1,4 @@ -using System.Text.RegularExpressions; +using System.Net.Mail; using Azure; using Azure.Communication.Email; using Microsoft.Extensions.Localization; @@ -189,7 +189,7 @@ private EmailMessage FromMailMessage(MailMessage message, Dictionary[^<]*)\s)?<(?[^>]+)>$")] - public static partial Regex ParseEmailAddressWithDisplayNameRegex(); -} From f4b89e20ccddacd35fe688a31d90d535b3fc7a3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Ros?= Date: Thu, 17 Oct 2024 10:37:44 -0700 Subject: [PATCH 4/5] Change method name --- .../Services/AzureEmailProviderBase.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Email.Azure/Services/AzureEmailProviderBase.cs b/src/OrchardCore.Modules/OrchardCore.Email.Azure/Services/AzureEmailProviderBase.cs index 0c974abfa49..4edf7dc0267 100644 --- a/src/OrchardCore.Modules/OrchardCore.Email.Azure/Services/AzureEmailProviderBase.cs +++ b/src/OrchardCore.Modules/OrchardCore.Email.Azure/Services/AzureEmailProviderBase.cs @@ -189,7 +189,7 @@ private EmailMessage FromMailMessage(MailMessage message, Dictionary Date: Thu, 24 Oct 2024 15:58:53 +0200 Subject: [PATCH 5/5] More robust error handling in AzureEmailProviderBase --- .../Services/AzureEmailProvider.cs | 3 +- .../Services/AzureEmailProviderBase.cs | 85 +++++++++++-------- .../Services/DefaultAzureEmailProvider.cs | 3 +- 3 files changed, 51 insertions(+), 40 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Email.Azure/Services/AzureEmailProvider.cs b/src/OrchardCore.Modules/OrchardCore.Email.Azure/Services/AzureEmailProvider.cs index f1d444b2310..e5891bddafa 100644 --- a/src/OrchardCore.Modules/OrchardCore.Email.Azure/Services/AzureEmailProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Email.Azure/Services/AzureEmailProvider.cs @@ -11,10 +11,9 @@ public class AzureEmailProvider : AzureEmailProviderBase public AzureEmailProvider( IOptions options, - IEmailAddressValidator emailAddressValidator, ILogger logger, IStringLocalizer stringLocalizer) - : base(options.Value, emailAddressValidator, logger, stringLocalizer) + : base(options.Value, logger, stringLocalizer) { } diff --git a/src/OrchardCore.Modules/OrchardCore.Email.Azure/Services/AzureEmailProviderBase.cs b/src/OrchardCore.Modules/OrchardCore.Email.Azure/Services/AzureEmailProviderBase.cs index 4edf7dc0267..f71114ad43c 100644 --- a/src/OrchardCore.Modules/OrchardCore.Email.Azure/Services/AzureEmailProviderBase.cs +++ b/src/OrchardCore.Modules/OrchardCore.Email.Azure/Services/AzureEmailProviderBase.cs @@ -79,7 +79,6 @@ public abstract class AzureEmailProviderBase : IEmailProvider }; private readonly AzureEmailOptions _providerOptions; - private readonly IEmailAddressValidator _emailAddressValidator; private readonly ILogger _logger; private EmailClient _emailClient; @@ -88,12 +87,10 @@ public abstract class AzureEmailProviderBase : IEmailProvider public AzureEmailProviderBase( AzureEmailOptions options, - IEmailAddressValidator emailAddressValidator, ILogger logger, IStringLocalizer stringLocalizer) { _providerOptions = options; - _emailAddressValidator = emailAddressValidator; _logger = logger; S = stringLocalizer; } @@ -117,12 +114,15 @@ public virtual async Task SendAsync(MailMessage message) if (!string.IsNullOrWhiteSpace(senderAddress)) { - if (!_emailAddressValidator.Validate(senderAddress)) + if (MailAddress.TryCreate(senderAddress, out var senderMailAddress)) + { + // For compatibility with configuration for other providers that allow a sender with display name. + message.From = senderMailAddress.Address; + } + else { return EmailResult.FailedResult(nameof(message.From), S["Invalid email address for the sender: '{0}'.", senderAddress]); } - - message.From = senderAddress; } var errors = new Dictionary>(); @@ -150,7 +150,7 @@ public virtual async Task SendAsync(MailMessage message) { _logger.LogError(ex, "An error occurred while sending an email using the Azure Email Provider."); - // IMPORTANT, do not expose ex.Message as it could contain the connection string in a raw format! + // IMPORTANT: Do not expose ex.Message as it could contain the connection string in a raw format! return EmailResult.FailedResult(string.Empty, S["An error occurred while sending an email."]); } } @@ -159,22 +159,43 @@ private EmailMessage FromMailMessage(MailMessage message, Dictionary toRecipients = null; - if (recipients.To.Count > 0) + var toRecipients = new List(); + foreach (var toRecipient in recipients.To) { - toRecipients = [.. recipients.To.Select(ConvertEmailAddressToAzureEmailAddress)]; + if (MailAddress.TryCreate(toRecipient, out var toMailAddress)) + { + toRecipients.Add(ConvertMailAddressToAzureEmailAddress(toMailAddress)); + } + else + { + errors[nameof(recipients.To)].Add(S["Invalid email address for the 'To' recipient: '{0}'.", toRecipient]); + } } - List ccRecipients = null; - if (recipients.Cc.Count > 0) + var ccRecipients = new List(); + foreach (var ccRecipient in recipients.Cc) { - ccRecipients = [.. recipients.Cc.Select(ConvertEmailAddressToAzureEmailAddress)]; + if (MailAddress.TryCreate(ccRecipient, out var ccMailAddress)) + { + ccRecipients.Add(ConvertMailAddressToAzureEmailAddress(ccMailAddress)); + } + else + { + errors[nameof(recipients.Cc)].Add(S["Invalid email address for the 'CC' recipient: '{0}'.", ccRecipient]); + } } - List bccRecipients = null; - if (recipients.Bcc.Count > 0) + var bccRecipients = new List(); + foreach (var bccRecipient in recipients.Bcc) { - bccRecipients = [.. recipients.Bcc.Select(ConvertEmailAddressToAzureEmailAddress)]; + if (MailAddress.TryCreate(bccRecipient, out var bccMailAddress)) + { + bccRecipients.Add(ConvertMailAddressToAzureEmailAddress(bccMailAddress)); + } + else + { + errors[nameof(recipients.Bcc)].Add(S["Invalid email address for the 'BCC' recipient: '{0}'.", bccRecipient]); + } } var content = new EmailContent(message.Subject); @@ -188,14 +209,20 @@ private EmailMessage FromMailMessage(MailMessage message, Dictionary + new EmailAddress(mailAddress.Address, mailAddress.DisplayName); } diff --git a/src/OrchardCore.Modules/OrchardCore.Email.Azure/Services/DefaultAzureEmailProvider.cs b/src/OrchardCore.Modules/OrchardCore.Email.Azure/Services/DefaultAzureEmailProvider.cs index 321b18754de..009189cc46c 100644 --- a/src/OrchardCore.Modules/OrchardCore.Email.Azure/Services/DefaultAzureEmailProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Email.Azure/Services/DefaultAzureEmailProvider.cs @@ -11,10 +11,9 @@ public class DefaultAzureEmailProvider : AzureEmailProviderBase public DefaultAzureEmailProvider( IOptions options, - IEmailAddressValidator emailAddressValidator, ILogger logger, IStringLocalizer stringLocalizer) - : base(options.Value, emailAddressValidator, logger, stringLocalizer) + : base(options.Value, logger, stringLocalizer) { }