Improved mail template service, added advanced emailsender

This commit is contained in:
Mia Rose Winter 2024-02-13 21:47:24 +01:00
parent 336e18d4e1
commit 46a621cc38
Signed by: miawinter
GPG key ID: 4B6F6A83178F595E
6 changed files with 53 additions and 32 deletions

View file

@ -5,7 +5,6 @@
@using Wave.Data @using Wave.Data
@using System.ComponentModel.DataAnnotations @using System.ComponentModel.DataAnnotations
@using System.Net @using System.Net
@using Microsoft.AspNetCore.Identity.UI.Services
@using Microsoft.EntityFrameworkCore @using Microsoft.EntityFrameworkCore
@using Wave.Services @using Wave.Services
@ -15,7 +14,7 @@
@inject IOptions<Features> Features @inject IOptions<Features> Features
@inject IOptions<Customization> Customizations @inject IOptions<Customization> Customizations
@inject NavigationManager Navigation @inject NavigationManager Navigation
@inject IEmailSender EmailSender @inject IAdvancedEmailSender EmailSender
@inject EmailTemplateService TemplateService @inject EmailTemplateService TemplateService
<PageTitle>@(TitlePrefix + Localizer["Title"])</PageTitle> <PageTitle>@(TitlePrefix + Localizer["Title"])</PageTitle>
@ -80,7 +79,10 @@
subscriber.Unsubscribed = false; subscriber.Unsubscribed = false;
await context.SaveChangesAsync(); await context.SaveChangesAsync();
await TemplateService.ValidateTokensAsync(Id, Token, deleteToken: true);
Message = Localizer["Success_Message"]; Message = Localizer["Success_Message"];
} catch (Exception ex) { } catch (Exception ex) {
Logger.LogError(ex, "Error trying to confirm subscriber."); Logger.LogError(ex, "Error trying to confirm subscriber.");
Message = Localizer["Failure_Message"]; Message = Localizer["Failure_Message"];
@ -111,17 +113,10 @@
string confirmLink = Navigation.ToAbsoluteUri( string confirmLink = Navigation.ToAbsoluteUri(
$"/Email/Confirm?user={WebUtility.UrlEncode(id)}&token={WebUtility.UrlEncode(token)}").AbsoluteUri; $"/Email/Confirm?user={WebUtility.UrlEncode(id)}&token={WebUtility.UrlEncode(token)}").AbsoluteUri;
string body = string.Format(Localizer["ConfirmEmailBody"], Customizations.Value.AppName) +
var customization = Customizations.Value; $"""<p style="text-align: center"><a href="{confirmLink}">{Localizer["Submit"]}</a></p>""";
string body = TemplateService.Default( await EmailSender.SendDefaultMailAsync(subscriber.Email, subscriber.Name, Localizer["ConfirmEmailSubject"],
Navigation.BaseUri, Localizer["ConfirmEmailTitle"], body);
!string.IsNullOrWhiteSpace(customization.LogoLink) ?
customization.LogoLink :
Navigation.ToAbsoluteUri("/img/logo.png").AbsoluteUri,
Localizer["ConfirmEmailTitle"],
string.Format(Localizer["ConfirmEmailBody"], customization.AppName) +
$"""<p style="text-align: center"><a href="{confirmLink}">{Localizer["Submit"]}</a></p>""");
await EmailSender.SendEmailAsync(subscriber.Email, Localizer["ConfirmEmailSubject"], body);
} }
} catch (Exception ex) { } catch (Exception ex) {
Logger.LogError(ex, "Failed to create subscriber/send confirmation mail."); Logger.LogError(ex, "Failed to create subscriber/send confirmation mail.");

View file

@ -122,6 +122,7 @@
if (smtpConfig.Exists()) { if (smtpConfig.Exists()) {
builder.Services.Configure<SmtpConfiguration>(smtpConfig); builder.Services.Configure<SmtpConfiguration>(smtpConfig);
builder.Services.AddScoped<IEmailSender, SmtpEmailSender>(); builder.Services.AddScoped<IEmailSender, SmtpEmailSender>();
builder.Services.AddScoped<IAdvancedEmailSender, SmtpEmailSender>();
builder.Services.AddScoped<IEmailSender<ApplicationUser>, SmtpEmailSender>(); builder.Services.AddScoped<IEmailSender<ApplicationUser>, SmtpEmailSender>();
} else { } else {
builder.Services.AddSingleton<IEmailSender<ApplicationUser>, IdentityNoOpEmailSender>(); builder.Services.AddSingleton<IEmailSender<ApplicationUser>, IdentityNoOpEmailSender>();

View file

@ -0,0 +1,8 @@
using Microsoft.AspNetCore.Identity.UI.Services;
namespace Wave.Services;
public interface IAdvancedEmailSender : IEmailSender {
Task SendEmailAsync(string email, string? name, string subject, string htmlMessage);
Task SendDefaultMailAsync(string receiverMail, string? receiverName, string subject, string title, string bodyHtml);
}

View file

@ -81,18 +81,12 @@ public class EmailBackgroundWorker(ILogger<EmailBackgroundWorker> logger, IDbCon
newsletter.IsSend = true; newsletter.IsSend = true;
context.SaveChanges(); context.SaveChanges();
string articleLink = ArticleUtilities.GenerateArticleLink( string articleLink = ArticleUtilities.GenerateArticleLink(newsletter.Article, new Uri(Customizations.AppUrl, UriKind.Absolute));
newsletter.Article, new Uri(Customizations.AppUrl, UriKind.Absolute)); string template = TemplateService.Newsletter(host.AbsoluteUri, articleLink,
string template = TemplateService.Process("newsletter", new Dictionary<EmailTemplateService.Constants, object?>{ (!string.IsNullOrWhiteSpace(Customizations.LogoLink) ?
{EmailTemplateService.Constants.BrowserLink, articleLink}, new Uri(Customizations.LogoLink) :
{EmailTemplateService.Constants.ContentLogo, (!string.IsNullOrWhiteSpace(Customizations.LogoLink) ? new Uri(host, "/img/logo.png")).AbsoluteUri, newsletter.Article.Title, newsletter.Article.BodyHtml,
new Uri(Customizations.LogoLink) : "[[<__UNSUBSCRIBE__>]]");
new Uri(host, "/img/logo.png"))
.AbsoluteUri},
{EmailTemplateService.Constants.ContentTitle, newsletter.Article.Title},
{EmailTemplateService.Constants.ContentBody, newsletter.Article.BodyHtml},
{EmailTemplateService.Constants.EmailUnsubscribeLink, "[[<__UNSUBSCRIBE__>]]"}
});
var message = new MimeMessage { var message = new MimeMessage {
From = { sender }, From = { sender },

View file

@ -42,15 +42,26 @@ public enum Constants {
} }
public string Default(string url, string logoLink, string title, string body) { public string Default(string home, string logoLink, string title, string body) {
return Process("default", new Dictionary<Constants, object?> { return Process("default", new Dictionary<Constants, object?> {
{Constants.HomeLink, url}, {Constants.HomeLink, home},
{Constants.ContentLogo, logoLink}, {Constants.ContentLogo, logoLink},
{Constants.ContentTitle, title}, {Constants.ContentTitle, title},
{Constants.ContentBody, body} {Constants.ContentBody, body}
}); });
} }
public string Newsletter(string home, string browserUrl, string logoLink, string title, string body, string unsubscribe) {
return Process("newsletter", new Dictionary<Constants, object?> {
{ Constants.HomeLink, home },
{ Constants.BrowserLink, browserUrl },
{ Constants.ContentLogo, logoLink },
{ Constants.ContentTitle, title },
{ Constants.ContentBody, body },
{ Constants.EmailUnsubscribeLink, unsubscribe }
});
}
public void TryCreateDefaultTemplates() { public void TryCreateDefaultTemplates() {
FileSystem.GetEmailTemplate("default", DefaultTemplates["default"]); FileSystem.GetEmailTemplate("default", DefaultTemplates["default"]);
FileSystem.GetEmailTemplate("newsletter", DefaultTemplates["newsletter"]); FileSystem.GetEmailTemplate("newsletter", DefaultTemplates["newsletter"]);

View file

@ -1,18 +1,20 @@
using MailKit.Net.Smtp; using MailKit.Net.Smtp;
using MailKit.Security; using MailKit.Security;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using MimeKit; using MimeKit;
using Wave.Data; using Wave.Data;
using Uri = System.Uri;
namespace Wave.Services; namespace Wave.Services;
public class SmtpEmailSender(IOptions<SmtpConfiguration> config, ILogger<SmtpEmailSender> logger) : IEmailSender<ApplicationUser>, IEmailSender { public class SmtpEmailSender(ILogger<SmtpEmailSender> logger, IOptions<SmtpConfiguration> config, IOptions<Customization> customizations, EmailTemplateService templateService) : IEmailSender<ApplicationUser>, IAdvancedEmailSender {
private ILogger<SmtpEmailSender> Logger { get; } = logger;
private SmtpConfiguration Configuration { get; } = config.Value; private SmtpConfiguration Configuration { get; } = config.Value;
private ILogger<SmtpEmailSender> Logger { get; } = logger; private Customization Customizations { get; } = customizations.Value;
private EmailTemplateService TemplateService { get; } = templateService;
public Task SendConfirmationLinkAsync(ApplicationUser user, string email, string confirmationLink) =>
public Task SendConfirmationLinkAsync(ApplicationUser user, string email, string confirmationLink) =>
SendEmailAsync(email, "Confirm your email", SendEmailAsync(email, "Confirm your email",
$"Please confirm your account by <a href='{confirmationLink}'>clicking here</a>."); $"Please confirm your account by <a href='{confirmationLink}'>clicking here</a>.");
@ -56,11 +58,21 @@ public class SmtpEmailSender(IOptions<SmtpConfiguration> config, ILogger<SmtpEma
throw new EmailNotSendException("Failed Email send.", ex); throw new EmailNotSendException("Failed Email send.", ex);
} }
await client.DisconnectAsync(true); await client.DisconnectAsync(true);
Logger.LogInformation("Successfully send mail to {email} (subject: {subject}).", email, subject);
} catch (Exception ex) { } catch (Exception ex) {
Logger.LogError(ex, "Error sending E-Mail"); Logger.LogError(ex, "Error sending E-Mail");
throw; throw;
} }
} }
public Task SendDefaultMailAsync(string receiverMail, string? receiverName, string subject, string title, string bodyHtml) {
var host = new Uri(string.IsNullOrWhiteSpace(Customizations.AppUrl) ? "" : Customizations.AppUrl);
string logo = !string.IsNullOrWhiteSpace(Customizations.LogoLink)
? Customizations.LogoLink
: new Uri(host, "/img/logo.png").AbsoluteUri;
string body = TemplateService.Default(host.AbsoluteUri, logo, title, bodyHtml);
return SendEmailAsync(receiverMail, receiverName, subject, body);
}
} }
public class EmailNotSendException(string message, Exception exception) : ApplicationException(message, exception); public class EmailNotSendException(string message, Exception exception) : ApplicationException(message, exception);