add postmark as default mail dispatcher
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using System.Net.Mail;
|
||||
using System.Text;
|
||||
|
||||
namespace zero.Mails;
|
||||
|
||||
@@ -26,6 +27,30 @@ public class Mail : MailMessage
|
||||
public MailPlaceholders Placeholders { get; set; } = new();
|
||||
|
||||
public MailMetadata Metadata { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Set To and From addresses based on values in MailOptions
|
||||
/// </summary>
|
||||
public Mail For(MailOptions options)
|
||||
{
|
||||
To.Add(new MailAddress(options.To, options.ToName));
|
||||
From = new MailAddress(options.From, options.FromName);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the body as plain text
|
||||
/// </summary>
|
||||
public string PlainText
|
||||
{
|
||||
get => Body;
|
||||
set
|
||||
{
|
||||
Body = value;
|
||||
IsBodyHtml = false;
|
||||
BodyEncoding = Encoding.UTF8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class MailMetadata : Dictionary<string, string>
|
||||
|
||||
@@ -10,12 +10,23 @@ public class MailOptions
|
||||
|
||||
//public string Password { get; set; }
|
||||
|
||||
//public string To { get; set; }
|
||||
public string From { get; set; }
|
||||
|
||||
public string FromName { get; set; }
|
||||
|
||||
public string To { get; set; }
|
||||
|
||||
public string ToName { get; set; }
|
||||
|
||||
public string ReplyTo { get; set; }
|
||||
|
||||
public bool Debug { get; set; } = true;
|
||||
|
||||
public string SenderEmail { get; set; }
|
||||
|
||||
public string SenderName { get; set; }
|
||||
|
||||
public PostmarkOptions Postmark { get; set; } = new();
|
||||
|
||||
public Func<Mail, string> BuildViewPath { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Options;
|
||||
using PostmarkDotNet;
|
||||
using PostmarkDotNet.Model;
|
||||
|
||||
namespace zero.Mails;
|
||||
|
||||
public class PostmarkDispatcher : IMailDispatcher
|
||||
{
|
||||
protected Queue<Mail> Queue { get; private set; } = new();
|
||||
|
||||
protected PostmarkClient Postmark { get; set; }
|
||||
|
||||
protected PostmarkAdminClient PostmarkAdmin { get; set; }
|
||||
|
||||
protected MailOptions Options { get; set; }
|
||||
|
||||
protected IWebHostEnvironment Env { get; set; }
|
||||
|
||||
|
||||
public PostmarkDispatcher(IOptionsMonitor<MailOptions> monitor, IWebHostEnvironment env)
|
||||
{
|
||||
Options = monitor.CurrentValue;
|
||||
Postmark = new(Options.Postmark.ServerToken);
|
||||
PostmarkAdmin = new(Options.Postmark.AccountToken);
|
||||
Env = env;
|
||||
|
||||
monitor.OnChange(opts =>
|
||||
{
|
||||
Options = opts;
|
||||
Postmark = new(Options.Postmark.ServerToken);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<bool> IsSenderSupported(string email)
|
||||
{
|
||||
if (email.IsNullOrWhiteSpace() || Options.Postmark.AccountToken.IsNullOrEmpty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
email = email.FullTrim();
|
||||
PostmarkSenderSignatureList signatures = await PostmarkAdmin.GetSenderSignaturesAsync();
|
||||
return signatures.SenderSignatures.Any(x => x.Confirmed && x.EmailAddress.Equals(email, StringComparison.InvariantCultureIgnoreCase));
|
||||
}
|
||||
catch
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Enqueue(Mail message)
|
||||
{
|
||||
Queue.Enqueue(message);
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task Send(CancellationToken token = default)
|
||||
{
|
||||
HashSet<PostmarkMessage> messages = [];
|
||||
|
||||
while (Queue.Count > 0)
|
||||
{
|
||||
Mail message = Queue.Dequeue();
|
||||
|
||||
PostmarkMessage data = new()
|
||||
{
|
||||
// to addresses
|
||||
To = message.To.ToString(),
|
||||
Cc = message.CC.ToString(),
|
||||
Bcc = message.Bcc.ToString(),
|
||||
|
||||
// from address
|
||||
From = message.From.ToString(),
|
||||
ReplyTo = message.ReplyToList.ToString(),
|
||||
|
||||
// subject
|
||||
Subject = message.Subject,
|
||||
|
||||
// tracking
|
||||
TrackLinks = LinkTrackingOptions.None,
|
||||
TrackOpens = false,
|
||||
|
||||
// configuration
|
||||
MessageStream = Options.Postmark.MessageStream,
|
||||
//Tag = message.Template?.Key,
|
||||
Metadata = message.Metadata
|
||||
};
|
||||
|
||||
// set attachments
|
||||
foreach (System.Net.Mail.Attachment attachment in message.Attachments)
|
||||
{
|
||||
data.AddAttachment(attachment.ContentStream, attachment.Name, attachment.ContentType.MediaType, attachment.ContentId);
|
||||
}
|
||||
|
||||
// set body
|
||||
if (!message.IsBodyHtml)
|
||||
{
|
||||
data.TextBody = message.Body;
|
||||
}
|
||||
else
|
||||
{
|
||||
data.HtmlBody = message.Body;
|
||||
}
|
||||
|
||||
// overwrite for debug mode
|
||||
if (Options.Debug || (Env != null && Env.IsDevelopment()))
|
||||
{
|
||||
data.From = "noreply@post.swcs.pro";
|
||||
|
||||
string[] allowedTlds = ["swcs.pro", "alias.swcs.pro"];
|
||||
string tld = data.To.TrimEnd('>').Split('@').LastOrDefault();
|
||||
|
||||
data.Cc = null; // "cee-maildev@gmx.at,anaheimcore@gmail.com,ceemaildev@yahoo.com";
|
||||
data.Bcc = null;
|
||||
|
||||
if (!allowedTlds.Contains(tld, StringComparer.InvariantCultureIgnoreCase))
|
||||
{
|
||||
data.Subject = $"{data.Subject} (test; für {data.To})";
|
||||
data.To = "maildev@alias.swcs.pro";
|
||||
}
|
||||
else
|
||||
{
|
||||
data.Subject = $"{data.Subject} (test)";
|
||||
}
|
||||
}
|
||||
|
||||
messages.Add(data);
|
||||
}
|
||||
|
||||
// finally sends the message
|
||||
IEnumerable<PostmarkResponse> responses = await Postmark.SendMessagesAsync(messages);
|
||||
|
||||
foreach (PostmarkResponse response in responses)
|
||||
{
|
||||
if (response.ErrorCode > 0)
|
||||
{
|
||||
throw new PostmarkSendException($"Could not send message via Postmark API. Code: {response.ErrorCode}, Message: {response.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose() { }
|
||||
}
|
||||
|
||||
|
||||
public class PostmarkSendException : Exception
|
||||
{
|
||||
public PostmarkSendException() : base() { }
|
||||
|
||||
public PostmarkSendException(string message) : base(message) { }
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace zero.Mails;
|
||||
|
||||
public class PostmarkOptions
|
||||
{
|
||||
public string ServerToken { get; set; }
|
||||
|
||||
public string AccountToken { get; set; }
|
||||
|
||||
public string MessageStream { get; set; } = "outbound";
|
||||
}
|
||||
@@ -8,7 +8,8 @@ internal class ZeroMailModule : ZeroModule
|
||||
public override void ConfigureServices(IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
services.AddScoped<IMailProvider, MailProvider>();
|
||||
services.AddScoped<IMailDispatcher, LoggerMailDispatcher>();
|
||||
//services.AddScoped<IMailDispatcher, LoggerMailDispatcher>();
|
||||
services.AddScoped<IMailDispatcher, PostmarkDispatcher>();
|
||||
|
||||
services.AddOptions<MailOptions>().Bind(configuration.GetSection("Zero:Mails")).Configure(opts =>
|
||||
{
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="9.0.4" />
|
||||
<PackageReference Include="FluentValidation" Version="11.11.0" />
|
||||
<PackageReference Include="Postmark" Version="5.3.0" />
|
||||
<PackageReference Include="PowCapServer.AspNetCore" Version="2.0.0" />
|
||||
<PackageReference Include="SixLabors.ImageSharp.Web" Version="3.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
Reference in New Issue
Block a user