Added mail template for Welcome emails
This commit is contained in:
parent
52edae5470
commit
fd43ead960
|
@ -7,7 +7,6 @@
|
||||||
@using System.Net
|
@using System.Net
|
||||||
@using Microsoft.EntityFrameworkCore
|
@using Microsoft.EntityFrameworkCore
|
||||||
@using Wave.Services
|
@using Wave.Services
|
||||||
@using Wave.Utilities
|
|
||||||
|
|
||||||
@inject ILogger<EmailSignup> Logger
|
@inject ILogger<EmailSignup> Logger
|
||||||
@inject IStringLocalizer<EmailSignup> Localizer
|
@inject IStringLocalizer<EmailSignup> Localizer
|
||||||
|
@ -82,27 +81,15 @@
|
||||||
Message = Localizer["Success_Message"];
|
Message = Localizer["Success_Message"];
|
||||||
|
|
||||||
await TemplateService.ValidateTokensAsync(Id, Token, deleteToken: true);
|
await TemplateService.ValidateTokensAsync(Id, Token, deleteToken: true);
|
||||||
|
|
||||||
var articles = await context.Set<EmailNewsletter>()
|
var articles = await context.Set<EmailNewsletter>()
|
||||||
.IgnoreAutoIncludes()
|
.IgnoreAutoIncludes()
|
||||||
.Include(a => a.Article).ThenInclude(a => a.Author)
|
.Include(a => a.Article).ThenInclude(a => a.Author)
|
||||||
.OrderByDescending(a => a.DistributionDateTime)
|
.OrderByDescending(a => a.DistributionDateTime)
|
||||||
.Take(3)
|
.Take(3)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
string body = $"<p>{Localizer["WelcomeEmailBody"]}</p>\n";
|
await EmailSender.SendWelcomeMailAsync(subscriber,
|
||||||
|
Localizer["WelcomeEmailSubject"], Localizer["WelcomeEmailTitle"], Localizer["WelcomeEmailBody"], articles);
|
||||||
foreach (var n in articles) {
|
|
||||||
string articleLink = ArticleUtilities.GenerateArticleLink(n.Article, new Uri(Customizations.Value.AppUrl, UriKind.Absolute));
|
|
||||||
body = body +
|
|
||||||
"<div style=\"padding: 10px; background: #333; color: #fff; margin-bottom: 10px\">" +
|
|
||||||
$"<h3>{n.Article.Title}</h3>" +
|
|
||||||
$"<small>{n.Article.Author.Name}</small>" +
|
|
||||||
$"<p>{n.Article.Body[..Math.Min(100, n.Article.Body.Length)]}...</p>" +
|
|
||||||
$"<a href=\"{articleLink}\">Link</a>" +
|
|
||||||
"</div>";
|
|
||||||
}
|
|
||||||
await EmailSender.SendSubscribedMailAsync(subscriber,
|
|
||||||
Localizer["WelcomeEmailSubject"], Localizer["WelcomeEmailTitle"], body, subscribedRole: "welcome");
|
|
||||||
} 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"];
|
||||||
|
|
|
@ -6,7 +6,7 @@ namespace Wave.Services;
|
||||||
|
|
||||||
public partial class EmailTemplateService(ILogger<EmailTemplateService> logger, IDistributedCache tokenCache, FileSystemService fileSystem) {
|
public partial class EmailTemplateService(ILogger<EmailTemplateService> logger, IDistributedCache tokenCache, FileSystemService fileSystem) {
|
||||||
public enum Constants {
|
public enum Constants {
|
||||||
BrowserLink, HomeLink, ContentLogo, ContentTitle, ContentBody, EmailUnsubscribeLink
|
BrowserLink, HomeLink, ContentLogo, ContentTitle, ContentBody, EmailUnsubscribeLink, ArticleRecommendations
|
||||||
}
|
}
|
||||||
|
|
||||||
private ILogger<EmailTemplateService> Logger { get; } = logger;
|
private ILogger<EmailTemplateService> Logger { get; } = logger;
|
||||||
|
@ -62,9 +62,21 @@ public enum Constants {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string Welcome(string home, string logoLink, string title, string body, string unsubscribe, string articles) {
|
||||||
|
return Process("welcome", new Dictionary<Constants, object?> {
|
||||||
|
{ Constants.HomeLink, home },
|
||||||
|
{ Constants.ContentLogo, logoLink },
|
||||||
|
{ Constants.ContentTitle, title },
|
||||||
|
{ Constants.ContentBody, body },
|
||||||
|
{ Constants.EmailUnsubscribeLink, unsubscribe },
|
||||||
|
{ Constants.ArticleRecommendations, articles }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
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"]);
|
||||||
|
FileSystem.GetEmailTemplate("welcome", DefaultTemplates["welcome"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ApplyTokens(string template, Func<string, string?> replacer) {
|
public string ApplyTokens(string template, Func<string, string?> replacer) {
|
||||||
|
@ -189,6 +201,60 @@ public enum Constants {
|
||||||
</mj-body>
|
</mj-body>
|
||||||
</mjml>
|
</mjml>
|
||||||
"""
|
"""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"welcome",
|
||||||
|
$"""
|
||||||
|
<mjml>
|
||||||
|
<mj-head>
|
||||||
|
<mj-preview />
|
||||||
|
</mj-head>
|
||||||
|
<mj-body>
|
||||||
|
<mj-section direction="rtl" padding-bottom="5px" padding-left="0px" padding-right="0px" padding-top="15px" padding="15px 0px 5px 0px">
|
||||||
|
<mj-column vertical-align="middle" width="33%">
|
||||||
|
<mj-image align="center" alt="" border-radius="0" border="none" container-background-color="transparent" height="auto" padding-bottom="5px" padding-left="5px" padding-right="5px" padding-top="5px" padding="5px 5px 5px 5px" href="[[{Constants.HomeLink}]]" src="[[{Constants.ContentLogo}]]"></mj-image>
|
||||||
|
</mj-column>
|
||||||
|
<mj-column vertical-align="middle" width="67%">
|
||||||
|
<mj-text font-size="13px" font-family="Ubuntu,Verdana">
|
||||||
|
<h1>[[{Constants.ContentTitle}]]</h1>
|
||||||
|
</mj-text>
|
||||||
|
</mj-column>
|
||||||
|
</mj-section>
|
||||||
|
<mj-section padding-top="5px" padding-bottom="5px" padding="5px 0 5px 0">
|
||||||
|
<mj-column>
|
||||||
|
<mj-divider border-color="#9f9f9f" border-width="1px"></mj-divider>
|
||||||
|
</mj-column>
|
||||||
|
</mj-section>
|
||||||
|
<mj-section>
|
||||||
|
<mj-column>
|
||||||
|
<mj-text color="#55575d" font-size="13px" font-family="Ubuntu,Verdana">[[{Constants.ContentBody}]]</mj-text>
|
||||||
|
</mj-column>
|
||||||
|
</mj-section>
|
||||||
|
<mj-section padding-top="5px" padding-bottom="5px" padding="5px 0 5px 0">
|
||||||
|
<mj-column>
|
||||||
|
<mj-divider border-color="#9f9f9f" border-width="1px"></mj-divider>
|
||||||
|
</mj-column>
|
||||||
|
</mj-section>
|
||||||
|
<mj-section>
|
||||||
|
<mj-column>
|
||||||
|
<mj-text color="#55575d" font-size="13px" font-family="Ubuntu,Verdana">[[{Constants.ArticleRecommendations}]]</mj-text>
|
||||||
|
</mj-column>
|
||||||
|
</mj-section>
|
||||||
|
<mj-section padding-top="5px" padding-bottom="5px" padding="5px 0 5px 0">
|
||||||
|
<mj-column>
|
||||||
|
<mj-divider border-color="#9f9f9f" border-width="1px"></mj-divider>
|
||||||
|
</mj-column>
|
||||||
|
</mj-section>
|
||||||
|
<mj-section>
|
||||||
|
<mj-column>
|
||||||
|
<mj-text align="center" font-size="13px" font-family="Ubuntu,Verdana">
|
||||||
|
<a href="[[{Constants.EmailUnsubscribeLink}]]">Unsubscribe</a>
|
||||||
|
</mj-text>
|
||||||
|
</mj-column>
|
||||||
|
</mj-section>
|
||||||
|
</mj-body>
|
||||||
|
</mjml>
|
||||||
|
"""
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -8,4 +8,6 @@ public interface IAdvancedEmailSender : IEmailSender {
|
||||||
Task SendDefaultMailAsync(string receiverMail, string? receiverName, string subject, string title, string bodyHtml);
|
Task SendDefaultMailAsync(string receiverMail, string? receiverName, string subject, string title, string bodyHtml);
|
||||||
Task SendSubscribedMailAsync(EmailSubscriber subscriber, string subject, string title, string bodyHtml,
|
Task SendSubscribedMailAsync(EmailSubscriber subscriber, string subject, string title, string bodyHtml,
|
||||||
string browserUrl = "", string subscribedRole = "-1");
|
string browserUrl = "", string subscribedRole = "-1");
|
||||||
|
Task SendWelcomeMailAsync(EmailSubscriber subscriber, string subject, string title, string bodyHtml,
|
||||||
|
IEnumerable<EmailNewsletter> articles);
|
||||||
}
|
}
|
|
@ -1,10 +1,12 @@
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Text;
|
||||||
using MailKit.Net.Smtp;
|
using MailKit.Net.Smtp;
|
||||||
using MailKit.Security;
|
using MailKit.Security;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using MimeKit;
|
using MimeKit;
|
||||||
using Wave.Data;
|
using Wave.Data;
|
||||||
|
using Wave.Utilities;
|
||||||
using Uri = System.Uri;
|
using Uri = System.Uri;
|
||||||
|
|
||||||
namespace Wave.Services;
|
namespace Wave.Services;
|
||||||
|
@ -97,6 +99,38 @@ public Task SendEmailAsync(string email, string? name, string subject, string ht
|
||||||
new Header(HeaderId.ListUnsubscribe, $"<{unsubscribeLink}>"),
|
new Header(HeaderId.ListUnsubscribe, $"<{unsubscribeLink}>"),
|
||||||
new Header(HeaderId.ListUnsubscribePost, "One-Click"));
|
new Header(HeaderId.ListUnsubscribePost, "One-Click"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task SendWelcomeMailAsync(EmailSubscriber subscriber, string subject, string title, string bodyHtml,
|
||||||
|
IEnumerable<EmailNewsletter> articles) {
|
||||||
|
(string user, string token) = await TemplateService
|
||||||
|
.CreateConfirmTokensAsync(subscriber.Id, "unsubscribe-welcome", TimeSpan.FromDays(30));
|
||||||
|
var host = new Uri(string.IsNullOrWhiteSpace(Customizations.AppUrl) ? "" : Customizations.AppUrl); // TODO get link
|
||||||
|
|
||||||
|
var articlesHtml = new StringBuilder("");
|
||||||
|
foreach (var n in articles) {
|
||||||
|
string articleLink = ArticleUtilities.GenerateArticleLink(n.Article, new Uri(Customizations.AppUrl, UriKind.Absolute));
|
||||||
|
articlesHtml.AppendFormat(
|
||||||
|
"""
|
||||||
|
<div style="padding: 10px; background: #333; color: #fff; margin-bottom: 10px">
|
||||||
|
<h3>{0}</h3>
|
||||||
|
<small>{1}</small>
|
||||||
|
<p>{2}</p>
|
||||||
|
<a href="{3}">Link</a>
|
||||||
|
</div>
|
||||||
|
""",
|
||||||
|
n.Article.Title, n.Article.Author.Name, n.Article.Body[..Math.Min(100, n.Article.Body.Length)], articleLink);
|
||||||
|
}
|
||||||
|
|
||||||
|
string logo = !string.IsNullOrWhiteSpace(Customizations.LogoLink)
|
||||||
|
? Customizations.LogoLink
|
||||||
|
: new Uri(host, "/img/logo.png").AbsoluteUri;
|
||||||
|
string unsubscribeLink = new Uri(host,
|
||||||
|
$"/Email/Unsubscribe?newsletter=welcome&user={WebUtility.UrlEncode(user)}&token={WebUtility.UrlEncode(token)}").AbsoluteUri;
|
||||||
|
string body = TemplateService.Welcome(host.AbsoluteUri, logo, title, bodyHtml, unsubscribeLink, articlesHtml.ToString());
|
||||||
|
await SendEmailAsync(subscriber.Email, subscriber.Name, subject, body,
|
||||||
|
new Header(HeaderId.ListUnsubscribe, $"<{unsubscribeLink}>"),
|
||||||
|
new Header(HeaderId.ListUnsubscribePost, "One-Click"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class EmailNotSendException(string message, Exception exception) : ApplicationException(message, exception);
|
public class EmailNotSendException(string message, Exception exception) : ApplicationException(message, exception);
|
Loading…
Reference in a new issue