Imports System.IO Imports DigitalData.Modules.Logging Imports DigitalData.Modules.Base Imports Limilabs.Mail Imports Limilabs.Mail.MIME Imports Limilabs.Mail.MSG Imports Limilabs.Client.IMAP Imports Limilabs.Client Public Class Email2 Private ReadOnly Logger As Logger Private ReadOnly LoggerMail As Logger Private ReadOnly LogConfig As LogConfig Private ReadOnly FileEx As FilesystemEx Private ReadOnly MailBuilder As New MailBuilder() Private ReadOnly TempFiles As New List(Of String) Private DisableExcessiveLogging As Boolean = False Public Sub New(pLogConfig As LogConfig) LogConfig = pLogConfig Logger = pLogConfig.GetLogger() LoggerMail = pLogConfig.GetLogger("Limilabs.Mail") FileEx = New FilesystemEx(pLogConfig) ' Turn on internal Mail.dll logging Limilabs.Mail.Log.Enabled = True AddHandler Limilabs.Mail.Log.WriteLine, AddressOf ProcessMailLog End Sub Public Enum EmailSecurity SSL START_TLS End Enum Private Sub ProcessMailLog(pMessage As String) If DisableExcessiveLogging = False Then LoggerMail.Debug(pMessage) End If End Sub Public Function New_SMTPConnection(pSMTP As Limilabs.Client.SMTP.Smtp, pServer As String, pUsername As String, pPassword As String, pSecurity As EmailSecurity, Optional pPort As Integer = 0) As Limilabs.Client.SMTP.Smtp Try Logger.Info("Connecting to SMTP server [{0}:{1}] with user [{2}]", pServer, pPort, pUsername) Dim oPort As Integer If pPort = 0 Then If pSecurity = EmailSecurity.SSL Then oPort = Limilabs.Client.SMTP.Smtp.DefaultSSLPort Else oPort = Limilabs.Client.SMTP.Smtp.DefaultPort End If Else oPort = pPort End If Logger.Debug("Using Port [{0}] for connection", oPort) If pSecurity = EmailSecurity.SSL Then Logger.Debug("Using SSL/TLS as Security Option") pSMTP.ConnectSSL(pServer, oPort) Else Logger.Debug("Using STARTTLS as Security Option") pSMTP.Connect(pServer, oPort) pSMTP.StartTLS() End If Logger.Debug("Connection to SMTP Server [{0}] established!", pServer) If pUsername <> String.Empty Then Logger.Debug("Logging in with user [{0}]", pUsername) pSMTP.UseBestLogin(pUsername, pPassword) End If Return pSMTP Catch ex As Exception Logger.Warn("Could not connect to server [{0}] with user [{1}]", pServer, pUsername) Logger.Error(ex) Return pSMTP End Try End Function Public Function New_IMAPConnection(pServer As String, pUsername As String, pPassword As String, pSecurity As EmailSecurity, Optional pPort As Integer = 0) As Imap Try Logger.Info("Connecting to IMAP server [{0}:{1}] with user [{2}]", pServer, pPort, pUsername) Dim oIMAP As New Imap() Dim oPort As Integer If pPort = 0 Then If pSecurity = EmailSecurity.SSL Then oPort = Imap.DefaultSSLPort Else oPort = Imap.DefaultPort End If Else oPort = pPort End If Logger.Debug("Using Port [{0}] for connection", oPort) If pSecurity = EmailSecurity.SSL Then Logger.Debug("Using SSL/TLS as Security Option") oIMAP.ConnectSSL(pServer, oPort) Else Logger.Debug("Using STARTTLS as Security Option") oIMAP.Connect(pServer, oPort) oIMAP.StartTLS() End If Logger.Debug("Connection to IMAP Server [{0}] established!", pServer) Logger.Debug("Logging in with user [{0}]", pUsername) oIMAP.UseBestLogin(pUsername, pPassword) Return oIMAP Catch ex As Exception Logger.Warn("Could not connect to server [{0}] with user [{1}]", pServer, pUsername) Logger.Error(ex) Throw ex End Try End Function Public Function Test_IMAPLogin(pClient As Imap, Optional pFolder As String = "Inbox") As Boolean Logger.Info("Testing Login to IMAP Server") Try Logger.Debug("Fetching Inbox") Dim oStatus As FolderStatus = pClient.SelectInbox() Logger.Debug("Test succeeded!") Return True Catch ex As Exception Logger.Warn("Login failed for IMAP server!") Logger.Error(ex) Return False End Try End Function Public Function Test_SMTPLogin(pClient As Limilabs.Client.SMTP.Smtp) As Boolean Logger.Info("Testing Login to IMAP Server") Try Dim oExtensions = pClient.SupportedExtensions() Dim oExtensionArray = oExtensions.Select(Function(ex) ex.ToString).ToArray Logger.Debug("Supported Extensions: ") Logger.Debug(String.Join(", ", oExtensionArray)) Logger.Debug("Test succeeded!") Return True Catch ex As Exception Logger.Warn("Login failed for SMTP server!") Logger.Error(ex) Return False End Try End Function Public Function Get_IMAPMessages(pClient As Imap, Optional pFolder As String = "Inbox") As List(Of IMail) Logger.Info("Fetching Messages in Folder [{0}]", pFolder) Dim oMails As New List(Of IMail) Try Logger.Debug("Fetching Folder [{0}]", pFolder) Dim oStatus As FolderStatus = pClient.Select(pFolder) Logger.Debug("Fetching Unseen UUIDs") DisableExcessiveLogging = True Dim oUUIDs As List(Of Long) = pClient.Search(Flag.Unseen) DisableExcessiveLogging = False Logger.Debug("Fetching Unseen Mails") For Each oUUID As Long In oUUIDs DisableExcessiveLogging = True Dim oEmlFile As Byte() = pClient.GetMessageByUID(oUUID) DisableExcessiveLogging = False Dim oEmail As IMail = MailBuilder.CreateFromEml(oEmlFile) oMails.Add(oEmail) Next Logger.Debug("Emails fetched!") Return oMails Catch ex As Exception Logger.Warn("Fetching messages for folder [{0}] failed!", pFolder) Logger.Error(ex) Return New List(Of IMail) End Try End Function Public Function Get_IMAPMessage(pClient As Imap, pMessageId As String, Optional pFolder As String = "Inbox") As IMail Logger.Info("Fetching Message [{0}]", pMessageId) Dim oMail As IMail = Nothing Try Logger.Debug("Fetching Folder [{0}]", pFolder) Dim oStatus As FolderStatus = pClient.Select(pFolder) Logger.Debug("Fetching UUIDs") Dim oUUIDs As List(Of Long) = pClient.Search(Flag.All) Logger.Debug("Fetching Mails") DisableExcessiveLogging = True Dim oInfos As List(Of MessageInfo) = pClient.GetMessageInfoByUID(oUUIDs) DisableExcessiveLogging = False Dim oMailInfo = oInfos.Where(Function(i) i.Envelope.MessageID = pMessageId).FirstOrDefault() If oMailInfo IsNot Nothing Then DisableExcessiveLogging = True Dim oMailData As Byte() = pClient.GetMessageByUID(oMailInfo.UID) DisableExcessiveLogging = False oMail = MailBuilder.CreateFromEml(oMailData) End If Logger.Debug("Email fetched!") Return oMail Catch ex As Exception Logger.Warn("Fetching message with MessageID [{0}] failed!", pMessageId) Logger.Error(ex) Return Nothing End Try End Function Public Function Send_SMTPMessage(pClient As Limilabs.Client.SMTP.Smtp, pSender As String, pReceiver As String, pSubject As String, pBody As String) As Boolean Logger.Info("Sending Message with Subject [{0}]", pSubject) Try Dim oBuilder As New MailBuilder() oBuilder.From.Add(New Headers.MailBox(pSender)) oBuilder.To.Add(New Headers.MailBox(pReceiver)) oBuilder.Subject = pSubject oBuilder.Text = pBody Dim oMail As IMail = oBuilder.Create() Dim oResult As Limilabs.Client.SMTP.ISendMessageResult = pClient.SendMessage(oMail) If oResult.Status = Limilabs.Client.SMTP.SendMessageStatus.Success Then Logger.Debug("Message sent successful!") Return True Else Logger.Warn("Message sending failed. Status: [{0}]", oResult.Status) Return False End If Catch ex As Exception Logger.Warn("Message sending failed.") Logger.Error(ex) Return False End Try End Function ''' ''' Loads an eml file from disk and returns the IMail representation of it ''' ''' Path to the eml file ''' The IMail object Public Function Load_Email(pFileName As String) As IMail Dim oFileName As String = MaybeConvert_MsgToEml(pFileName) Return MailBuilder.CreateFromEmlFile(oFileName) End Function ''' ''' Removes all attachments from an EML file and saves it to a temporary file. ''' ''' The EML file to process. ''' The optional suffix to add to the original filename. ''' The path of the new EML without attachments. Public Function Remove_AttachmentsFromEmail(pFileName As String, Optional pSuffix As String = "") As String Try ' Convert possible msg file to eml Dim oEmlPath As String = MaybeConvert_MsgToEml(pFileName) ' Clean and version new path Dim oTempPath As String = Path.Combine(Path.GetTempPath(), Add_FilenameSuffix(oEmlPath, pSuffix, ".eml")) Dim oCleanedPath As String = FileEx.GetCleanPath(oTempPath) Dim oVersionedPath As String = FileEx.GetVersionedFilename(oCleanedPath) ' Load eml file Dim oMail = MailBuilder.CreateFromEmlFile(oEmlPath) ' Remove attachments and save oMail.RemoveAttachments() oMail.Save(oVersionedPath) Return oVersionedPath Catch ex As Exception Logger.Error(ex) Return Nothing End Try End Function Public Function Save_AttachmentsToDisk(pFileName As String) As List(Of String) Try Dim oAttachmentPaths As New List(Of String) Dim oEmlFile As String = MaybeConvert_MsgToEml(pFileName) Dim oMail = MailBuilder.CreateFromEmlFile(oEmlFile) Dim oTempPath As String = IO.Path.GetTempPath() If oMail.Attachments.Count = 0 Then Return New List(Of String) End If For Each oAttachment As MimeData In oMail.Attachments Dim oPath As String = IO.Path.Combine(oTempPath, oAttachment.SafeFileName) Dim oVersionedPath As String = FileEx.GetVersionedFilename(oPath) oAttachment.Save(oVersionedPath) oAttachmentPaths.Add(oVersionedPath) TempFiles.Add(oVersionedPath) Next Return oAttachmentPaths Catch ex As Exception Logger.Error(ex) Return New List(Of String) End Try End Function Public Sub Clear_TempFiles() Logger.Info("Cleaning [{0}] email temp files", TempFiles.Count) For Each oFile In TempFiles Try IO.File.Delete(oFile) Catch ex As Exception Logger.Warn("Could not clean temp file [{0}]", oFile) Logger.Error(ex) End Try Next TempFiles.Clear() End Sub Public Function Get_MessageDate(Mail As IMail) As Date Try Dim oDate = Mail.Date Return oDate Catch ex As Exception Logger.Warn("Could not get Date from Mail [{0}]", Mail.MessageID) Logger.Error(ex) Return Date.MinValue End Try End Function Public Function Get_MessageSender(Mail As IMail) As String Try Dim oAddress = Mail.From.First() If oAddress Is Nothing Then Logger.Warn("Could not get MessageSender from Mail [{0}]", Mail.MessageID) Return Nothing End If Return oAddress.Address Catch ex As Exception Logger.Warn("Could not get MessageSender from Mail [{0}]", Mail.MessageID) Logger.Error(ex) Return Nothing End Try End Function Public Function Get_MessageReceiver(Mail As IMail) As String Try Dim oAddress = Mail.To.FirstOrDefault() If oAddress Is Nothing Then Logger.Warn("Could not get MessageReceiver from Mail [{0}]", Mail.MessageID) Return Nothing End If Dim oMailBox = oAddress.GetMailboxes().First() If oMailBox Is Nothing Then Logger.Warn("Could not get MessageReceiver from Mail [{0}]", Mail.MessageID) Return Nothing End If Return oMailBox.Address Catch ex As Exception Logger.Error(ex) Return Nothing End Try End Function Public Function Convert_ToEml(pFilePath As String) As String Return MaybeConvert_MsgToEml(pFilePath) End Function Private Function MaybeConvert_MsgToEml(pEmailFilePath As String) As String Dim oInfo As New FileInfo(pEmailFilePath) If oInfo.Extension.ToUpper = ".EML" Then Return pEmailFilePath ElseIf oInfo.Extension.ToUpper = ".MSG" Then Return DoConvertMsgToEmlFile(pEmailFilePath) Else Return Nothing End If End Function Private Function DoConvertMsgToEmlFile(pMsgFile As String) As String Try Logger.Debug("Converting Msg file to Eml: [{0}]", pMsgFile?.ToString) Dim oTempPath As String = IO.Path.GetTempPath() Dim oFileNameWithoutExtension = Path.GetFileNameWithoutExtension(pMsgFile) Dim oFileNameWithoutInvalidChars = StringEx.RemoveInvalidCharacters(oFileNameWithoutExtension) Dim oEmlPath As String = IO.Path.Combine(oTempPath, $"{oFileNameWithoutInvalidChars}.eml") Dim oVersionedPath As String = FileEx.GetVersionedFilename(oEmlPath) Logger.Debug("New Path for Eml file: [{0}]", oVersionedPath) Using oConverter As New MsgConverter(pMsgFile) Logger.Debug("Converter created") Dim oEmail As IMail = oConverter.CreateMessage() Logger.Debug("Message created") Dim oData As Byte() = oEmail.Render() Logger.Debug("Message rendered") oEmail.Save(oVersionedPath) Logger.Debug("Message saved") End Using Logger.Info("Msg File successfully converted to Eml: [{0}]", oVersionedPath) TempFiles.Add(oVersionedPath) Return oVersionedPath Catch ex As Exception Logger.Warn("Converting Msg to Eml file failed!") Logger.Error(ex) Return Nothing End Try End Function Private Function Add_FilenameSuffix(pFilename As String, pSuffix As String, Optional pExtension As String = Nothing) Dim oFileInfo As New FileInfo(pFilename) Dim oExtension As String = oFileInfo.Extension If pExtension IsNot Nothing Then If pExtension.StartsWith(".") = False Then oExtension = $".{pExtension}" Else oExtension = pExtension End If End If Dim oFileNameWithoutExtension = Path.GetFileNameWithoutExtension(pFilename) Return $"{oFileNameWithoutExtension}{pSuffix}{oExtension}" End Function End Class