From 4f6c18a1ac5e2b1c46fd43b1db100d4c3bcbec5b Mon Sep 17 00:00:00 2001 From: John Cardinal Date: Fri, 9 Oct 2026 17:08:23 -0700 Subject: [PATCH] case 4670 whups nearly missed an addition of services all ready to merge now for real --- Services/MailSender.cs | 47 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 Services/MailSender.cs diff --git a/Services/MailSender.cs b/Services/MailSender.cs new file mode 100644 index 0000000..b6e800d --- /dev/null +++ b/Services/MailSender.cs @@ -0,0 +1,47 @@ +using System.Threading.Tasks; +using MailKit.Net.Smtp; +using MailKit.Security; +using Microsoft.Extensions.Configuration; +using MimeKit; + +namespace contact.Services +{ + //Sends web form submissions to support. + //From is always the authenticated account; the visitor goes in Reply-To, so there is no sender spoofing. + //SMTP settings come from the "Smtp" config section; the password is never in source. + public class MailSender + { + private const string SupportAddress = "support@ayanova.com"; + private readonly IConfiguration _configuration; + + public MailSender(IConfiguration configuration) + { + _configuration = configuration; + } + + public async Task SendToSupportAsync(string subject, string body, string visitorName, string visitorEmail) + { + var smtp = _configuration.GetSection("Smtp"); + + var message = new MimeMessage(); + message.From.Add(new MailboxAddress("AyaNova web forms", smtp["User"])); + message.To.Add(MailboxAddress.Parse(SupportAddress)); + if (MailboxAddress.TryParse(visitorEmail, out var replyTo)) + { + replyTo.Name = visitorName; + message.ReplyTo.Add(replyTo); + } + message.Subject = OneLine(subject); + message.Body = new TextPart("plain") { Text = body }; + + using var client = new SmtpClient(); + await client.ConnectAsync(smtp["Host"], smtp.GetValue("Port"), SecureSocketOptions.StartTls); + await client.AuthenticateAsync(smtp["User"], smtp["Password"]); + await client.SendAsync(message); + await client.DisconnectAsync(true); + } + + //Subjects include visitor-supplied text; a hand-crafted POST could put line breaks in it + private static string OneLine(string s) => s.Replace("\r", " ").Replace("\n", " "); + } +}