pat.bat
Goto Top

PowerShell - Text an HTMLbody übergeben mit UTF-8 Kodierung

Hallo zusammen,

ich stoße momentan auf folgendes Problem.
Ich möchte mit meinem Skript E-Mails versenden.

Text und Signatur samt Bild funktioniert auch alles wunderbar allerdings werden Umlaute nicht richtig kodiert.

Um den Body Inhalt aufzubauen, gehe ich wie folgt vor:

$htmlBody = "<HTML lang=""de""><meta charset=""utf-8""><BODY><p>$Body</p><\BODY><\HTML>"  

Und beim Aufbau der E-Mail gehe ich wie folgt vor:

$o = New-Object -ComObject Outlook.Application

        $mail = $o.CreateItem(0)
        $mail.importance = $Importance
        $mail.subject = "$Subject"  
        $mail.HTMLbody = $Body + $Signatur2
        $mail.To = "$To"  
        $mail.CC = "$CC"   

Die Variable $Body wird vorher wie folgt gefüllt:

$EmailBody = "Erste Zeile mit dynamischer Variable Datum Heute: $Today<br>"  
$EmailBody += "Zweite Zeile mit dynmischer Variable Datum in 28 Tagen: $EVFaelligkeit <br>"  
$EmailBody += "Das Verzeichnis können Sie hier aufrufen: <a href=""$pathFiles"">$pathFiles</a><br>"  

Es sieht auch alles aus, wie ich es haben wollte, außer das die UTF-8 Konvertierung keine Wirkung zeigt.

Content-Key: 486619

Url: https://administrator.de/contentid/486619

Ausgedruckt am: 28.03.2024 um 14:03 Uhr

Mitglied: 140777
140777 19.08.2019 aktualisiert um 10:10:04 Uhr
Goto Top
Geht einwandfrei solange man natürlich die richtigen Variablen benutzt face-wink, schau dir dein "Variablen-Mischmasch" nochmal genau an, da passt so gar nichts zusammen face-wink. Außerdem steht da im HTML und Body End Tag ein Backslash anstatt richtigerweise einem Slash!

Test:
$today = get-date
$EVFaelligkeit = (get-date).AddDays(28)
$pathFiles = "http://domain.tld/files"  
$EmailBody = "Erste Zeile mit dynamischer Variable Datum Heute: $Today<br>"  
$EmailBody += "Zweite Zeile mit dynmischer Variable Datum in 28 Tagen: $EVFaelligkeit <br>"  
$EmailBody += "Das Verzeichnis können Sie hier aufrufen: <a href=""$pathFiles"">$pathFiles</a><br>"  
$htmlBody = "<HTML lang=""de""><meta charset=""utf-8""><BODY><p>$EMailBody</p></BODY></HTML>"  


$o = New-Object -ComObject Outlook.Application
$mail = $o.CreateItem(0)
$mail.importance = 0
$mail.subject = "Test"  
$mail.BodyFormat = 2
$mail.HTMLbody = $htmlBody
$mail.Display()

Result:

screenshot

Und im Zweifel gibt es immer die entsprechenden NET Klassen für die Konvertierung
https://docs.microsoft.com/de-de/dotnet/api/system.text.utf8encoding.get ...
Mitglied: erikro
erikro 19.08.2019 um 09:40:56 Uhr
Goto Top
Moin,

ganz einfach: In Deiner Variablen steht kein Unicode, sondern ISO 8859-1. Guckst Du mal hier:
https://mohitgoyal.co/2017/03/03/understanding-default-encoding-and-chan ...
https://docs.microsoft.com/en-us/powershell/scripting/components/vscode/ ...

hth

Erik
Mitglied: Pat.bat
Pat.bat 19.08.2019 aktualisiert um 09:50:42 Uhr
Goto Top
@140777 funktioniert bei mir nicht, hatte vergessen, den Funktionsaufruf zu erwähnen:

