namespace PendingEmails { using MailKit.Net.Smtp; using MailKit.Security; using MimeKit; using System; using System.Collections.Generic; using System.Data; using System.Data.SqlClient; using System.IO; using System.Linq; using System.Net; using System.Threading; public static partial class Program { private static void Main() { try { var awaiter = new ManualResetEventSlim(); while (true) { if (!AppSettings.TryLoadExeConfiguration(out var errors)) { WriteLine(new string('=', 50)); foreach (var error in errors) { WriteLine(error); } } else { WriteLine(new string('=', 50)); using (var connection = new SqlConnection(AppSettings.MSSQLConnectionString)) { OpenConnection(connection); FindWarantyEmails(connection); var messages = FindPendingEmails(connection); if (messages.Count <= 0) { WriteLine($"Keine neue nachrichten gefunden."); } var invalidMessages = messages.Where(x => !x.IsValid).ToList(); if (invalidMessages.Count > 0) { WriteLine($"{invalidMessages.Count} von {messages.Count} ungültige nachrichten gefunden."); var rowsAffected = SetOutDate(connection, invalidMessages.Select(x => x.Id)); WriteLine($"{rowsAffected} von {invalidMessages.Count} wurden als gesended markiert."); } else { WriteLine($"Keine neue ungültige nachrichten gefunden."); } var validMessages = messages .Where(x => x.IsValid) .ToList(); validMessages = new List { new Message(-1, AppSettings.Sender, "Just test", "It works!", "stoyan.zlatev@xylem.com", null) }; if (validMessages.Count > 0) { WriteLine($"{validMessages.Count} von {messages.Count} gültige nachrichten gefunden."); SendEmails(connection, validMessages); } } } awaiter.Wait(AppSettings.Interval); awaiter.Reset(); } } catch (Exception e) { WriteLine(e.ToString()); } } private static void OpenConnection(SqlConnection connection) { connection.FireInfoMessageEventOnUserErrors = true; connection.InfoMessage += (_, args) => WriteLine(args.Message); connection.Open(); } private static void SendEmails(SqlConnection connection, List messages) { var sentEmails = new List(); var excludedRecipients = AppSettings .ExcludeRecipients .ToEmailList(); WriteLine($"Sender: {AppSettings.Sender}"); using (var smtpClient = new SmtpClient()) { ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls13; smtpClient.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true; smtpClient.Connect(AppSettings.SMTPHost, AppSettings.SMTPPort, SecureSocketOptions.StartTls); if (!string.IsNullOrWhiteSpace(AppSettings.SMTPUsername) && !string.IsNullOrWhiteSpace(AppSettings.SMTPPassword)) { smtpClient.Authenticate(AppSettings.SMTPUsername, AppSettings.SMTPPassword); } foreach (var message in messages) { try { var recipients = message .Recipients .ToEmailList() .Except(excludedRecipients) .ToList(); if (recipients.Count <= 0) { break; } var recipientsCC = message .RecipientsCC .ToEmailList() .Except(excludedRecipients) .ToList(); var emailMessage = new MimeMessage { From = { new MailboxAddress("noreplay", AppSettings.Sender) }, Subject = message.Subject, Body = new TextPart { Text = message.Body } }; recipients.ForEach(x => emailMessage.To.Add(new MailboxAddress(x, x))); recipientsCC.ForEach(x => emailMessage.Cc.Add(new MailboxAddress(x, x))); smtpClient.Send(emailMessage); sentEmails.Add(message.Id); WriteLine($"Nachricht: {message.Id} wurde gesendet."); } catch (Exception e) { WriteLine(e.ToString()); } } } if (sentEmails.Count > 0) { WriteLine($"Gesendet {sentEmails.Count} von {messages.Count}"); var rowsAffected = SetOutDate(connection, sentEmails); WriteLine($"{rowsAffected} von {messages.Count} wurden als gesended markiert."); } else { WriteLine($"Keine nachrichten gesendet."); } } private static int SetOutDate(SqlConnection connection, IEnumerable messageIds) { var rowsAffected = default(int); using (var command = connection.CreateCommand()) { command.CommandText = $@" UPDATE Messages SET OutDate = GETDATE() WHERE Id IN ({string.Join(", ", messageIds)})"; rowsAffected = command.ExecuteNonQuery(); } return rowsAffected; } private static List FindPendingEmails(SqlConnection connection) { var pendingMessages = new List(); using (var command = connection.CreateCommand()) { command.CommandText = @" SELECT Id , Sender , Subject , Body , Recipients , CC FROM Messages WHERE OutDate IS NULL ORDER BY InDate DESC"; using (var reader = command.ExecuteReader()) { while (reader.Read()) { var messageId = reader.GetValue(0); var sender = reader.GetValue(1); var subject = reader.GetValue(2); var body = reader.GetValue(3); var recipients = reader.GetValue(4); var recipientsCC = reader.GetValue(5); pendingMessages.Add(new Message(messageId, sender, subject, body, recipients, recipientsCC)); } } } return pendingMessages; } private static void FindWarantyEmails(SqlConnection connection) { using (var command = connection.CreateCommand()) { command.CommandTimeout = 60000; command.CommandType = CommandType.StoredProcedure; command.CommandText = @"SP_EMAILS_FUER_GARANTIESCHEINE_LADEN"; WriteLine($"E-Mails für Garantiescheine gefunden: {command.ExecuteNonQuery()}"); } } private static void WriteLine(object e) { var logFolder = AppSettings.LogFolder; var logPath = Directory.CreateDirectory(logFolder).FullName; var logFile = Path.Combine(logPath, $"{DateTime.Now:yyyy-MM-dd}.txt"); var message = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {e}{Environment.NewLine}"; File.AppendAllText(logFile, message); Console.WriteLine(message.Trim()); } private static T GetValue(this SqlDataReader sqlDataReader, int index, T defaultValue = default(T)) { var value = defaultValue; if (0 <= index && index < sqlDataReader.FieldCount && !sqlDataReader.IsDBNull(index)) { var sqlValue = sqlDataReader.GetValue(index); var type = Nullable.GetUnderlyingType(typeof(T)); if (type is null) { type = typeof(T); } try { sqlValue = Convert.ChangeType(sqlValue, type); if (sqlValue is T expectedValue) { value = expectedValue; } } catch (Exception e) { WriteLine(e); } } return value; } private static List ToEmailList(this string value) => value ?.ToLower() ?.Split(new[] { ',', ';', ' ' }, StringSplitOptions.RemoveEmptyEntries) ?.Where(x => !string.IsNullOrWhiteSpace(x)) ?.ToList() ?? new List(); } }