简体   繁体   中英

Sending email attachment - Converting CSV file to bytes removes line breaks

I'm trying to use the MS Graph cmdlet Send-MgUserMail to send an email and include a CSV attachment.

If I do it like this, it works fine, and the attachment is fine.

Sample CSV attachment

"App","AppId","Date","User"
"App1","43a9087d-8551-47d5-9869-3287736ce7c3","2023/01/26","me@email.com"
"App2","f33750cd-c79b-43be-8e55-ee14d163e2b3","2024/01/26","me@email.com"

Working code

$attachment   = "C:\Users\Me\Downloads\SampleFile.csv"
$base64string = [Convert]::ToBase64String([IO.File]::ReadAllBytes($attachment))

$params = @{
    UserId = "me@email.com"
    BodyParameter = @{
        Message = @{
            Subject = "Test Email"
            Body    = @{
                ContentType = "Html"
                Content     = "This is sample text."
            }
            ToRecipients = @(
                @{
                    EmailAddress = @{
                        Address = "toAddress@email.com"
                    }
                }
            )
            Attachments = @(
                @{
                    "@odata.type" = "#microsoft.graph.fileAttachment"
                    Name         = "SampleFile.csv"
                    ContentType  = "text/csv"
                    ContentBytes = $base64string
                }
            )
        }
        SaveToSentItems = "false"
    }
}
 
Send-MgUserMail @params

Objective

What I would like is to attach the CSV, without having an actual saved file. The content would be from memory, like so.

$output = @(
    [PSCustomObject] @{
        App = "App1"
        AppId = "43a9087d-8551-47d5-9869-3287736ce7c3"
        Date  = "2023/01/26"
        User  = "me@email.com"
    },
    [PSCustomObject] @{
        App = "App2"
        AppId = "f33750cd-c79b-43be-8e55-ee14d163e2b3"
        Date  = "2024/01/26"
        User  = "me@email.com"
    }
)

$attachment = $output | ConvertTo-Csv -NoTypeInformation

$bytes         = [System.Text.Encoding]::UTF8.GetBytes($attachment)
$base64string  = [Convert]::ToBase64String($bytes)

My issue when I do this is the CSV content is entirely on 1 line, there's no more line breaks.

Issue Sample CSV Output

"App","AppId","Date","User" "App1","43a9087d-8551-47d5-9869-3287736ce7c3","2023/01/26","me@email.com" "App2","f33750cd-c79b-43be-8e55-ee14d163e2b3","2024/01/26","me@email.com"

How can I convert this properly?

Answer was given in comments but to give it closure, what happens is that ConvertTo-Csv outputs an array of strings and they don't have new line characters (CRLF in Windows, LF in Linux), before getting the bytes of your Csv you need to convert this array into a single multi-line string, for this you can use Out-String :

$attachment = $output | ConvertTo-Csv -NoTypeInformation | Out-String

Or join them by a new line character to preserve the structure:

$attachment = ($output | ConvertTo-Csv -NoTypeInformation) -join [Environment]::NewLine

Also, [System.Text.Encoding]::UTF8.GetBytes(...) which has a string type argument is coercing your array into a string and when you coerce an array into a string in PowerShell, it is joined by $OFS (a white space character by default) hence why you get a single line joined by whitespaces when decoding the base64 string.


Another way this could've been done is by assigning $OFS the value of a new line character:

$attachment = $output | ConvertTo-Csv -NoTypeInformation
$OFS = [System.Environment]::NewLine
$bytes         = [System.Text.Encoding]::UTF8.GetBytes($attachment)
$base64string  = [Convert]::ToBase64String($bytes)
$OFS = ' '

# Decoding should look as expected
[System.Text.Encoding]::UTF8.GetString(
    [Convert]::FromBase64String($base64string)
)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM