IMAPMailer.cs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. using InABox.Core;
  2. using MailKit;
  3. using MailKit.Net.Imap;
  4. using MailKit.Net.Smtp;
  5. using MimeKit;
  6. namespace InABox.Mail
  7. {
  8. public class IMAPMailer : CoreMailer<IMAPMailFolder, IMAPMailSummary, IMAPMailMessage>
  9. {
  10. private static ProtocolLogger imaplog;
  11. private static ProtocolLogger smtplog;
  12. private ImapClient _client;
  13. protected override void Initialize()
  14. {
  15. if (imaplog == null)
  16. imaplog = new ProtocolLogger(Path.Combine(CoreUtils.GetPath(), "imap.log"));
  17. _client = new ImapClient(imaplog);
  18. _client.ServerCertificateValidationCallback = (s, c, h, e) => true;
  19. }
  20. public override void Dispose()
  21. {
  22. if (_client.IsConnected)
  23. _client.Disconnect(true);
  24. _client.Dispose();
  25. _client = null;
  26. }
  27. protected override bool DoConnect()
  28. {
  29. try
  30. {
  31. if (_client.IsConnected)
  32. return true;
  33. _client.Connect(MailboxHost, MailboxPort == 0 ? 993 : MailboxPort, MailboxPort != 143);
  34. _client.Authenticate(MailboxUserName, MailboxPassword);
  35. return true;
  36. }
  37. catch (Exception e)
  38. {
  39. return false;
  40. }
  41. }
  42. protected override bool GetIsConnected()
  43. {
  44. return _client.IsConnected;
  45. }
  46. protected override IMAPMailMessage DoCreateMessage()
  47. {
  48. return new IMAPMailMessage(null, UniqueId.MinValue, new MimeMessage());
  49. }
  50. protected override IMAPMailFolder DoFindFolder(IMAPMailFolder parent, string name)
  51. {
  52. if (string.IsNullOrEmpty(name))
  53. return parent;
  54. return new IMAPMailFolder(parent.Folder.GetSubfolder(name));
  55. }
  56. protected override IMAPMailFolder GetInbox()
  57. {
  58. return new IMAPMailFolder(_client.Inbox);
  59. }
  60. protected override IMAPMailFolder GetSentItems()
  61. {
  62. if ((_client.Capabilities & (ImapCapabilities.SpecialUse | ImapCapabilities.XList)) != 0)
  63. return new IMAPMailFolder(_client.GetFolder(SpecialFolder.Sent));
  64. string[] CommonSentFolderNames = { "Sent", "Sent Items", "Sent Mail", "Sent Messages" /* maybe add some translated names */ };
  65. var personal = _client.GetFolder(_client.PersonalNamespaces[0]);
  66. var folder = personal.GetSubfolders().FirstOrDefault(x => CommonSentFolderNames.Contains(x.Name));
  67. if (folder != null)
  68. return new IMAPMailFolder(folder);
  69. throw new Exception("Cannot find Sent Items Folder!");
  70. }
  71. protected override IMAPMailMessage DoGetMessage(IMAPMailFolder folder, string id)
  72. {
  73. var fld = folder != null ? folder.Folder : _client.Inbox;
  74. if (!fld.IsOpen)
  75. fld.Open(FolderAccess.ReadWrite);
  76. var uid = UniqueId.Parse(id);
  77. var msg = fld.GetMessage(uid);
  78. return new IMAPMailMessage(fld, uid, msg);
  79. }
  80. protected override IEnumerable<IMAPMailMessage> DoGetMessages(IMAPMailFolder folder)
  81. {
  82. var results = new List<IMAPMailMessage>();
  83. var fld = folder != null ? folder.Folder : _client.Inbox;
  84. if (!fld.IsOpen)
  85. fld.Open(FolderAccess.ReadWrite);
  86. var summaries = fld.Fetch(0, -1, MessageSummaryItems.UniqueId | MessageSummaryItems.Flags);
  87. foreach (var summary in summaries)
  88. if (!summary.Flags.HasValue || !summary.Flags.Value.HasFlag(MessageFlags.Deleted))
  89. {
  90. var msg = fld.GetMessage(summary.UniqueId);
  91. results.Add(new IMAPMailMessage(fld, summary.UniqueId, msg));
  92. }
  93. return results;
  94. }
  95. protected override IEnumerable<IMAPMailSummary> DoListMessages(IMAPMailFolder folder, int min = 0, int max = int.MaxValue)
  96. {
  97. var fld = folder != null ? folder.Folder : _client.Inbox;
  98. if (!fld.IsOpen)
  99. fld.Open(FolderAccess.ReadOnly);
  100. var summaries = fld.Fetch(min, max, MessageSummaryItems.UniqueId | MessageSummaryItems.Flags | MessageSummaryItems.Envelope);
  101. return summaries.Where(x => !x.Flags.Value.HasFlag(MessageFlags.Deleted)).Select(x => new IMAPMailSummary(fld, x));
  102. }
  103. protected override bool DoMoveMessage(IMAPMailMessage message, IMAPMailFolder to)
  104. {
  105. message.Move(to != null ? to.Folder : _client.Inbox);
  106. return true;
  107. }
  108. private bool UsesSSL(int port)
  109. {
  110. return port != 25;
  111. }
  112. protected override bool DoSendMessage(IMAPMailMessage message)
  113. {
  114. if (smtplog == null)
  115. smtplog = new ProtocolLogger(Path.Combine(CoreUtils.GetPath(), "smtp.log"));
  116. using (var smtp = new SmtpClient(smtplog))
  117. {
  118. smtp.ServerCertificateValidationCallback = (s, c, h, e) => true;
  119. smtp.Connect(SMTPHost, SMTPPort == 0 ? 587 : SMTPPort, SMTPPort == 465);
  120. smtp.Authenticate(SMTPUserName, SMTPPassword);
  121. smtp.Send(message.Message);
  122. if ((_client.Capabilities & (ImapCapabilities.SpecialUse | ImapCapabilities.XList)) != 0)
  123. {
  124. var sent = _client.GetFolder(SpecialFolder.Sent);
  125. sent.Open(FolderAccess.ReadWrite);
  126. var id = sent.Append(message.Message).Value;
  127. sent.SetFlags(id, MessageFlags.Seen, true);
  128. }
  129. smtp.Disconnect(true);
  130. }
  131. return true;
  132. }
  133. protected override bool DoSaveDraft(IMAPMailMessage message)
  134. {
  135. var draftFolder = _client.GetFolder(SpecialFolder.Drafts);
  136. if (draftFolder == null)
  137. {
  138. var toplevel = _client.GetFolder(_client.PersonalNamespaces[0]);
  139. draftFolder = toplevel.Create(SpecialFolder.Drafts.ToString(), true);
  140. }
  141. message.Move(draftFolder);
  142. draftFolder.SetFlags(message.UniqueID, MessageFlags.Draft, true);
  143. draftFolder.Expunge();
  144. return true;
  145. }
  146. }
  147. }