using InABox.Core; using MailKit; using MailKit.Net.Imap; using MailKit.Net.Smtp; using MimeKit; namespace InABox.Mail { public class IMAPMailer : CoreMailer { private static ProtocolLogger imaplog; private static ProtocolLogger smtplog; private ImapClient _client; protected override void Initialize() { if (imaplog == null) imaplog = new ProtocolLogger(Path.Combine(CoreUtils.GetPath(), "imap.log")); _client = new ImapClient(imaplog); _client.ServerCertificateValidationCallback = (s, c, h, e) => true; } public override void Dispose() { if (_client.IsConnected) _client.Disconnect(true); _client.Dispose(); _client = null; } protected override bool DoConnect() { try { if (_client.IsConnected) return true; _client.Connect(MailboxHost, MailboxPort == 0 ? 993 : MailboxPort, MailboxPort != 143); _client.Authenticate(MailboxUserName, MailboxPassword); return true; } catch (Exception e) { return false; } } protected override bool GetIsConnected() { return _client.IsConnected; } protected override IMAPMailMessage DoCreateMessage() { return new IMAPMailMessage(null, UniqueId.MinValue, new MimeMessage()); } protected override IMAPMailFolder DoFindFolder(IMAPMailFolder parent, string name) { if (string.IsNullOrEmpty(name)) return parent; return new IMAPMailFolder(parent.Folder.GetSubfolder(name)); } protected override IMAPMailFolder GetInbox() { return new IMAPMailFolder(_client.Inbox); } protected override IMAPMailFolder GetSentItems() { if ((_client.Capabilities & (ImapCapabilities.SpecialUse | ImapCapabilities.XList)) != 0) return new IMAPMailFolder(_client.GetFolder(SpecialFolder.Sent)); string[] CommonSentFolderNames = { "Sent", "Sent Items", "Sent Mail", "Sent Messages" /* maybe add some translated names */ }; var personal = _client.GetFolder(_client.PersonalNamespaces[0]); var folder = personal.GetSubfolders().FirstOrDefault(x => CommonSentFolderNames.Contains(x.Name)); if (folder != null) return new IMAPMailFolder(folder); throw new Exception("Cannot find Sent Items Folder!"); } protected override IMAPMailMessage DoGetMessage(IMAPMailFolder folder, string id) { var fld = folder != null ? folder.Folder : _client.Inbox; if (!fld.IsOpen) fld.Open(FolderAccess.ReadWrite); var uid = UniqueId.Parse(id); var msg = fld.GetMessage(uid); return new IMAPMailMessage(fld, uid, msg); } protected override IEnumerable DoGetMessages(IMAPMailFolder folder) { var results = new List(); var fld = folder != null ? folder.Folder : _client.Inbox; if (!fld.IsOpen) fld.Open(FolderAccess.ReadWrite); var summaries = fld.Fetch(0, -1, MessageSummaryItems.UniqueId | MessageSummaryItems.Flags); foreach (var summary in summaries) if (!summary.Flags.HasValue || !summary.Flags.Value.HasFlag(MessageFlags.Deleted)) { var msg = fld.GetMessage(summary.UniqueId); results.Add(new IMAPMailMessage(fld, summary.UniqueId, msg)); } return results; } protected override IEnumerable DoListMessages(IMAPMailFolder folder, int min = 0, int max = int.MaxValue) { var fld = folder != null ? folder.Folder : _client.Inbox; if (!fld.IsOpen) fld.Open(FolderAccess.ReadOnly); var summaries = fld.Fetch(min, max, MessageSummaryItems.UniqueId | MessageSummaryItems.Flags | MessageSummaryItems.Envelope); return summaries.Where(x => !x.Flags.Value.HasFlag(MessageFlags.Deleted)).Select(x => new IMAPMailSummary(fld, x)); } protected override bool DoMoveMessage(IMAPMailMessage message, IMAPMailFolder to) { message.Move(to != null ? to.Folder : _client.Inbox); return true; } private bool UsesSSL(int port) { return port != 25; } protected override bool DoSendMessage(IMAPMailMessage message) { if (smtplog == null) smtplog = new ProtocolLogger(Path.Combine(CoreUtils.GetPath(), "smtp.log")); using (var smtp = new SmtpClient(smtplog)) { smtp.ServerCertificateValidationCallback = (s, c, h, e) => true; smtp.Connect(SMTPHost, SMTPPort == 0 ? 587 : SMTPPort, SMTPPort == 465); smtp.Authenticate(SMTPUserName, SMTPPassword); smtp.Send(message.Message); if ((_client.Capabilities & (ImapCapabilities.SpecialUse | ImapCapabilities.XList)) != 0) { var sent = _client.GetFolder(SpecialFolder.Sent); sent.Open(FolderAccess.ReadWrite); var id = sent.Append(message.Message).Value; sent.SetFlags(id, MessageFlags.Seen, true); } smtp.Disconnect(true); } return true; } protected override bool DoSaveDraft(IMAPMailMessage message) { var draftFolder = _client.GetFolder(SpecialFolder.Drafts); if (draftFolder == null) { var toplevel = _client.GetFolder(_client.PersonalNamespaces[0]); draftFolder = toplevel.Create(SpecialFolder.Drafts.ToString(), true); } message.Move(draftFolder); draftFolder.SetFlags(message.UniqueID, MessageFlags.Draft, true); draftFolder.Expunge(); return true; } } }