diff --git a/Pages/Contact.cshtml.cs b/Pages/Contact.cshtml.cs
index ba6af89..b776cce 100644
--- a/Pages/Contact.cshtml.cs
+++ b/Pages/Contact.cshtml.cs
@@ -1,13 +1,14 @@
-using System.Collections.Generic;
-using Microsoft.AspNetCore.Mvc.RazorPages;
+using System;
using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Threading.Tasks;
+using MailKit.Net.Smtp;
+using MailKit.Security;
using Microsoft.AspNetCore.Mvc;
-using System.Net.Mail;
-using System.Net;
-//for captcha:
-using System.Net.Http;
-using Newtonsoft.Json.Linq;
+using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging;
+using MimeKit;
namespace contact.Pages
{
@@ -28,137 +29,31 @@ namespace contact.Pages
public string Email { get; set; }
[Required]
public string Message { get; set; }
-
}
public class ContactModel : PageModel
{
+ private const string ConfirmedUrl = "https://ayanova.com/confirmed.htm";
+
+ //2022-05-06 Company names containing any of these are dropped silently but still get the
+ //success redirect, so the spammer gets no signal and has to pay someone to enter them by hand
+ private static readonly string[] SpamBlocks = { "google", "jumboleadmagnet", "boostleadgeneration" };
+
public string Message { get; set; }
+
[BindProperty(SupportsGet = true)]
public ContactFormModel Contact { get; set; }
+ //Set when the send fails, so Contact.cshtml can tell the visitor instead of claiming success
+ public bool SendFailed { get; set; }
+
private readonly IConfiguration _configuration;
- public ContactModel(IConfiguration configuration)
+ private readonly ILogger _logger;
+
+ public ContactModel(IConfiguration configuration, ILogger logger)
{
_configuration = configuration;
- }
-
- public ActionResult OnPost()
- {
- if (!ModelState.IsValid)
- {
- return Page();
- }
-
-
- //2025-11-01 Google dropping support for captcha, just nuking it for now, see how much spam I get
- // if (!ReCaptchaPassed(
- // Request.Form["g-recaptcha-response"], // that's how you get it from the Request object
- // _configuration.GetSection("GoogleReCaptcha:secret").Value
- // ))
- // {
- // //Return a fail code that will hopefully take us off the spammers list
- // return StatusCode(500);
- // }
-
-
-
- //go away spammers
- //2022-05-06 changes to get rid of jumbo lead magnet spammer but still force him to pay someone to manually enter the stuff
- //ideally it should read from a text file here but this is a quickie fix while Joyce is on important viha phone call
- var blocks = new List();
- blocks.Add("google");
- blocks.Add("jumboleadmagnet");//<--go away this guy in particular, keeps spamming
- blocks.Add("boostleadgeneration");
- //ericjonesmyemail@gmail.com
- var companyname = Contact.Company.ToLowerInvariant();
- foreach (string s in blocks)
- {
- if (companyname.Contains(s))
- {
- goto skipspam;
-
- }
- }
-
- SendMail();
-
- skipspam:
- //TODO: go to a successful submit page on the ayanova site
- //return Redirect("/confirm.html");//sample quickie page I made up
- return Redirect("https://ayanova.com/confirmed.htm");
- }
-
-
- private void SendMail()
- {
- var MessageBody = $"Name:\r\n{Contact.Name}\r\n\r\nCompany:\r\n{Contact.Company}\r\n\r\nDatabase Id:\r\n{Contact.DbId}\r\n\r\nMessage:\r\n{Contact.Message}";
-
- //SEND TO US
- using (var message = new MailMessage())
- {
- message.To.Add(new MailAddress("support@ayanova.com"));
- message.From = new MailAddress(Contact.Email);
- message.Subject = $"Question about AyaNova from {Contact.Company}";
- message.Body = MessageBody;
- using (var smtpClient = new SmtpClient("smtp.fastmail.com"))
- {
-
- smtpClient.Host = "smtp.fastmail.com";
- smtpClient.Port = 587;
- smtpClient.UseDefaultCredentials = false;
- //testing
- smtpClient.EnableSsl = true;
-
- // smtpClient.Port=465;
- // smtpClient.DeliveryMethod= SmtpDeliveryMethod.Network;
-
-
-
- //NOTE: Do not use the noreply email address to send mail, it crashes the server somehow
-
- //******************************************************************************************************************
- //******************************************************************************************************************
- //TEST CRASH
- // smtpClient.Credentials = new System.Net.NetworkCredential("noreply@ayanova.com", "91768700489f8edd28aa71e3e0f4073eba54ce83c4c1a6a910700fa94094ddfd");
-
-
- //FASTMAIL CHANGES
- //Fastmail server names and ports help page: https://www.fastmail.help/hc/en-us/articles/1500000278342
- //APP Password created in fastmail for smtp use only labelled 'contact-form': cnea8agl6nlx5j7l
-
- //try using from as support@onayanova.com
- //try domain version if this still won't work
- smtpClient.Credentials = new System.Net.NetworkCredential("support@onayanova.com", "cnea8agl6nlx5j7l");
- //******************************************************************************************************************
- //******************************************************************************************************************
-
- smtpClient.Send(message);
- }
- }
-
- //Removed 2022-10-06 causing backscatter and also not helpful
- // //SEND COPY TO CLIENT
- // using (var message = new MailMessage())
- // {
- // message.To.Add(new MailAddress(Contact.Email));
- // message.From = new MailAddress("support@ayanova.com");
- // message.Subject = $"Confirmation that your question about AyaNova has been received from {Contact.Company}";
- // message.Body = MessageBody;
-
- // using (var smtpClient = new SmtpClient("smtp.fastmail.com"))
- // {
-
- // smtpClient.Host = "smtp.fastmail.com";
- // smtpClient.Port = 587;
- // smtpClient.UseDefaultCredentials = false;
- // smtpClient.EnableSsl=true;
- // //NOTE: Do not use the noreply email address to send mail, it crashes the server somehow
- // smtpClient.Credentials = new System.Net.NetworkCredential("support@onayanova.com", "cnea8agl6nlx5j7l");
- // smtpClient.Send(message);
- // }
- // }
-
+ _logger = logger;
}
public void OnGet()
@@ -166,28 +61,64 @@ namespace contact.Pages
Message = "Your contact page.";
}
+ public async Task OnPostAsync()
+ {
+ if (!ModelState.IsValid)
+ {
+ return Page();
+ }
- //2025-11-01 Google dropping support for captcha, just nuking it for now, see how much spam I get
- // public static bool ReCaptchaPassed(string gRecaptchaResponse, string secret)
- // {
- // HttpClient httpClient = new HttpClient();
- // var res = httpClient.GetAsync($"https://www.google.com/recaptcha/api/siteverify?secret={secret}&response={gRecaptchaResponse}").Result;
- // if (res.StatusCode != HttpStatusCode.OK)
- // {
- // // logger.LogError("Error while sending request to ReCaptcha");
- // return false;
- // }
+ //2025-11-01 reCAPTCHA removed (Google service change). Replacement deferred, see runbook Phase 6.
- // string JSONres = res.Content.ReadAsStringAsync().Result;
- // dynamic JSONdata = JObject.Parse(JSONres);
- // if (JSONdata.success != "true")
- // {
- // return false;
- // }
+ var company = Contact.Company.ToLowerInvariant();
+ if (SpamBlocks.Any(s => company.Contains(s)))
+ {
+ return Redirect(ConfirmedUrl);
+ }
- // return true;
- // }
+ try
+ {
+ await SendMailAsync();
+ }
+ catch (Exception ex)
+ {
+ //Log the whole submission so it can be recovered from the journal, not lost
+ _logger.LogError(ex,
+ "Contact form send failed. Name: {Name} | Company: {Company} | Email: {Email} | DbId: {DbId} | Message: {Message}",
+ Contact.Name, Contact.Company, Contact.Email, Contact.DbId, Contact.Message);
+ SendFailed = true;
+ return Page();
+ }
+ return Redirect(ConfirmedUrl);
+ }
+ private async Task SendMailAsync()
+ {
+ var smtp = _configuration.GetSection("Smtp");
+
+ //Email is in the body as well as Reply-To, so it survives even if Reply-To can't be set
+ var body = $"Name:\r\n{Contact.Name}\r\n\r\nCompany:\r\n{Contact.Company}\r\n\r\nEmail:\r\n{Contact.Email}\r\n\r\nDatabase Id:\r\n{Contact.DbId}\r\n\r\nMessage:\r\n{Contact.Message}";
+
+ var message = new MimeMessage();
+ //From is always the authenticated account; the visitor goes in Reply-To (no sender spoofing)
+ message.From.Add(new MailboxAddress("AyaNova contact form", smtp["User"]));
+ message.To.Add(MailboxAddress.Parse("support@ayanova.com"));
+ if (MailboxAddress.TryParse(Contact.Email, out var replyTo))
+ {
+ replyTo.Name = Contact.Name;
+ message.ReplyTo.Add(replyTo);
+ }
+ message.Subject = $"Question about AyaNova from {OneLine(Contact.Company)}";
+ 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);
+ }
+
+ private static string OneLine(string s) => s.Replace("\r", " ").Replace("\n", " ");
}
}
diff --git a/Program.cs b/Program.cs
index a6518bb..b354103 100644
--- a/Program.cs
+++ b/Program.cs
@@ -1,19 +1,14 @@
-using Microsoft.AspNetCore;
-using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Hosting;
namespace contact
{
public class Program
{
- public static void Main(string[] args)
- {
- CreateWebHostBuilder(args).Build().Run();
- }
-
- public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
- WebHost.CreateDefaultBuilder(args)
- .UseUrls("http://*:3002")//only this port works with nginx proxy
- //.UseUrls("http://localhost:3002")//this doesn't work with nginx proxy
- .UseStartup();
+ public static void Main(string[] args) =>
+ Host.CreateDefaultBuilder(args)
+ .ConfigureWebHostDefaults(web => web.UseStartup())
+ .Build()
+ .Run();
}
}
diff --git a/appsettings.Development.json b/appsettings.Development.json
index a2880cb..143621e 100644
--- a/appsettings.Development.json
+++ b/appsettings.Development.json
@@ -5,5 +5,6 @@
"System": "Information",
"Microsoft": "Information"
}
- }
+ },
+ "AllowedHosts": "localhost"
}
diff --git a/contact.csproj b/contact.csproj
index 48a82e2..691b674 100644
--- a/contact.csproj
+++ b/contact.csproj
@@ -1,20 +1,9 @@
-
-
+
- net6.0
+ net10.0
+ efc95c93-c628-4ad5-a697-cd1613181a44
-
-
-
+
+
-
-
-
+
\ No newline at end of file