Anders Thyrsson
Anders Thyrsson

Reputation: 67

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)"

Upvotes: 0

Views: 1544

Answers (2)

jstedfast
jstedfast

Reputation: 38528

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.

Upvotes: 1

Tomalak
Tomalak

Reputation: 338128

Converting a file to Base64 is easy with .NET's Convert.ToBase64String(Byte[]) method.

The method needs a byte array as input, which you can obtain via File.ReadAllBytes(). Note that this method needs an absolute path to work. If you're working with relative paths in PowerShell, use Convert-Path to convert them into absolute paths first.

Generic approach:

$absolutePath = Convert-Path "attachment filename"
$bytes = [System.IO.File]::ReadAllBytes($absolutePath)
$base64 = [Convert]::ToBase64String($bytes)

Write-Host $base64

Upvotes: 0

Related Questions