diff --git a/zero.Core/Api/MailTemplatesApi.cs b/zero.Core/Api/MailTemplatesApi.cs index c6dcdc5b..d0181a9b 100644 --- a/zero.Core/Api/MailTemplatesApi.cs +++ b/zero.Core/Api/MailTemplatesApi.cs @@ -9,7 +9,7 @@ using zero.Core.Extensions; namespace zero.Core.Api { - public class MailTemplatesApi : BackofficeApi, IMailTemplatesApi + public class MailTemplatesApi : AppAwareBackofficeApi, IMailTemplatesApi { protected IValidator Validator { get; private set; } @@ -27,6 +27,14 @@ namespace zero.Core.Api } + /// + public async Task GetByKey(string key) + { + using IAsyncDocumentSession session = Raven.OpenAsyncSession(); + return await session.Query().Scope(Scope).FirstOrDefaultAsync(x => x.Key == key); + } + + /// public async Task> GetByIds(params string[] ids) { @@ -82,6 +90,11 @@ namespace zero.Core.Api /// Task GetById(string id); + /// + /// Get mail template by associated key + /// + Task GetByKey(string key); + /// /// Get mail templates by ids /// diff --git a/zero.Core/Extensions/StringExtensions.cs b/zero.Core/Extensions/StringExtensions.cs index 18efe918..86bec22a 100644 --- a/zero.Core/Extensions/StringExtensions.cs +++ b/zero.Core/Extensions/StringExtensions.cs @@ -37,6 +37,12 @@ namespace zero.Core.Extensions } + public static string Or(this string value, string fallback) + { + return String.IsNullOrWhiteSpace(value) ? fallback : value; + } + + public static string TrimEnd(this string value, string forRemoving) { if (String.IsNullOrEmpty(value)) return value; diff --git a/zero.Core/Mails/IMailSender.cs b/zero.Core/Mails/IMailSender.cs new file mode 100644 index 00000000..4cbc8e7a --- /dev/null +++ b/zero.Core/Mails/IMailSender.cs @@ -0,0 +1,19 @@ +using System.Threading; +using System.Threading.Tasks; +using zero.Core.Entities; + +namespace zero.Core.Mails +{ + public interface IMailSender + { + /// + /// Send a mail + /// + //Task Create(IMailTemplate template); + + /// + /// Send a mail + /// + //Task Send(Mail message, CancellationToken token = default); + } +} diff --git a/zero.Core/Mails/Mail.cs b/zero.Core/Mails/Mail.cs new file mode 100644 index 00000000..978c3534 --- /dev/null +++ b/zero.Core/Mails/Mail.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Mail; +using zero.Core.Entities; + +namespace zero.Core.Mails +{ + public class Mail : MailMessage + { + public IMailTemplate Template { get; set; } + + public Dictionary Placeholders { get; private set; } = new Dictionary(); + } +} diff --git a/zero.Core/Mails/MailSendResult.cs b/zero.Core/Mails/MailSendResult.cs new file mode 100644 index 00000000..ba0263e7 --- /dev/null +++ b/zero.Core/Mails/MailSendResult.cs @@ -0,0 +1,15 @@ +using Newtonsoft.Json; +using System; +using System.Linq; + +namespace zero.Core.Mails +{ + public class MailSendResult + { + public string Alias { get; set; } + + public DateTimeOffset LastRunDate { get; set; } + + public MailSendResult() { } + } +} diff --git a/zero.Core/Mails/MailSender.cs b/zero.Core/Mails/MailSender.cs new file mode 100644 index 00000000..0e0cbf9f --- /dev/null +++ b/zero.Core/Mails/MailSender.cs @@ -0,0 +1,120 @@ +using Microsoft.Extensions.Logging; +using System; +using System.Net.Mail; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using zero.Core.Api; +using zero.Core.Entities; +using zero.Core.Extensions; + +namespace zero.Core.Mails +{ + public class MailSender : IMailSender + { + protected IMailTemplatesApi TemplatesApi { get; set; } + + protected SmtpClient Client { get; set; } + + protected ILogger Logger { get; set; } + + protected IZeroContext Zero { get; set; } + + private Encoding encoding = Encoding.UTF8; + + + public MailSender(IZeroContext zero, IMailTemplatesApi templatesApi, ILogger logger) + { + Zero = zero; + TemplatesApi = templatesApi; + Logger = logger; + Client = new SmtpClient(); + } + + + /// + //public virtual async Task Create(string mailTemplateKey, CancellationToken token = default) + //{ + // IMailTemplate template = await GetMailTemplate(mailTemplateKey); + + // if (template == null) + // { + // Logger.LogError("Could not find a mail template with the key {key}", mailTemplateKey); + // return null; + // } + + // MailMessage message = new MailMessage(); + + // // get sender from template or fall back to application + // message.From = message.Sender; + // message.Sender = new MailAddress(template.SenderEmail.Or(Zero.App.Email), template.SenderName.Or(Zero.App.FullName), encoding); + // message.ReplyToList.Add(message.From); + + // // cc + bcc (multiple addresses are separated with commas + // if (!template.Cc.IsNullOrWhiteSpace()) + // { + // message.CC.Add(template.Cc); + // } + // if (!template.Bcc.IsNullOrWhiteSpace()) + // { + // message.Bcc.Add(template.Bcc); + // } + + // // recipient + // if (!template.RecipientEmail.IsNullOrWhiteSpace()) + // { + // message.To.Add(template.RecipientEmail); + // } + + // // subject + // message.Subject = template.Subject; + // message.SubjectEncoding = encoding; + //} + + + /// + public virtual async Task Send(string mailTemplateKey, Mail message, CancellationToken token = default) + { + message.Template = await GetMailTemplate(mailTemplateKey); + + if (message.Template == null) + { + Logger.LogError("Could not find a mail template with the key {key}", mailTemplateKey); + return false; + } + + return await Send(message, token); + } + + + /// + public virtual async Task Send(Mail message, CancellationToken token = default) + { + await Task.Delay(0); + return true; + } + + + /// + public virtual async Task Send(MailMessage message, CancellationToken token = default) + { + try + { + await Client.SendMailAsync(message, token); + return true; + } + catch (Exception ex) + { + Logger.LogError(ex, "Could not send mail message via SmtpClient"); + return false; + } + } + + + /// + protected virtual async Task GetMailTemplate(string key) + { + return await TemplatesApi.GetByKey(key); + } + } +}