using MailKit.Net.Smtp; using Microsoft.Extensions.Options; using MimeKit; using PrivaPub.Models; namespace PrivaPub.Services { public interface IMailer { /// Sends a plain-text email; throws when SMTP fails, so the job that sends it retries. Task Send(string to, string subject, string body, CancellationToken token); } // The server's one way to send an email: through the SMTP account in appsettings (AppConfiguration:EmailConfiguration), // read as it is now. Only jobs call it, so nobody waits on SMTP. public class Mailer : IMailer { readonly IOptionsMonitor _app; public Mailer(IOptionsMonitor app) => _app = app; public async Task Send(string to, string subject, string body, CancellationToken token) { var email = _app.CurrentValue.EmailConfiguration; var message = new MimeMessage(); message.From.Add(new MailboxAddress("PrivaPub", email.SmtpUsername)); message.To.Add(MailboxAddress.Parse(to)); message.Subject = subject; message.Body = new TextPart("plain") { Text = body }; using var smtp = new SmtpClient(); await smtp.ConnectAsync(email.SmtpServer, email.SmtpPort, email.UseSSL, token); if (!string.IsNullOrEmpty(email.SmtpPassword)) await smtp.AuthenticateAsync(email.SmtpUsername, email.SmtpPassword, token); await smtp.SendAsync(message, token); await smtp.DisconnectAsync(quit: true, token); } } }