Send-Mail   -Importance $Importance `
            -Subject $Subject `
            -Body $htmlBody `
            -To $To `
            -CC $cc `
            -Source $FilePath `
            -BoolAttachments $BoolAttachments `
            -Dateien @($Files)


Anbei das komplette Skript zum senden einer E-Mail:

param(
    $bAttachments,
    $Subject,
    $Importance,
    $Body,
    $To,
    $cc,
    $FilePath,
    $Files,
    $PProcedure
)

$Signatur2 = Get-Content -Path "G:\FD_50_Bank\System\Aufgabenplanungen\E-Mail\Signatur.htm"  
$htmlBody = "<HTML lang=""de""><meta charset=""utf-8""><BODY><p>$Body</p><\BODY><\HTML>"  

# Funktion zum Senden einer E-Mail. Parameter müssen mit übergeben werden.
Function Send-Mail($Importance, $Subject, $Body, $To, $CC, $Source, $BoolAttachments, [Array]$Dateien) 
{
    Try {
        # Erstellen eines Outlook Application Objekts
        $o = New-Object -ComObject Outlook.Application

        $mail = $o.CreateItem(0)
        $mail.importance = $Importance          # 1 = Normal, 2 = Wichtig
        $mail.subject = "$Subject"          
        $mail.HTMLbody = $Body + $Signatur2
        $mail.To = "$To"   
        $mail.CC = "$CC"  
 
        # Gehe über alle Files in Pfad und füge nur Dateien mit bestimmten Name.Endung hinzu 
        if ($BoolAttachments)
            {
                $files = Get-ChildItem $Source
               for ($i=0; $i -lt $files.Count; $i++) {

                GetFiles -files $files
              }
            }

            $mail.Send()
 
            # Der E-Mail etwas Zeit geben zum verschicken
            Start-Sleep 5

            # Outlook Objekt Schließen
             #$o.Quit()
        }
    catch {
	    $temp = $_.Exception
	    $invocationInfo = $_.InvocationInfo.PositionMessage
	    if ($_.InvocationInfo -ne $null) {
            write-host $temp
        }
    }
}

function GetFiles( $files )
{
    $outfileName = $files[$i].Name
    $outfileNameFullname = $files[$i].FullName
    $outfileNameExtension = $files[$i].Extension
 
    # wenn der Name.Endung der ist, den wir wollen, füge die Datei hinzu
    Foreach ( $f in $Dateien) {
        if($outfileName -eq $f)
        {
            $mail.Attachments.Add($outfileNameFullname);
        }
    }
}

Send-Mail   -Importance $Importance `
            -Subject $Subject `
            -Body $htmlBody `
            -To $To `
            -CC $cc `
            -Source $FilePath `
            -BoolAttachments $BoolAttachments `
            -Dateien @($Files)

Folgende E-Mail wird erstellt:
e-mailkonvertierung
Mitglied: 140777
140777 19.08.2019 aktualisiert um 09:54:42 Uhr
Goto Top
Nun du liest hier eine Signatur ein ohne das Encoding korrekt zu definieren:
$Signatur2 = Get-Content -Path "G:\FD_50_Bank\System\Aufgabenplanungen\E-Mail\Signatur.htm"  
und kombinierst das mit selbst definiertem UTF16 Text in der Powershell im Mail Parameter mit dem + Operator. Gebe beim Get-Content den -Encoding Parameter korrekt mit ein an und kombiniere beides vorher in einer Variablen statt erst in der Eigenschaft.

Und in der entsprechenden Konsole aus der du das PS1 Skript aus aufrufst muss das Output Encoding natürlich ebenfalls stimmen (außer du konvertierst über .NET direkt) s. @erikro
Mitglied: Pat.bat
Pat.bat 19.08.2019 um 11:07:26 Uhr
Goto Top
hm ich habs versucht, mit und ohne Signatur.

der cmdlet Get-Content besitzt keinen -Encoding Parameter.

Aber selbst wenn ich die Signatur raus lasse und nur den $Body übergebe, kann er keine Umlaute.
Mitglied: 140777
140777 19.08.2019 aktualisiert um 11:46:02 Uhr
Goto Top
der cmdlet Get-Content besitzt keinen -Encoding Parameter.
Doch. Einfach mal weiterbilden...
https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell. ...

