Messaging: Add SMTP Functions, inital tests

This commit is contained in:
Jonathan Jenne 2021-07-26 16:32:06 +02:00
parent 999e2e617b
commit 0f0b517c56
2 changed files with 237 additions and 119 deletions

View File

@ -7,28 +7,34 @@ Public Class frmEmail
Private Email As Email2 Private Email As Email2
Private Sub frmEmail_Load(sender As Object, e As EventArgs) Handles Me.Load Private Sub frmEmail_Load(sender As Object, e As EventArgs) Handles Me.Load
Logconfig = New LogConfig(LogConfig.PathType.Temp) Logconfig = New LogConfig(LogConfig.PathType.Temp, ProductName:="TestGUI.IMAP")
Logconfig.Debug = True
Email = New Email2(Logconfig) Email = New Email2(Logconfig)
End Sub End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim oResult = Email.Test_Login(txtServer.Text, txtUser.Text, txtPassword.Text, Email2.EmailSecurity.SSLTLS) Using oClient = Email.New_IMAPConnection(txtServer.Text, txtUser.Text, txtPassword.Text, Email2.EmailSecurity.SSL)
Dim oResult = Email.Test_IMAPLogin(oClient, "Inbox")
If oResult = True Then If oResult = True Then
AddLog($"Connection to {txtServer.Text} successful.") AddLog($"Connection to {txtServer.Text} successful.")
Else Else
AddLog($"Connection to {txtServer.Text} failed!") AddLog($"Connection to {txtServer.Text} failed!")
End If End If
End Using
End Sub End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim oMessages = Email.Get_Messages(txtServer.Text, txtUser.Text, txtPassword.Text, Email2.EmailSecurity.SSLTLS, "Inbox")
AddLog($"Found {oMessages.Count} Messages!")
For Each oMessage In oMessages Using oClient = Email.New_IMAPConnection(txtServer.Text, txtUser.Text, txtPassword.Text, Email2.EmailSecurity.SSL)
AddLog(oMessage.MessageID) Dim oMessages = Email.Get_IMAPMessages(oClient, "Inbox")
Next AddLog($"Found {oMessages.Count} Messages!")
For Each oMessage In oMessages
AddLog(oMessage.MessageID)
Next
End Using
End Sub End Sub
Private Sub AddLog(pMessage) Private Sub AddLog(pMessage)
@ -36,22 +42,24 @@ Public Class frmEmail
End Sub End Sub
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
Dim oMessageId As String = txtMessageID.Text Using oClient = Email.New_IMAPConnection(txtServer.Text, txtUser.Text, txtPassword.Text, Email2.EmailSecurity.SSL)
Dim oMail As IMail = Email.Get_Message(txtServer.Text, txtUser.Text, txtPassword.Text, Email2.EmailSecurity.SSLTLS, oMessageId, "Inbox") Dim oMessageId As String = txtMessageID.Text
Dim oFilename As String = IO.Path.GetTempFileName Dim oMail As IMail = Email.Get_IMAPMessage(oClient, oMessageId, "Inbox")
oMail.Save(oFilename) Dim oFilename As String = IO.Path.GetTempFileName
oMail.Save(oFilename)
AddLog($"Mail saved to {oFilename}") AddLog($"Mail saved to {oFilename}")
Dim oEmailTempPath = Email.Remove_AttachmentsFromEmail(oFilename) Dim oEmailTempPath = Email.Remove_AttachmentsFromEmail(oFilename)
AddLog($"Mail without attachments saved to {oEmailTempPath}") AddLog($"Mail without attachments saved to {oEmailTempPath}")
Dim oAttachments As List(Of String) = Email.Save_AttachmentsToDisk(oFilename) Dim oAttachments As List(Of String) = Email.Save_AttachmentsToDisk(oFilename)
For Each oAttachment In oAttachments For Each oAttachment In oAttachments
AddLog($"Attachmen saved to {oAttachment}") AddLog($"Attachmen saved to {oAttachment}")
Next Next
End Using
End Sub End Sub
Private Sub ListBox1_SelectedValueChanged(sender As Object, e As EventArgs) Handles ListBox1.SelectedValueChanged Private Sub ListBox1_SelectedValueChanged(sender As Object, e As EventArgs) Handles ListBox1.SelectedValueChanged

