2022-02-01 16:30:47 +01:00

482 lines
16 KiB
VB.net

Imports System.IO
Imports DigitalData.Modules.Logging
Imports DigitalData.Modules.Filesystem
Imports Limilabs.Mail
Imports Limilabs.Mail.MIME
Imports Limilabs.Mail.MSG
Imports Limilabs.Client.IMAP
Imports Limilabs.Client.SMTP
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 Filesystem.File
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 Filesystem.File(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 Smtp, pServer As String, pUsername As String, pPassword As String, pSecurity As EmailSecurity, Optional pPort As Integer = 0) As 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 = Smtp.DefaultSSLPort
Else
oPort = 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)
Logger.Debug("Logging in with user [{0}]", pUsername)
pSMTP.UseBestLogin(pUsername, pPassword)
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 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 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 ISendMessageResult = pClient.SendMessage(oMail)
If oResult.Status = 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
''' <summary>
''' Loads an eml file from disk and returns the IMail representation of it
''' </summary>
''' <param name="pFileName">Path to the eml file</param>
''' <returns>The IMail object</returns>
Public Function Load_Email(pFileName As String) As IMail
Dim oFileName As String = MaybeConvert_MsgToEml(pFileName)
Return MailBuilder.CreateFromEmlFile(oFileName)
End Function
''' <summary>
''' Removes all attachments from an EML file and saves it to a temporary file.
''' </summary>
''' <param name="pFileName">The EML file to process.</param>
''' <param name="pSuffix">The optional suffix to add to the original filename.</param>
''' <returns>The path of the new EML without attachments.</returns>
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
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 = Language.Utils.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