Die Powershell Funktion Send-MailMessage https://msdn.microsoft.com/de-de/powershell/reference/5.1/microsoft.powershell.utility/send-mailmessage hat so ihre Tücken und hilft leider nicht, wenn es Probleme beim E-Mailversand gibt. Teilweise reagiert sie auch nicht wie erwartet. In der heutigen Zeit, vor allem wegen der TLS-Pflicht reagiert sie oft zickig in Bezug auf den UseSSL Parameter. Aus diesem Grund hier eine einfache Methode E-Mails mittels TLS per Powershell versenden zu können.
Wer Probleme beim E-Mailversand hat, der schaue sich https://newyear2006.wordpress.com/2015/08/23/probleme-mit-transportverschlsselung-zertifikaten-oder-passwrtern-bei-smtp-servern-mittels-powershell-berprfen/ an, dort wird im Detail beschrieben, wie dieses Skript funktioniert.
Gleichzeitig benutzt diese Routine nicht mehr die Test-NetConnection Funktion, da diese komischerweise nicht mehr den Socket öffnet. Statt dessen wird der benötigte TCP-Socket zu beginn manuell geöffnet. Der Rest sind nur Anpassungen für diese Änderung.
Man muss nur die im ersten Block aufgeführten Parameter eintragen und schon kann die Spammerei losgehen…
Hier der ganze Code:
$smtp = "smtp.web.de"
$smtpPort = 587
$user = "meinewebdeadresse@web.de"
# $userPass kann auch leer gesetzt werden, dann wird nachgefragt
$userPass = "meinPasswort"
$Subject = "Test Betreff"
$Body = "Test Body"
$from = "meinewebdeadresse@web.de"
$to = "meinewebdeadresse@web.de"
$xmailer = "Powershell v1"$c=New-Object System.Net.Sockets.TcpClient
$c.Connect($smtp, $smtpPort)# Antwort vom SMTP-Server holen und ausgeben
[byte[]]$buffer= @(0) * $c.Client.Available
$c.Client.Receive($buffer)
[System.Text.Encoding]::ASCII.GetString($buffer)# Begrüßung durchführen
$buffer=[System.Text.Encoding]::ASCII.GetBytes("EHLO $Env:Computername`r`n")
$c.Client.Send($buffer)
Sleep -Seconds 1# Antwort vom SMTP-Server holen
[byte[]]$buffer= @(0) * $c.Client.Available
$c.Client.Receive($buffer)
[System.Text.Encoding]::ASCII.GetString($buffer)# STARTTLS-Anfrage starten
$buffer=[System.Text.Encoding]::ASCII.GetBytes("STARTTLS`r`n")
$c.Client.Send($buffer)
Sleep -Seconds 1# Bei dieser Antwort sollte 220 rauskommen,
# sonst gibt es ein Problem
[byte[]]$buffer= @(0) * $c.Client.Available
$c.Client.Receive($buffer)
[System.Text.Encoding]::ASCII.GetString($buffer)# für den weiteren Gang ist entscheidend, dass man einen Stream braucht
# vom Socket erhält man einen Stream, durch Weitergabe an NetworkStream-Klasse
$n=New-Object System.Net.Sockets.NetworkStream $c.Client# über den Networkstream kann man nun SslStream aktivieren:
$ssl = New-Object System.Net.Security.SslStream $n, $true# nun kann man den eigentlichen TLS Handshake starten, dazu muss nochmal der Host angegeben werden
$ssl.AuthenticateAsClient($smtp)# für die weitere Kommunikation richtet man sich am besten zusätzliche Streams ein:
$reader = New-Object System.IO.StreamReader $ssl
$writer = New-Object System.IO.StreamWriter $ssl
$writer.AutoFlush = $true# damit wird die weitere Kommunikation einfacher und das Spiel beginnt von vorne:
$writer.WriteLine("EHLO $Env:Computername")
while ($reader.Peek() -gt -1) {
$reader.ReadLine()
}$writer.WriteLine("AUTH LOGIN")
$reader.ReadLine()[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String("VXNlcm5hbWU6"))
If ($UserPass) {
$Spass = ConvertTo-SecureString -String $UserPass -AsPlainText -Force
$cred = New-Object -TypeName "System.Management.Automation.PSCredential" -ArgumentList $User, $SPass } else {
$cred = Get-Credential –UserName $User –Message "Bitte Passwort eingeben"
}
$pass = $cred.GetNetworkCredential().Password
$userBytes = [System.Text.Encoding]::ASCII.GetBytes($user)
$userBase64 = [System.Convert]::ToBase64String($userBytes)
$writer.WriteLine($userBase64)
$reader.ReadLine()$passBytes = [System.Text.Encoding]::ASCII.GetBytes($pass)
$passBase64 = [System.Convert]::ToBase64String($passBytes)
$writer.WriteLine($passBase64)
$reader.ReadLine()$writer.WriteLine("MAIL FROM:$from")
$writer.WriteLine("RCPT TO:$to")
$writer.WriteLine("DATA")
#$writer.WriteLine("")
$writer.WriteLine("From: $from")
$writer.WriteLine("To: $to")
$writer.WriteLine("Date: {0}", (Get-Date).ToString("ddd, d M y H:m:s z"))
$writer.WriteLine("Subject: $Subject")
$writer.WriteLine("X-Mailer: $xmailer")
$writer.WriteLine("")
$writer.WriteLine("$Body")
$writer.WriteLine(".")
$writer.WriteLine("")
$writer.WriteLine("")
$reader.ReadLine()# Streams und Sockets schließen
$ssl.Close()
$n.Close()
$c.Close()