Aber selbst wenn ich die Signatur raus lasse und nur den $Body übergebe, kann er keine Umlaute.
Siehe Kommentar oben.

Btw. wieso überhaupt mit Outlook senden, geht doch viel schneller auch mit Send-MailMessage?

In Outlook selbst muss natürlich UTF8 in den internationalen Optionen auch aktiviert sein
Mitglied: Pat.bat
Pat.bat 19.08.2019 aktualisiert um 14:21:39 Uhr
Goto Top
Hallo @140777

Hatte ich in der Doc übersehen, habe mich zu sehr auf Intellisense von VS Code verlassen. Der zeigt mir diesen Paramter hinter dem Get-Content Befehl nicht an.

Über Send-MailMessage bekomme ich das ganze gar nicht zum laufen. Hatte damals schon viel rum probiert und Outlook schien da die beste Lösung für zu sein.

Normal sollte das dann ja so funktionieren:

$Signature = Get-Content -Path "G:\FD_50_Bank\System\Aufgabenplanungen\E-Mail\Signatur.htm" -Encoding utf-8   

Aber das funktioniert nicht.

In Outlook selber ist es meines Wissens nach aktiviert, sonst hätte ich doch das Problem mit den Umlauten in alle meinen E-Mails oder nicht?

So wollte ich es jetzt zusammenstellen:

$Signature = Get-Content -Path "G:\FD_50_Bank\System\Aufgabenplanungen\E-Mail\Signatur.htm" #-Encoding utf-8  
$htmlBody = "<HTML><meta charset=""utf-8""><BODY><p>$Body</p>$Signature<\BODY><\HTML>"  

ich finde es auch etwas kurios, das die Umlaute in der Signatur funktionieren :S
Mitglied: erikro
erikro 19.08.2019 um 15:59:59 Uhr
Goto Top
Moin,

hast Du die Dokumente gelesen, auf die ich verwiesen habe? Das Problem ist nicht der input, sondern der output. Hier mal ein Beispiel. Ich habe mit einem Editor (Kate) eine Datei erzeugt, in der steht "Können". Und die jage ich jetzt auf die Powershell.

PS P:\test> $in_utf8 = Get-Content .\umlaute_in_utf8.txt -Encoding utf8
PS P:\test> $in_utf8
Können

Soweit, so gut. Jetzt mal mit dem default encoding der Powershell

PS P:\test> $in_default = Get-Content .\umlaute_in_utf8.txt -Encoding default
PS P:\test> $in_default
Können

Deshalb muss ich dem Eingabebefehlen in der Powershell das UTF8-Encoding mitteilen, wenn ich was anderes als ISO 8859-1 einlesen will. Das heißt aber noch lange nicht, dass in der Variablen $in_utf8 nun auch UTF8 drinsteht. Dem ist nämlich nicht so:

PS P:\test> $in_utf8 | set-content umlaute_out.txt
PS P:\test> $in_false = get-content .\umlaute_out.txt -encoding utf8
PS P:\test> $in_false
K?nnen

Aha, das ist also kein Unicode, was da raus kommt, sondern die Default-Kodierung der PS. Und das ist nun einmal ISO 8859-1 (jedenfalls bei uns).

PS P:\test> $in_correct = Get-Content .\umlaute_out.txt -encoding default
PS P:\test> $in_correct
Können

Das ist Dein Problem. Du schreibst in den HTML-Header rein, dass UTF-8 kommt, lieferst aber im Body ISO 8859-1 aus. Und dann funktioniert das halt nicht.

Teile ich hingegen der PS bei der Ausgabe wieder mit, dass sie nicht default schreiben soll, sondern UTF-8, dann klappt das wieder.

PS P:\test> $in_utf8 | set-content umlaute_out_utf8.txt -Encoding utf8
PS P:\test> Get-Content .\umlaute_out_utf8.txt -encoding utf8
Können

