Search code examples
powershellmailkitmimekit

How to convert attachments to Base64


I am a bit in over my head and need help. I am trying to build a mail integration tool that will check POP3 and IMAP4 mailboxes for emails and import them to another system. The system that I want to import the emails to can only handle attachment as Base64 strings.

I am using PowerShell 7.1 with the module Mailozaurr (https://github.com/EvotecIT/Mailozaurr), Mailozaurr uses MailKit and MimeKit under the hood, in order to connect to POP3 and IMAP4 server and gather/download/collect any emails. I will then convert the different properties of the email to a XML-object and send it to the systems web api. When converting the email to a XML-object any attachments from the email need to be added to the XML-object as such:

<Attachment name="filename">base64string</sch:Attachment>

My code now looks like this for collecting emails and enumerating its properties.

$pop3BasicConnParams = @{
    Server = "$($configuration.host)"
    Password = "$($configuration.password)"
    UserName = "$($configuration.login)"
    Port = $port
}
$Client = Connect-POP @pop3BasicConnParams -Options Auto
$emailItems = Get-POPMessage -Client $Client -Index 0 -Count 1
foreach ($email in $emailItems) {
    $emailProperties = @{}
    $emailProperties.Add("to","$($email.to.Address)")
    $emailProperties.Add("from","$($email.from.Address)")
    $emailProperties.Add("subject","$($email.subject)")
    $emailProperties.Add("body_plain","$($email.TextBody)")
    foreach ($attachment in $email.Attachments) {
        if ($attachment.IsAttachment -eq 'True') {
            # code to convert attachment to base64 string
            $attachmentStream = $attachment.Content.Stream
            $bytes = [System.IO.StreamReader]::new($attachmentStream)
            $B64String = [System.Convert]::ToBase64String($bytes)
            $filename = "$($attachment.Content.Filename)"
            $emailProperties.Add("$filename","$base64string")
            $attachment.Content.Stream.Flush()
            $attachment.Content.Stream.Dispose()
        }
    }
}
Disconnect-POP3 -Client $Client

Since I do not have any knowledge or experience with MailKit, MimeKit or .Net I do not know how to convert attachment to a base64string (what to replace '# code to convert attachment to base64 string' with). May I please have some help with this?

Thanks in advance, Anders.

-- Update --

This: $filename = "$($attachment.Content.Filename)"

Should be: $filename = "$($attachment.Filename)"


Solution

  • You would probably do something like this (keep in mind I'm not good with Powershell scripting, so syntax may be off):

    # code to convert attachment to base64 string:
    # Step 1: decode the content into a memory stream (so we can get the raw bytes)
    $contentStream = [System.IO.MemoryStream]::new()
    $attachment.Content.DecodeTo($contentStream)
    # Step 2: Get the raw content in byte array form
    $bytes = $contentStream.ToArray()
    # Step 3: dispose the memory stream because we don't need it anymore
    $contentStream.Dispose()
    # Step 4: convert the raw attachment content into a base64 string
    $b64String = [System.Convert]::ToBase64String($bytes)
    $filename = "$($attachment.Filename)"
    $emailProperties.Add("$filename","$b64string")
    

    May also be worth mentioning that you don't need the surrounding if ($attachment.IsAttachment -eq 'True') { since the $email.Attachments list is already limited to only items where IsAttachment is true.

    There are ways to optimize this a bit more since it's possible for the content to already be base64 encoded (although it would have line breaks which would need to be removed), but this is a script and it's probably not worth making this overly complicated.