869 lines
34 KiB
C#
869 lines
34 KiB
C#
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
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Forward a message to the isspam@ayanova.com address and then erase it
|
|
/// </summary>
|
|
/// <param name="spamMessageId"></param>
|
|
/// <param name="replyFromAccount"></param>
|
|
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
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Move to sub or unsub mail folder and mark as read
|
|
/// </summary>
|
|
/// <param name="moveMessageId"></param>
|
|
/// <param name="replyFromAccount"></param>
|
|
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<rfMailMessage> GetMessages(SearchQuery query)
|
|
{
|
|
List<rfMailMessage> ret = new List<rfMailMessage>();
|
|
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<MailboxAddress> mbAll = new List<MailboxAddress>();
|
|
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<rfMessageSummary> GetSalesAndSupportSummaries()
|
|
{
|
|
List<rfMessageSummary> ret = new List<rfMessageSummary>();
|
|
|
|
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<rfMessageSummary> getInboxSummariesFor(string sourceAccount, string sourcePassword)
|
|
{
|
|
//Console.WriteLine($"getInboxSummariesFor {sourceAccount}");
|
|
List<rfMessageSummary> ret = new List<rfMessageSummary>();
|
|
|
|
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();
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="mailAccount"></param>
|
|
/// <param name="mailFolder"></param>
|
|
/// <param name="mirrorServer"></param>
|
|
/// <returns></returns>
|
|
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
|