diff --git a/src/BuildingBlocks/Mailing/HtmlEmail.cs b/src/BuildingBlocks/Mailing/HtmlEmail.cs
new file mode 100644
index 0000000000..d09621008a
--- /dev/null
+++ b/src/BuildingBlocks/Mailing/HtmlEmail.cs
@@ -0,0 +1,110 @@
+using System.Net;
+
+namespace FSH.Framework.Mailing;
+
+///
+
|
+
{safeIntro}
++ {safeLabel} +
+
+ If the button does not work, copy this address into your browser:
+ {safeUrl}
+
{Encode(message)}
"""); + } +} diff --git a/src/Modules/Identity/Modules.Identity/Events/UserRegisteredEmailHandler.cs b/src/Modules/Identity/Modules.Identity/Events/UserRegisteredEmailHandler.cs index b123831eca..c995d01366 100644 --- a/src/Modules/Identity/Modules.Identity/Events/UserRegisteredEmailHandler.cs +++ b/src/Modules/Identity/Modules.Identity/Events/UserRegisteredEmailHandler.cs @@ -2,7 +2,6 @@ using FSH.Framework.Mailing; using FSH.Framework.Mailing.Services; using FSH.Modules.Identity.Contracts.Events; -using FSH.Modules.Identity.Services; using Microsoft.Extensions.Logging; namespace FSH.Modules.Identity.Events; @@ -41,7 +40,7 @@ public async Task HandleAsync(UserRegisteredIntegrationEvent @event, Cancellatio var mail = new MailRequest( to: new System.Collections.ObjectModel.Collection
-
|
-
-
|
-
Hi {Escape(tenantName)},
" + - $"Your {Escape(plan)} subscription is valid until " + + $"
Hi {HtmlEmail.Encode(tenantName)},
" + + $"Your {HtmlEmail.Encode(plan)} subscription is valid until " + $"{Date(validUpto)} ({daysRemaining} day(s) remaining).
" + "Please contact your account operator to renew and avoid any interruption to your service.
"); var text = Text(subject, @@ -35,8 +37,8 @@ public static (string Subject, string Body, string TextBody) EnteredGrace(string const string subject = "Your subscription has lapsed — grace period active"; var plan = planKey ?? "current"; var body = Wrap(subject, - $"Hi {Escape(tenantName)},
" + - $"Your {Escape(plan)} subscription expired on " + + $"
Hi {HtmlEmail.Encode(tenantName)},
" + + $"Your {HtmlEmail.Encode(plan)} subscription expired on " + $"{Date(validUpto)}. Your service continues during a grace period that ends on " + $"{Date(graceEnds)}.
" + "Please renew before the grace period ends to keep your access uninterrupted.
"); @@ -52,8 +54,8 @@ public static (string Subject, string Body, string TextBody) Expired(string tena const string subject = "Your subscription has expired"; var plan = planKey ?? "current"; var body = Wrap(subject, - $"Hi {Escape(tenantName)},
" + - $"Your {Escape(plan)} subscription expired on " + + $"
Hi {HtmlEmail.Encode(tenantName)},
" + + $"Your {HtmlEmail.Encode(plan)} subscription expired on " + $"{Date(validUpto)} and the grace period has ended, so access is now suspended.
" + "Contact your account operator to renew and restore access.
"); var text = Text(subject, @@ -69,7 +71,9 @@ public static (string Subject, string Body, string TextBody) InvoiceIssued(strin var amountText = $"{amount.ToString("0.00", CultureInfo.InvariantCulture)} {currency}"; var due = dueAtUtc is null ? string.Empty : $"Due by {Date(dueAtUtc.Value)}.
"; var body = Wrap(subject, - $"A new invoice {Escape(invoiceNumber)} for {amountText} has been issued.
" + + // amountText embeds the currency, which is data rather than a literal, so it is encoded + // for the HTML part while the text/plain twin below keeps it verbatim. + $"A new invoice {HtmlEmail.Encode(invoiceNumber)} for {HtmlEmail.Encode(amountText)} has been issued.
" + due + "You can view and download this invoice from your dashboard.
"); var text = Text(subject, @@ -79,12 +83,17 @@ public static (string Subject, string Body, string TextBody) InvoiceIssued(strin return (subject, body, text); } + ///This is an automated message.
" + - "This is an automated message.
" + + "