using System; using System.Collections.Generic; using System.Text; using System.Linq; using System.IO; using System.Text.RegularExpressions; using MailKit.Net.Smtp; using MailKit.Net.Imap; using MailKit.Search; using MailKit; using MimeKit; using MimeKit.Utils; namespace rockfishCore.Util { /* HOW TO DIAGNOSE ISSUES: Get a protocol log: https://github.com/jstedfast/MailKit/blob/master/FAQ.md#ProtocolLog docs http://www.mimekit.net/docs/html/Introduction.htm */ //http://www.mimekit.net/ public static class RfMail { public const string MAIL_MIRROR_SMPT_ADDRESS = "mail2.ayanova.com"; public const string MAIL_MIRROR_IMAP_ADDRESS = "mail2.ayanova.com"; public const string MAIL_SMPT_ADDRESS = "mail.ayanova.com"; public const int MAIL_SMPT_PORT = 465; public const string MAIL_IMAP_ADDRESS = "mail.ayanova.com"; //public const int MAIL_IMAP_PORT = 993; //testing public const int MAIL_IMAP_PORT = 143; public const string MAIL_ACCOUNT_SUPPORT = "support@ayanova.com"; public const string MAIL_ACCOUNT_PASSWORD_SUPPORT = "e527b6c5a00c27bb61ca694b3de0ee178cbe3f1541a772774762ed48e9caf5ce"; public const string MAIL_ACCOUNT_SALES = "sales@ayanova.com"; public const string MAIL_ACCOUNT_PASSWORD_SALES = "6edbae5eb616a975abf86bcd9f45616f5c70c4f05189af60a1caaa62b406149d"; public enum rfMailAccount { support = 1, sales = 2 } public class rfMailMessage { public MimeMessage message { get; set; } public uint uid { get; set; } } class DeliverStatusSmtpClient : SmtpClient { protected override DeliveryStatusNotification? GetDeliveryStatusNotifications(MimeMessage message, MailboxAddress mailbox) { return DeliveryStatusNotification.Delay | DeliveryStatusNotification.Failure | DeliveryStatusNotification.Success; } } ///////////////////////////////////////////////////////// // // Do the sending with optional deliver status receipt // public static void DoSend(MimeMessage message, string MailAccount, string MailAccountPassword, bool trackDeliveryStatus) { if (trackDeliveryStatus) { //set the return receipt and disposition to headers message.Headers.Add("Return-Receipt-To", "<" + MailAccount + ">"); message.Headers.Add("Disposition-Notification-To", "<" + MailAccount + ">"); using (var client = new DeliverStatusSmtpClient()) { //Accept all SSL certificates (in case the server supports STARTTLS) //(we have a funky cert on the mail server) client.ServerCertificateValidationCallback = (s, c, h, e) => true; client.Connect(MAIL_SMPT_ADDRESS, MAIL_SMPT_PORT); // Note: since we don't have an OAuth2 token, disable // the XOAUTH2 authentication mechanism. client.AuthenticationMechanisms.Remove("XOAUTH2"); // Note: only needed if the SMTP server requires authentication client.Authenticate(MAIL_ACCOUNT_SUPPORT, MAIL_ACCOUNT_PASSWORD_SUPPORT); client.Send(message); client.Disconnect(true); } } else { using (var client = new SmtpClient()) { //Accept all SSL certificates (in case the server supports STARTTLS) //(we have a funky cert on the mail server) client.ServerCertificateValidationCallback = (s, c, h, e) => true; client.Connect(MAIL_SMPT_ADDRESS, MAIL_SMPT_PORT); // Note: since we don't have an OAuth2 token, disable // the XOAUTH2 authentication mechanism. client.AuthenticationMechanisms.Remove("XOAUTH2"); // Note: only needed if the SMTP server requires authentication client.Authenticate(MAIL_ACCOUNT_SUPPORT, MAIL_ACCOUNT_PASSWORD_SUPPORT); client.Send(message); client.Disconnect(true); } } } public static void SendMessage(string MessageFrom, string MessageTo, string MessageSubject, string MessageBody, bool trackDeliveryStatus = false, string CustomHeader = "", string CustomHeaderValue = "") { var message = new MimeMessage(); message.From.Add(new MailboxAddress("", MessageFrom)); message.To.Add(new MailboxAddress("", MessageTo)); message.Subject = MessageSubject; message.Body = new TextPart("plain") { Text = MessageBody }; message.Headers["X-Mailer"] = RfVersion.Full; if (CustomHeader != "" && CustomHeaderValue != "") { message.Headers["X-Rockfish-" + CustomHeader] = CustomHeaderValue; } //send with optional tracking DoSend(message, MAIL_ACCOUNT_SUPPORT, MAIL_ACCOUNT_PASSWORD_SUPPORT, trackDeliveryStatus); // using (var client = new SmtpClient()) // { // //Accept all SSL certificates (in case the server supports STARTTLS) // //(we have a funky cert on the mail server) // client.ServerCertificateValidationCallback = (s, c, h, e) => true; // client.Connect(MAIL_SMPT_ADDRESS, MAIL_SMPT_PORT, true); // // Note: since we don't have an OAuth2 token, disable // // the XOAUTH2 authentication mechanism. // client.AuthenticationMechanisms.Remove("XOAUTH2"); // // Note: only needed if the SMTP server requires authentication // client.Authenticate(MAIL_ACCOUNT_SUPPORT, MAIL_ACCOUNT_PASSWORD_SUPPORT); // client.Send(message); // client.Disconnect(true); // } }//send message #region handle spam message /// /// Forward a message to the isspam@ayanova.com address and then erase it /// /// /// public static void HandleSpamMessage(uint spamMessageId, rfMailAccount replyFromAccount) { using (var client = new ImapClient()) { // Accept all SSL certificates client.ServerCertificateValidationCallback = (s, c, h, e) => true; client.Connect(MAIL_IMAP_ADDRESS, MAIL_IMAP_PORT); // Note: since we don't have an OAuth2 token, disable // the XOAUTH2 authentication mechanism. client.AuthenticationMechanisms.Remove("XOAUTH2"); if (replyFromAccount == rfMailAccount.support) { client.Authenticate(MAIL_ACCOUNT_SUPPORT, MAIL_ACCOUNT_PASSWORD_SUPPORT); } else { client.Authenticate(MAIL_ACCOUNT_SALES, MAIL_ACCOUNT_PASSWORD_SALES); } var spamFolder = client.GetFolder("Spam"); if (spamFolder != null) { client.Inbox.Open(FolderAccess.ReadWrite); client.Inbox.MoveTo(new UniqueId(spamMessageId), spamFolder); } client.Disconnect(true); } }//spaminator #endregion #region handle read and move message /// /// Move to sub or unsub mail folder and mark as read /// /// /// public static void MoveAndMarkRead(uint moveMessageId, rfMailAccount replyFromAccount, bool toSubscribed) { using (var client = new ImapClient()) { // Accept all SSL certificates client.ServerCertificateValidationCallback = (s, c, h, e) => true; client.Connect(MAIL_IMAP_ADDRESS, MAIL_IMAP_PORT); // Note: since we don't have an OAuth2 token, disable // the XOAUTH2 authentication mechanism. client.AuthenticationMechanisms.Remove("XOAUTH2"); if (replyFromAccount == rfMailAccount.support) { client.Authenticate(MAIL_ACCOUNT_SUPPORT, MAIL_ACCOUNT_PASSWORD_SUPPORT); } else { client.Authenticate(MAIL_ACCOUNT_SALES, MAIL_ACCOUNT_PASSWORD_SALES); } //AyaNovaReceivedNOTSUB //AyaNovaReceivedSubscribed //Flag as read //flag the message as having been replied to FlagMessageSeen(moveMessageId, replyFromAccount); var newFolder = client.GetFolder(toSubscribed ? "AyaNovaReceivedSubscribed" : "AyaNovaReceivedNOTSUB"); if (newFolder != null) { client.Inbox.Open(FolderAccess.ReadWrite); client.Inbox.MoveTo(new UniqueId(moveMessageId), newFolder); } client.Disconnect(true); } }//spaminator #endregion public static void ReplyMessage(uint replyToMessageId, rfMailAccount replyFromAccount, string replyBody, bool replyToAll, bool trackDeliveryStatus = false, string CustomHeader = "", string CustomHeaderValue = "") { //get the original to reply to it: MimeMessage message = GetMessage(replyToMessageId, replyFromAccount); if (message == null) { throw new System.ArgumentException("RfMail:ReplyMessage->source message not found (id=" + replyToMessageId.ToString() + ")"); } //construct the new message var reply = new MimeMessage(); MailboxAddress from = null; string from_account = ""; string from_account_password = ""; switch (replyFromAccount) { case rfMailAccount.sales: from_account = MAIL_ACCOUNT_SALES; from_account_password = MAIL_ACCOUNT_PASSWORD_SALES; from = new MailboxAddress("", from_account); break; default: from_account = MAIL_ACCOUNT_SUPPORT; from_account_password = MAIL_ACCOUNT_PASSWORD_SUPPORT; from = new MailboxAddress("", from_account); break; } reply.From.Add(from); // reply to the sender of the message if (message.ReplyTo.Count > 0) { reply.To.AddRange(message.ReplyTo); } else if (message.From.Count > 0) { reply.To.AddRange(message.From); } else if (message.Sender != null) { reply.To.Add(message.Sender); } if (replyToAll) { // include all of the other original recipients (removing ourselves from the list) reply.To.AddRange(message.To.Mailboxes.Where(x => x.Address != from.Address)); reply.Cc.AddRange(message.Cc.Mailboxes.Where(x => x.Address != from.Address)); } // set the reply subject if (!message.Subject.StartsWith("Re:", StringComparison.OrdinalIgnoreCase)) reply.Subject = "Re: " + message.Subject; else reply.Subject = message.Subject; // construct the In-Reply-To and References headers if (!string.IsNullOrEmpty(message.MessageId)) { reply.InReplyTo = message.MessageId; foreach (var id in message.References) reply.References.Add(id); reply.References.Add(message.MessageId); } // quote the original message text using (var quoted = new StringWriter()) { var sender = message.Sender ?? message.From.Mailboxes.FirstOrDefault(); var name = sender != null ? (!string.IsNullOrEmpty(sender.Name) ? sender.Name : sender.Address) : "someone"; quoted.WriteLine("On {0}, {1} wrote:", message.Date.ToString("f"), name); //Try to get the original message text and format it as > quoted var theBody = message.GetTextBody(MimeKit.Text.TextFormat.Plain); if (theBody == null) { //No text body so go with the new method to extract the text part // might be an html email, try to get the text anyway var ht = message.HtmlBody; if (!string.IsNullOrWhiteSpace(ht)) { theBody = StripHTML(ht, true); theBody += "> "; theBody = theBody.Replace("\r\n", "\r\n> ").Trim().TrimEnd('>'); theBody = "\r\n" + theBody;//descend the first line under the On you wrote bit } else { theBody = "> Source Message Empty"; } quoted.WriteLine(theBody); } else { //has a text body so go with old method using (var reader = new StringReader(message.TextBody)) { string line; while ((line = reader.ReadLine()) != null) { quoted.Write("> "); quoted.WriteLine(line); } } } reply.Body = new TextPart("plain") { Text = replyBody + "\r\n\r\n\r\n" + quoted.ToString() }; } reply.Headers["X-Mailer"] = RfVersion.Full; if (CustomHeader != "" && CustomHeaderValue != "") { reply.Headers["X-Rockfish-" + CustomHeader] = CustomHeaderValue; } //send with optional tracking DoSend(reply, from_account, from_account_password, trackDeliveryStatus); //flag the message as having been replied to FlagInboxMessageSeenReplied(replyToMessageId, replyFromAccount); }//send message //Fetch message by UID public static MimeMessage GetMessage(uint uid, rfMailAccount fromAccount = rfMailAccount.support) { using (var client = new ImapClient()) { // Accept all SSL certificates client.ServerCertificateValidationCallback = (s, c, h, e) => true; client.Connect(MAIL_IMAP_ADDRESS, MAIL_IMAP_PORT); // Note: since we don't have an OAuth2 token, disable // the XOAUTH2 authentication mechanism. client.AuthenticationMechanisms.Remove("XOAUTH2"); if (fromAccount == rfMailAccount.support) { client.Authenticate(MAIL_ACCOUNT_SUPPORT, MAIL_ACCOUNT_PASSWORD_SUPPORT); } else { client.Authenticate(MAIL_ACCOUNT_SALES, MAIL_ACCOUNT_PASSWORD_SALES); } var inbox = client.Inbox; inbox.Open(FolderAccess.ReadOnly); var m = inbox.GetMessage(new UniqueId(uid)); client.Disconnect(true); return m; } }//get message //Fetch messages by Search query public static List GetMessages(SearchQuery query) { List ret = new List(); using (var client = new ImapClient()) { // Accept all SSL certificates client.ServerCertificateValidationCallback = (s, c, h, e) => true; client.Connect(MAIL_IMAP_ADDRESS, MAIL_IMAP_PORT); // Note: since we don't have an OAuth2 token, disable // the XOAUTH2 authentication mechanism. client.AuthenticationMechanisms.Remove("XOAUTH2"); client.Authenticate(MAIL_ACCOUNT_SUPPORT, MAIL_ACCOUNT_PASSWORD_SUPPORT); var inbox = client.Inbox; inbox.Open(FolderAccess.ReadOnly); foreach (var uid in inbox.Search(query)) { ret.Add(new rfMailMessage { message = inbox.GetMessage(uid), uid = uid.Id }); } client.Disconnect(true); } return ret; }//get message //Flag message as seen and replied by UID public static bool FlagInboxMessageSeenReplied(uint uid, rfMailAccount inAccount = rfMailAccount.support) { using (var client = new ImapClient()) { // Accept all SSL certificates client.ServerCertificateValidationCallback = (s, c, h, e) => true; client.Connect(MAIL_IMAP_ADDRESS, MAIL_IMAP_PORT); // Note: since we don't have an OAuth2 token, disable // the XOAUTH2 authentication mechanism. client.AuthenticationMechanisms.Remove("XOAUTH2"); if (inAccount == rfMailAccount.support) { client.Authenticate(MAIL_ACCOUNT_SUPPORT, MAIL_ACCOUNT_PASSWORD_SUPPORT); } else { client.Authenticate(MAIL_ACCOUNT_SALES, MAIL_ACCOUNT_PASSWORD_SALES); } var inbox = client.Inbox; inbox.Open(FolderAccess.ReadWrite); inbox.AddFlags(new UniqueId(uid), MessageFlags.Seen, true); inbox.AddFlags(new UniqueId(uid), MessageFlags.Answered, true); client.Disconnect(true); return true; } }//get message //Flag message as seen public static bool FlagMessageSeen(uint uid, rfMailAccount inAccount = rfMailAccount.support) { using (var client = new ImapClient()) { // Accept all SSL certificates client.ServerCertificateValidationCallback = (s, c, h, e) => true; client.Connect(MAIL_IMAP_ADDRESS, MAIL_IMAP_PORT); // Note: since we don't have an OAuth2 token, disable // the XOAUTH2 authentication mechanism. client.AuthenticationMechanisms.Remove("XOAUTH2"); if (inAccount == rfMailAccount.support) { client.Authenticate(MAIL_ACCOUNT_SUPPORT, MAIL_ACCOUNT_PASSWORD_SUPPORT); } else { client.Authenticate(MAIL_ACCOUNT_SALES, MAIL_ACCOUNT_PASSWORD_SALES); } var inbox = client.Inbox; inbox.Open(FolderAccess.ReadWrite); inbox.AddFlags(new UniqueId(uid), MessageFlags.Seen, true); // inbox.AddFlags(new UniqueId(uid), MessageFlags.Answered, true); client.Disconnect(true); return true; } }//get message //////////////////////////////////////////////////// //Put a message in the drafts folder of support // public static void DraftMessage(string MessageFrom, string MessageTo, string MessageSubject, string MessageBody, string CustomHeader = "", string CustomHeaderValue = "") { var message = new MimeMessage(); message.From.Add(new MailboxAddress("", MessageFrom)); //case 3512 handle more than one email in the address if (MessageTo.Contains(",")) { List mbAll = new List(); var addrs = MessageTo.Split(','); foreach (string addr in addrs) { mbAll.Add(new MailboxAddress("", addr.Trim())); } message.To.AddRange(mbAll); } else { message.To.Add(new MailboxAddress("", MessageTo)); } message.Subject = MessageSubject; message.Body = new TextPart("plain") { Text = MessageBody }; if (CustomHeader != "" && CustomHeaderValue != "") { message.Headers["X-Rockfish-" + CustomHeader] = CustomHeaderValue; } //adapted from https://stackoverflow.com/questions/33365072/mailkit-sending-drafts using (var client = new ImapClient()) { try { // Accept all SSL certificates client.ServerCertificateValidationCallback = (s, c, h, e) => true; client.Connect(MAIL_IMAP_ADDRESS, MAIL_IMAP_PORT); // Note: since we don't have an OAuth2 token, disable // the XOAUTH2 authentication mechanism. client.AuthenticationMechanisms.Remove("XOAUTH2"); client.Authenticate(MAIL_ACCOUNT_SUPPORT, MAIL_ACCOUNT_PASSWORD_SUPPORT); var draftFolder = client.GetFolder("Drafts");//Our surgemail server works with this other servers in future might not if (draftFolder != null) { draftFolder.Open(FolderAccess.ReadWrite); draftFolder.Append(message, MessageFlags.Draft); //draftFolder.Expunge(); } } catch (Exception ex) { throw new System.Exception("RfMail->DraftMessage() - Exception has occured: " + ex.Message); } client.Disconnect(true); } }//draft message ///////////////////////////////////////////////////////////////// //Fetch summaries of unread messages in sales and support //inboxes // public static List GetSalesAndSupportSummaries() { List ret = new List(); ret.AddRange(getInboxSummariesFor(MAIL_ACCOUNT_SUPPORT, MAIL_ACCOUNT_PASSWORD_SUPPORT)); ret.AddRange(getInboxSummariesFor(MAIL_ACCOUNT_SALES, MAIL_ACCOUNT_PASSWORD_SALES)); return ret; } private static List getInboxSummariesFor(string sourceAccount, string sourcePassword) { //Console.WriteLine($"getInboxSummariesFor {sourceAccount}"); List ret = new List(); using (var client = new ImapClient()) // using (var client = new ImapClient(new ProtocolLogger(Console.OpenStandardOutput()))) { // Accept all SSL certificates client.ServerCertificateValidationCallback = (s, c, h, e) => true; //Console.WriteLine($"connecting to {MAIL_IMAP_ADDRESS} on {MAIL_IMAP_PORT}"); client.Connect(MAIL_IMAP_ADDRESS, MAIL_IMAP_PORT); // Note: since we don't have an OAuth2 token, disable // the XOAUTH2 authentication mechanism. //Console.WriteLine($"removing XOAUTH2"); client.AuthenticationMechanisms.Remove("XOAUTH2"); //Console.WriteLine($"authenticating..."); client.Authenticate(sourceAccount, sourcePassword); var inbox = client.Inbox; //Console.WriteLine($"opening inbox..."); inbox.Open(FolderAccess.ReadOnly); for (int i = 0; i < inbox.Count; i++) { var message = inbox.GetMessage(i); //Sometimes bad hombres don't set a from address so don't expect one string sFrom = "UNKNOWN / NOT SET"; if (message.From.Count > 0) { sFrom = message.From[0].ToString().Replace("\"", "").Replace("<", "").Replace(">", "").Trim(); } //get flags var summ = inbox.Fetch(new[] { i }, MessageSummaryItems.Flags | MessageSummaryItems.UniqueId); ret.Add(new rfMessageSummary { account = sourceAccount, id = summ[0].UniqueId.Id, subject = message.Subject, sent = DateUtil.DateTimeOffSetNullableToEpoch(message.Date), from = sFrom, flags = summ[0].Flags.ToString().ToLowerInvariant() }); //Console.WriteLine("Subject: {0}", message.Subject); } //This was failing with an exception //re-wrote from an example on the mailkit page and it works fine //so going with the new method now // //Console.WriteLine($"fetching summaries..."); // var summaries = inbox.Fetch(0, -1, MessageSummaryItems.Full | MessageSummaryItems.UniqueId); // //Console.WriteLine($"disconnecting..."); // client.Disconnect(true); // foreach (var summary in summaries) // { // //Sometimes bad hombres don't set a from address so don't expect one // string sFrom = "UNKNOWN / NOT SET"; // if (summary.Envelope.From.Count > 0) // { // sFrom = summary.Envelope.From[0].ToString().Replace("\"", "").Replace("<", "").Replace(">", "").Trim(); // } // ret.Add(new rfMessageSummary // { // account = sourceAccount, // id = summary.UniqueId.Id, // subject = summary.Envelope.Subject, // sent = DateUtil.DateTimeOffSetNullableToEpoch(summary.Envelope.Date), // from = sFrom, // flags = summary.Flags.ToString().ToLowerInvariant() // }); // } } //reverse the results array as emails come in oldest first order but we want oldest last ret.Reverse(); return ret; } public class rfMessageSummary { public string account { get; set; } public uint id { get; set; } public string from { get; set; } public string subject { get; set; } public long? sent { get; set; } public string flags { get; set; } } //Fetch a single string preview of message by Account / folder / UID public static rfMessagePreview GetMessagePreview(string mailAccount, string mailFolder, uint uid) { using (var client = new ImapClient()) { // Accept all SSL certificates client.ServerCertificateValidationCallback = (s, c, h, e) => true; //client.Connect(MAIL_IMAP_ADDRESS, MAIL_IMAP_PORT, true); client.Connect(MAIL_IMAP_ADDRESS, MAIL_IMAP_PORT); // Note: since we don't have an OAuth2 token, disable // the XOAUTH2 authentication mechanism. client.AuthenticationMechanisms.Remove("XOAUTH2"); //TODO: make accounts reside in dictionary in future if (mailAccount == "support@ayanova.com") { client.Authenticate(MAIL_ACCOUNT_SUPPORT, MAIL_ACCOUNT_PASSWORD_SUPPORT); } if (mailAccount == "sales@ayanova.com") { client.Authenticate(MAIL_ACCOUNT_SALES, MAIL_ACCOUNT_PASSWORD_SALES); } var fldr = client.GetFolder(mailFolder); fldr.Open(FolderAccess.ReadOnly); var m = fldr.GetMessage(new UniqueId(uid)); client.Disconnect(true); StringBuilder sb = new StringBuilder(); sb.Append("From: "); sb.AppendLine(m.From[0].ToString().Replace("\"", "").Replace("<", "").Replace(">", "").Trim()); sb.Append("To: "); sb.AppendLine(mailAccount); sb.Append("Subject: "); sb.AppendLine(m.Subject); sb.AppendLine(); sb.AppendLine(); // sb.AppendLine(m.GetTextBody(MimeKit.Text.TextFormat.Plain)); //TODO: if it's an all html email then body will be empty, so attempt to co-erce it into some readable text because the above is not working for that var theBody = m.GetTextBody(MimeKit.Text.TextFormat.Plain); if (theBody == null) { //might be an html email, try to get the text anyway var ht = m.HtmlBody; if (!string.IsNullOrWhiteSpace(ht)) { theBody = "**** HTML-ONLY MESSAGE ****"; theBody += "\r\n=-=-=-=- TEXT CONVERSION =-=-=-=-\r\n"; theBody += StripHTML(ht, true); theBody += "\r\n=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-"; theBody += "\r\n=-=-=-=- SOURCE HTML =-=-=-=-\r\n"; theBody += ht; theBody += "\r\n=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-"; theBody += "\r\n******* END MESSAGE *******"; } else { theBody = "NO MESSAGE BODY WAS FOUND NEITHER HTML NOR TEXT"; } } sb.AppendLine(theBody); rfMessagePreview preview = new rfMessagePreview(); preview.id = uid; preview.preview = sb.ToString(); preview.isKeyRequest = m.Subject.StartsWith("Request for 30 day temporary"); return preview; } }//get message public class rfMessagePreview { public bool isKeyRequest { get; set; } public string preview { get; set; } public uint id { get; set; } } //convert html to text public static string StripHTML(string HTMLText, bool decode = true) { Regex reg = new Regex("<[^>]+>", RegexOptions.IgnoreCase); var stripped = reg.Replace(HTMLText, ""); var ret = decode ? System.Web.HttpUtility.HtmlDecode(stripped) : stripped; return ret.Trim(); } /// /// /// /// /// /// /// public static IMessageSummary GetMostRecentMessageSummary(string mailAccount, string mailFolder, bool mirrorServer) { using (var client = new ImapClient()) { // Accept all SSL certificates client.ServerCertificateValidationCallback = (s, c, h, e) => true; //case 3667 fix for intermittent cert issue hopefully //https://github.com/jstedfast/MailKit/issues/515#issuecomment-439438242 client.CheckCertificateRevocation = false; //client.Connect(MAIL_IMAP_ADDRESS, MAIL_IMAP_PORT, true); if (mirrorServer) client.Connect(MAIL_MIRROR_IMAP_ADDRESS, MAIL_IMAP_PORT); else client.Connect(MAIL_IMAP_ADDRESS, MAIL_IMAP_PORT); // Note: since we don't have an OAuth2 token, disable // the XOAUTH2 authentication mechanism. client.AuthenticationMechanisms.Remove("XOAUTH2"); if (mailAccount == "support@ayanova.com") { client.Authenticate(MAIL_ACCOUNT_SUPPORT, MAIL_ACCOUNT_PASSWORD_SUPPORT); } if (mailAccount == "sales@ayanova.com") { client.Authenticate(MAIL_ACCOUNT_SALES, MAIL_ACCOUNT_PASSWORD_SALES); } var fldr = client.GetFolder(mailFolder); fldr.Open(FolderAccess.ReadOnly); //--------------- int Count = fldr.Count; var messages = fldr.Fetch(Count - 1, Count, MessageSummaryItems.Envelope).ToList(); //-------------- client.Disconnect(true); if (messages.Count > 0) return messages[0]; else return null; } }//get message ///////////////////////////////////////////////////////////////// //Validate mirroring is working // // public static bool MailIsMirroringProperly() { //check that the mirror and master contain the same most recent message in //Sent //AyaNovaReceivedSubscribed // var SentMasterSummary = GetMostRecentMessageSummary("support@ayanova.com", "Sent", false); var AyaNovaReceivedSubscribedSummary = GetMostRecentMessageSummary("support@ayanova.com", "AyaNovaReceivedSubscribed", false); var SentMirrorSummary = GetMostRecentMessageSummary("support@ayanova.com", "Sent", true); var AyaNovaReceivedSubscribedMirrorSummary = GetMostRecentMessageSummary("support@ayanova.com", "AyaNovaReceivedSubscribed", true); return SentMasterSummary.UniqueId.Id == SentMirrorSummary.UniqueId.Id && AyaNovaReceivedSubscribedSummary.UniqueId.Id == AyaNovaReceivedSubscribedMirrorSummary.UniqueId.Id; } //---------------- }//eoc }//eons