View File

@ -1,168 +1,238 @@
Imports DigitalData.Modules.Logging Imports System.IO
Imports DigitalData.Modules.Logging
Imports DigitalData.Modules.Filesystem Imports DigitalData.Modules.Filesystem
Imports Limilabs.Mail Imports Limilabs.Mail
Imports Limilabs.Client.IMAP
Imports Limilabs.Mail.MIME Imports Limilabs.Mail.MIME
Imports System.IO
Imports Limilabs.Mail.MSG Imports Limilabs.Mail.MSG
Imports Limilabs.Client.IMAP
Imports Limilabs.Client.SMTP
Imports Limilabs.Client
Public Class Email2 Public Class Email2
Private ReadOnly Logger As Logger Private ReadOnly Logger As Logger
Private ReadOnly LoggerMail As Logger
Private ReadOnly LogConfig As LogConfig Private ReadOnly LogConfig As LogConfig
Private ReadOnly FileEx As Filesystem.File Private ReadOnly FileEx As Filesystem.File
Private ReadOnly MailBuilder As New MailBuilder() Private ReadOnly MailBuilder As New MailBuilder()
Private DisableExcessiveLogging As Boolean = False
Public Sub New(pLogConfig As LogConfig) Public Sub New(pLogConfig As LogConfig)
LogConfig = pLogConfig LogConfig = pLogConfig
Logger = pLogConfig.GetLogger() Logger = pLogConfig.GetLogger()
LoggerMail = pLogConfig.GetLogger("Limilabs.Mail")
FileEx = New Filesystem.File(pLogConfig) 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 End Sub
Public Enum EmailSecurity Public Enum EmailSecurity
SSLTLS SSL
STARTTLS START_TLS
End Enum End Enum
Private Function Get_PortForSecurityOption(pSecurity As EmailSecurity) As Integer Private Sub ProcessMailLog(pMessage As String)
If pSecurity = EmailSecurity.STARTTLS Then If DisableExcessiveLogging = False Then
Return 143 LoggerMail.Debug(pMessage)
Else ' EmailSecurity.SSL
Return 993
End If End If
End Function End Sub
Private Function New_Connection(pIMAP As Imap, pServer As String, pUsername As String, pPassword As String, pPort As Integer, pSecurity As EmailSecurity) As Boolean 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 Try
Logger.Debug("Connecting to IMAP server [{0}]", pServer) 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
Dim oPort As Integer = pPort
If oPort = 0 Then
oPort = Get_PortForSecurityOption(pSecurity)
End If End If
Logger.Debug("Using Port [{0}] for connection", oPort) Logger.Debug("Using Port [{0}] for connection", oPort)
If pSecurity = EmailSecurity.STARTTLS Then If pSecurity = EmailSecurity.SSL Then
Logger.Debug("Using STARTTLS as Security Option")
pIMAP.Connect(pServer, oPort)
pIMAP.StartTLS()
Else
Logger.Debug("Using SSL/TLS as Security Option") Logger.Debug("Using SSL/TLS as Security Option")
pIMAP.ConnectSSL(pServer, oPort) pSMTP.ConnectSSL(pServer, oPort)
Else
Logger.Debug("Using STARTTLS as Security Option")
pSMTP.Connect(pServer, oPort)
pSMTP.StartTLS()
End If End If
Logger.Debug("Connection to IMAP Server [{0}] established!", pServer) Logger.Debug("Connection to SMTP Server [{0}] established!", pServer)
Logger.Debug("Logging in with user [{0}]", pUsername) Logger.Debug("Logging in with user [{0}]", pUsername)
pIMAP.UseBestLogin(pUsername, pPassword) pSMTP.UseBestLogin(pUsername, pPassword)
Return True Return pSMTP
Catch ex As Exception Catch ex As Exception
Logger.Warn("Could not connect to server [{0}] with user [{1}]", pServer, pUsername) Logger.Warn("Could not connect to server [{0}] with user [{1}]", pServer, pUsername)
Logger.Error(ex) Logger.Error(ex)
Return False Return pSMTP
End Try End Try
End Function End Function
Public Function Test_Login(pServer As String, pUsername As String, pPassword As String, pSecurity As EmailSecurity, Optional pFolder As String = "Inbox", Optional pPort As Integer = 0) As Boolean Public Function New_IMAPConnection(pServer As String, pUsername As String, pPassword As String, pSecurity As EmailSecurity, Optional pPort As Integer = 0) As Imap
Logger.Debug("Testing Login to Server [{0}:{1}] with user [{2}]", pServer, pPort, pUsername)
Try Try
Using oClient As New Imap() Logger.Info("Connecting to IMAP server [{0}:{1}] with user [{2}]", pServer, pPort, pUsername)
If New_Connection(oClient, pServer, pUsername, pPassword, pPort, pSecurity) Then
Logger.Debug("Fetching Inbox")
Dim oStatus As FolderStatus = oClient.SelectInbox()
Logger.Debug("Test finished!") Dim oIMAP As New Imap()
oClient.Close() Dim oPort As Integer
If pPort = 0 Then
If pSecurity = EmailSecurity.SSL Then
oPort = Imap.DefaultSSLPort
Else
oPort = Imap.DefaultPort
End If End If
End Using 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 Return True
Catch ex As Exception Catch ex As Exception
Logger.Warn("Login failed for server [{0}:{1}] with user [{2}]!", pServer, pPort, pUsername) Logger.Warn("Login failed for IMAP server!")
Logger.Error(ex) Logger.Error(ex)
Return False Return False
End Try End Try
End Function End Function
Public Function Get_Messages(pServer As String, pUsername As String, pPassword As String, pSecurity As EmailSecurity, Optional pFolder As String = "Inbox", Optional pPort As Integer = 0) As List(Of IMail) Public Function Test_SMTPLogin(pClient As Smtp) As Boolean
Logger.Debug("Fetching Messages from Server [{0}:{1}] with user [{2}]", pServer, pPort, pUsername) 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) Dim oMails As New List(Of IMail)
Try Try
Using oClient As New Imap() Logger.Debug("Fetching Folder [{0}]", pFolder)
If New_Connection(oClient, pServer, pUsername, pPassword, pPort, pSecurity) Then Dim oStatus As FolderStatus = pClient.Select(pFolder)
Logger.Debug("Fetching Folder [{0}]", pFolder)
Dim oStatus As FolderStatus = oClient.Select(pFolder)
Logger.Debug("Fetching Unseen UUIDs") Logger.Debug("Fetching Unseen UUIDs")
Dim oUUIDs As List(Of Long) = oClient.Search(Flag.Unseen)
Dim oMailBuilder As New MailBuilder()
Logger.Debug("Fetching Unseen Mails") DisableExcessiveLogging = True
For Each oUUID As Long In oUUIDs Dim oUUIDs As List(Of Long) = pClient.Search(Flag.Unseen)
Dim oEmlFile As Byte() = oClient.GetMessageByUID(oUUID) DisableExcessiveLogging = False
Dim oEmail As IMail = oMailBuilder.CreateFromEml(oEmlFile)
oMails.Add(oEmail)
Next Logger.Debug("Fetching Unseen Mails")
For Each oUUID As Long In oUUIDs
DisableExcessiveLogging = True
Dim oEmlFile As Byte() = pClient.GetMessageByUID(oUUID)
DisableExcessiveLogging = False
Logger.Debug("Emails fetched!") Dim oEmail As IMail = MailBuilder.CreateFromEml(oEmlFile)
oClient.Close() oMails.Add(oEmail)
End If Next
End Using Logger.Debug("Emails fetched!")
Return oMails Return oMails
Catch ex As Exception Catch ex As Exception
Logger.Warn("Login failed for server [{0}:{1}] with user [{2}]!", pServer, pPort, pUsername) Logger.Warn("Fetching messages for folder [{0}] failed!", pFolder)
Logger.Error(ex) Logger.Error(ex)
Return New List(Of IMail) Return New List(Of IMail)
End Try End Try
End Function End Function
Public Function Get_Message(pServer As String, pUsername As String, pPassword As String, pSecurity As EmailSecurity, pMessageId As String, Optional pFolder As String = "Inbox", Optional pPort As Integer = 0) As IMail Public Function Get_IMAPMessage(pClient As Imap, pMessageId As String, Optional pFolder As String = "Inbox") As IMail
Logger.Debug("Fetching Message [{0}] from Server [{1}:{2}] with user [{3}]", pMessageId, pServer, pPort, pUsername) Logger.Info("Fetching Message [{0}]", pMessageId)
Dim oMail As IMail = Nothing Dim oMail As IMail = Nothing
Try Try
Using oClient As New Imap() Logger.Debug("Fetching Folder [{0}]", pFolder)
If New_Connection(oClient, pServer, pUsername, pPassword, pPort, pSecurity) Then Dim oStatus As FolderStatus = pClient.Select(pFolder)
Logger.Debug("Fetching Folder [{0}]", pFolder)
Dim oStatus As FolderStatus = oClient.Select(pFolder)
Logger.Debug("Fetching UUIDs") Logger.Debug("Fetching UUIDs")
Dim oUUIDs As List(Of Long) = oClient.Search(Flag.All) Dim oUUIDs As List(Of Long) = pClient.Search(Flag.All)
Logger.Debug("Fetching Mails") Logger.Debug("Fetching Mails")
Dim oInfos As List(Of MessageInfo) = oClient.GetMessageInfoByUID(oUUIDs)
Dim oMailInfo = oInfos.Where(Function(i) i.Envelope.MessageID = pMessageId).FirstOrDefault() DisableExcessiveLogging = True
Dim oInfos As List(Of MessageInfo) = pClient.GetMessageInfoByUID(oUUIDs)
DisableExcessiveLogging = False
If oMailInfo IsNot Nothing Then Dim oMailInfo = oInfos.Where(Function(i) i.Envelope.MessageID = pMessageId).FirstOrDefault()
Dim oMailData As Byte() = oClient.GetMessageByUID(oMailInfo.UID)
oMail = MailBuilder.CreateFromEml(oMailData)
End If
Logger.Debug("Emails fetched!") If oMailInfo IsNot Nothing Then
oClient.Close() DisableExcessiveLogging = True
Dim oMailData As Byte() = pClient.GetMessageByUID(oMailInfo.UID)
DisableExcessiveLogging = False
oMail = MailBuilder.CreateFromEml(oMailData)
End If
End If Logger.Debug("Email fetched!")
End Using
Return oMail Return oMail
Catch ex As Exception Catch ex As Exception
Logger.Warn("Login failed for server [{0}:{1}] with user [{2}]!", pServer, pPort, pUsername) Logger.Warn("Fetching message with MessageID [{0}] failed!", pMessageId)
Logger.Error(ex) Logger.Error(ex)
Return Nothing Return Nothing
@ -170,15 +240,54 @@ Public Class Email2
End Try End Try
End Function 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>
''' 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 Public Function Remove_AttachmentsFromEmail(pFileName As String, Optional pSuffix As String = "") As String
Try Try
Dim oTempFileName As String = Path.Combine(Path.GetTempPath(), AddFilenameSuffix(pFileName, pSuffix)) Dim oTempPath As String = Path.Combine(Path.GetTempPath(), Add_FilenameSuffix(pFileName, pSuffix))
Dim oCleanedPath As String = FileEx.GetCleanFilename(oTempPath)
Dim oVersionedPath As String = FileEx.GetVersionedFilename(oCleanedPath)
Dim oMail = MailBuilder.CreateFromEmlFile(pFileName) Dim oMail = MailBuilder.CreateFromEmlFile(pFileName)
oMail.RemoveAttachments() oMail.RemoveAttachments()
oMail.Save(oTempFileName) oMail.Save(oVersionedPath)
Return oTempFileName Return oVersionedPath
Catch ex As Exception Catch ex As Exception
Logger.Error(ex) Logger.Error(ex)
@ -186,6 +295,10 @@ Public Class Email2
End Try End Try
End Function End Function
Public Function Load_Email(pFileName As String) As IMail
Return MailBuilder.CreateFromEmlFile(pFileName)
End Function
Public Function Save_AttachmentsToDisk(pFileName As String) As List(Of String) Public Function Save_AttachmentsToDisk(pFileName As String) As List(Of String)
Try Try
Dim oAttachmentPaths As New List(Of String) Dim oAttachmentPaths As New List(Of String)
@ -212,7 +325,7 @@ Public Class Email2
End Try End Try
End Function End Function
Public Function ConvertMsgToEml(pEmailFileName As String) As String Public Function Convert_MsgToEml(pEmailFileName As String) As String
Dim oInfo As New FileInfo(pEmailFileName) Dim oInfo As New FileInfo(pEmailFileName)
If oInfo.Extension.ToUpper = ".EML" Then If oInfo.Extension.ToUpper = ".EML" Then
@ -229,38 +342,35 @@ Public Class Email2
Private Function DoConvertMsgToEmlFile(pMsgFile As String) As String Private Function DoConvertMsgToEmlFile(pMsgFile As String) As String
Try Try
Dim oTempPath As String = IO.Path.GetTempPath()
Dim oFileNameWithoutExtension = Path.GetFileNameWithoutExtension(pMsgFile) Dim oFileNameWithoutExtension = Path.GetFileNameWithoutExtension(pMsgFile)
Dim oEmlPath As String = $"{oFileNameWithoutExtension}.eml" Dim oEmlPath As String = IO.Path.Combine(oTempPath, $"{oFileNameWithoutExtension}.eml")
Dim oVersionedPath As String = FileEx.GetVersionedFilename(oEmlPath)
Using oConverter As New MsgConverter(pMsgFile) Using oConverter As New MsgConverter(pMsgFile)
Dim oEmail As IMail = oConverter.CreateMessage() Dim oEmail As IMail = oConverter.CreateMessage()
Dim oData As Byte() = oEmail.Render() Dim oData As Byte() = oEmail.Render()
oEmail.Save(oEmlPath) oEmail.Save(oVersionedPath)
End Using End Using
Return oEmlPath Return oVersionedPath
Catch ex As Exception Catch ex As Exception
Return Nothing Logger.Warn("Converting Msg to Eml file failed!")
Logger.Error(ex)
Return Nothing
End Try End Try
End Function End Function
Private Function GetTempFileNameWithExtension(pExtension As String) As String Private Function Add_FilenameSuffix(pFilename As String, pSuffix As String)
Dim oTempFileName As String = IO.Path.GetTempFileName()
Dim oInfo As New IO.FileInfo(oTempFileName)
Dim oExtension As String = IIf(pExtension.StartsWith("."), pExtension, $".{pExtension}")
Dim oNewFileName = IO.Path.Combine(oInfo.DirectoryName, oInfo.Name.Replace(oInfo.Extension, oExtension))
Return oNewFileName
End Function
Private Function AddFilenameSuffix(pFilename As String, pSuffix As String)
Dim oFileInfo As New FileInfo(pFilename) Dim oFileInfo As New FileInfo(pFilename)
Dim oExtension As String = oFileInfo.Extension Dim oExtension As String = oFileInfo.Extension
Dim oFileNameWithoutExtension = Path.GetFileNameWithoutExtension(pFilename) Dim oFileNameWithoutExtension = Path.GetFileNameWithoutExtension(pFilename)
Return $"{oFileNameWithoutExtension}{pSuffix}{oExtension}" Return $"{oFileNameWithoutExtension}{pSuffix}{oExtension}"
End Function End Function
End Class End Class