Anders gesagt, auch wenn ich was anderes schreiben will als ISO 8859-1, muss ich das der PS sagen.

Liebe Grüße

Erik
Mitglied: 140777
140777 19.08.2019 um 20:44:32 Uhr
Goto Top
Deshalb muss ich dem Eingabebefehlen in der Powershell das UTF8-Encoding mitteilen, wenn ich was anderes als ISO 8859-1 einlesen will.
Nicht zwingend. Powershell ist so intelligent das Encoding einer Datei zu erkennen sofern die Datei ein BOM enthält.
Mitglied: erikro
erikro 20.08.2019 um 08:15:04 Uhr
Goto Top
Zitat von @140777:

Deshalb muss ich dem Eingabebefehlen in der Powershell das UTF8-Encoding mitteilen, wenn ich was anderes als ISO 8859-1 einlesen will.
Nicht zwingend. Powershell ist so intelligent das Encoding einer Datei zu erkennen sofern die Datei ein BOM enthält.

Das widerspricht nicht meiner Aussage. face-wink Dafür ist der BOM ja da, dass er einem Programm mitteilt: Achtung! Das ist UTF-X.
Mitglied: 140777
140777 20.08.2019 aktualisiert um 08:51:14 Uhr
Goto Top
Ich bezog mich auf das : "muss ich dem Eingabebefehlen".
Muss nicht, kommt drauf an face-wink.
Mitglied: erikro
erikro 20.08.2019 um 08:56:35 Uhr
Goto Top
Zitat von @140777:

Ich bezog mich auf das : "muss ich dem Eingabebefehlen".
Muss nicht, kommt drauf an face-wink.

Wie gesagt, das ist eine Frage der Perspektive. face-wink Ich muss es mitteilen (entweder mit -encoding utf8 oder mit U+FEFF am Anfang des Datenstroms).
Mitglied: 140777
140777 20.08.2019 aktualisiert um 12:33:56 Uhr
Goto Top
Zitat von @Pat.bat:
Über Send-MailMessage bekomme ich das ganze gar nicht zum laufen.
Ist doch kein Thema ...
Send-MailMessage -From "user@domain.de" -to "empfaenger@domain.de" -Subject "BlaBlub" -Body $htmlbody -BodyAsHtml -SmtpServer smtp.domain.de -Credential (New-Object PSCredential("USERNAME",(ConvertTo-SecureString 'PASSWORD' -AsPlainText -Force))) -UseSSL -Encoding ([System.Text.Encoding]::UTF8) -Attachments $files -Priority High  
Fertsch, und du kannst Outlook in den Schrank hängen ...

Außerdem gibt's alternativ auch noch die entsprechenden .NET Methoden dafür
https://blogs.msdn.microsoft.com/deva/2017/08/30/code-send-email-using-p ...
Mitglied: 77559
77559 20.08.2019 um 19:10:10 Uhr
Goto Top
Aber Hallo,

Ist doch kein Thema ...
> Send-MailMessage -From "user@domain.de" -to "empfaenger@domain.de" -Subject "BlaBlub" -Body $htmlbody -BodyAsHtml -SmtpServer smtp.domain.de -Credential (New-Object PSCredential("USERNAME",(ConvertTo-SecureString 'PASSWORD' -AsPlainText -Force))) -UseSSL -Encoding ([System.Text.Encoding]::UTF8) -Attachments $files -Priority High  
> 
Anstatt der Bandwurm Einzeiler würde ICH ja lieber Splatting benutzen

$params = @{
   From        = "user@domain.de"   
   to          = "empfaenger@domain.de"   
   Subject     = "BlaBlub"   
   Body        = $htmlbody 
   BodyAsHtml  = $True
   SmtpServer  = 'smtp.domain.de'   
   Credential  = ((New-Object PSCredential("USERNAME",(ConvertTo-SecureString 'PASSWORD' -AsPlainText -Force)))  
   UseSSL      = $True
   Encoding    = ([System.Text.Encoding]::UTF8) 
   Attachments = $files 
   Priority    = 'High'  
}

Send-MailMessage @params