I am having a problem with the formatting of an e-mail. I have special characters in the body and they are not being displayed correctly, I have tried several solutions but the e-mail keeps arriving with a format that does not interpret special characters. The body of the e-mail has to be sent in plain text, so I cannot use [-BodyAsHtml]. Here is my function. I hope someone can help me. Best regards
function SendMail {
$PDFName = $settings.pdf.Name
$WebResponseObj = Invoke-WebRequest -Uri $PDFUrl
$getLastModified = $WebResponseObj.Headers.'Last-Modified'
$PDFdate = [DateTime]$getLastModified
$dateTimePDF = $PDFdate.DateTime
$plainTextBody = "
Meldung über das aktualisierte Dokument `r`n
File Name: $PDFName `r`n
File Url: $PDFUrl `r`n
Letzte Aktualisierung: $dateTimePDF `r`n
Letzte Aktualisierungsprüfung: $getDateTime
"
$param = #{
SmtpServer = $settings.mail.SmtpServer
Port = $settings.mail.Port
UseSsl = $true
Credential = $userCredential
From = $settings.mail.FromUser
To = $settings.mail.ToUser
Subject = $settings.mail.Subject
Body = $plainTextBody
Priority = 'High'
DeliveryNotificationOption = 'OnFailure'
ErrorAction = 'Stop'
Encoding = ([System.Text.Encoding]::UTF8)
}
Send-MailMessage #param
}
I have found the problem, the .ps1 file was in UTF-8 format and to be interpreted correctly it has to be UTF-8 with BOM, that's it!
Related
Try to generate sha1 base64 hash of an empty string in powershell
$enc = [system.Text.Encoding]::UTF8
$string = ""
$data=$enc.GetBytes($string)
$sha1 = New-Object System.Security.Cryptography.SHA1CryptoServiceProvider
$ResultHash = $sha1.ComputeHash($data)
$str_out = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($ResultHash))
write-host $str_out
result is
MjE4IDU3IDE2MyAyMzggOTQgMTA3IDc1IDEzIDUwIDg1IDE5MSAyMzkgMTQ5IDk2IDI0IDE0NCAxNzUgMjE2IDcgOQ==
and I should have received
2jmj7l5rSw0yVb/vlWAYkK/YBwk=
Please could someone advice?
The output from ComputeHash is already a byte array, not a string - [Text.Encoding]::UTF8.GetBytes($ResultHash) makes no sense here.
Remove that part and it'll work as expected:
$enc = [system.Text.Encoding]::UTF8
$string = ""
$data=$enc.GetBytes($string)
$sha1 = New-Object System.Security.Cryptography.SHA1CryptoServiceProvider
$ResultHash = $sha1.ComputeHash($data)
$str_out = [Convert]::ToBase64String($ResultHash)
write-host $str_out
Your expected encoded base64 string is not UTF-8 encoded.
If you want to get 2jmj7l5rSw0yVb/vlWAYkK/YBwk= you have to replace :
$str_out = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($ResultHash))
by
$str_out = [Convert]::ToBase64String($ResultHash)
What I am hoping to do is once a new email hits a folder containing a specific subject. That email is then forwarded to another inbox and a specific file is automatically attached. The code I have been able to cobble together so far is this. Is a .Net method the appropriate method to achieve my goal or would using Send-MailMessge to a hastable be better method? I am new to PowerShell code I am able to get both methods to work. But was wondering A. which method is preferred. B. is there a better/more efficient way?
#####Define Variables########
$fromaddress = "donotreply#fromemail.com"
$toaddress = "blah#toemail.com"
$bccaddress = "blah#bcc.com"
$CCaddress = "blah#cc.com"
$Subject = "ACtion Required"
$body = get-content .\content.htm
$attachment = "C:\sendemail\test.txt"
$smtpserver = "smtp.labtest.com"
##############################
$message = new-object System.Net.Mail.MailMessage
$message.From = $fromaddress
$message.To.Add($toaddress)
$message.CC.Add($CCaddress)
$message.Bcc.Add($bccaddress)
$message.IsBodyHtml = $True
$message.Subject = $Subject
$attach = new-object Net.Mail.Attachment($attachment)
$message.Attachments.Add($attach)
$message.body = $body
$smtp = new-object Net.Mail.SmtpClient($smtpserver)
$smtp.Send($message)
(Example of the hashtable method
$emailHashSplat = #{ To = $toAddress
From = $fromAddress
Subject = $emailSubject
Body = $emailBody SMTPServer = $smtpServer BodyAsHtml =
$true Attachments = "C:\sendemail\test.txt" # Attachments =)
Stick with Powershell commands whenever possible, .NET might be faster in some cases but it is a best practice to use only Powershell commands when possible.
Also make sure your code is easy to read and understand by others, using hastables with splatting wil help with this, see the following example: Github Gist Link (Click Me!)
Copy of the code, in case of link failure.
### Script Global Settings
#Declare SMTP Connection Settings
$SMTPConnection = #{
#Use Office365, Gmail, Other or OnPremise SMTP Relay FQDN
SmtpServer = 'outlook.office365.com'
#OnPrem SMTP Relay usually uses port 25 without SSL
#Other Public SMTP Relays usually use SSL with a specific port such as 587 or 443
Port = 587
UseSsl = $true
#Option A: Query for Credential at run time.
Credential = Get-Credential -Message 'Enter SMTP Login' -UserName "emailaddress#domain.tld"
<#
#Option B: Hardcoded Credential based on a SecureString
Credential = New-Object -TypeName "System.Management.Automation.PSCredential" -ArgumentList #(
#The SMTP User Emailaddress
"emailaddress#domain.tld"
#The Password as SecureString encoded by the user that wil run this script!
#To create a SecureString Use the folowing Command: Read-Host "Enter Password" -AsSecureString | ConvertFrom-SecureString
"Enter the SecureString here as a single line" | ConvertTo-SecureString
)
#>
}
### Script Variables
#Declare Mailmessages.
$MailMessageA = #{
From = "emailaddress#domain.tld"
To = #(
"emailaddress#domain.tld"
)
#Cc = #(
# "emailaddress#domain.tld"
#)
#Bcc = #(
# "emailaddress#domain.tld"
#)
Subject = 'Mailmessage from script'
#Priority = 'Normal' #Normal by default, options: High, Low, Normal
#Attachments = #(
#'FilePath'
#)
#InlineAttachments = #{
#'CIDA'='FilePath'
#} #For more information about inline attachments in mailmessages see: https://gallery.technet.microsoft.com/scriptcenter/Send-MailMessage-3a920a6d
BodyAsHtml = $true
Body = "Something Unexpected Occured as no Content has been Provided for this Mail Message!" #Default Message
}
### Script Start
#Retrieve Powershell Version Information and store it as HTML with Special CSS Class
$PSVersionTable_HTLM = ($PSVersionTable.Values | ConvertTo-Html -Fragment) -replace '<table>', '<table class="table">'
#Retrieve CSS Stylesheet
$CSS = Invoke-WebRequest "https://raw.githubusercontent.com/advancedrei/BootstrapForEmail/master/Stylesheet/bootstrap-email.min.css" | Select-Object -ExpandProperty Content
#Build HTML Mail Message and Apply it to the MailMessage HashTable
$MailMessageA.Body = ConvertTo-Html -Title $MailMessageA.Subject -Head "<style>$($CSS)</style>" -Body "
<p>
Hello World,
</p>
<p>
If your recieved this message then this script works.</br>
</br>
<div class='alert alert-info' role='alert'>
Powershell version
</div>
$($PSVersionTable_HTLM)
</P>
" | Out-String
#Send MailMessage
#This example uses the HashTable's with a technique called Splatting to match/bind the Key's in the HashTable with the Parameters of the command.
#Use the # Symbol instead of $ to invoke Splatting, Splatting improves readability and allows for better management and reuse of variables
Send-MailMessage #SMTPConnection #MailMessageA
My powershell script currently handles sending an email from the command line to a list of users. I would like to add an attachment to the email and also a list of Cc so all emails don't come through the "To" email parameter. Here is my current function.
function SendEmail
{
$smtpServer = "smtp.server"
$smtpFrom = "PROD <email#gmail.com>"
$smtpTo = "me#gmail.com"
$messageSubject = "Weekly List "+$day
$messagebody = "Hi User, Please find attached document. Thank you."
$smtp = New-Object Net.Mail.SmtpClient($smtpServer)
$smtp.Send($smtpFrom,$smtpTo,$messageSubject,$messagebody)
}
My attempt was to add a variable called $attachment = "\PathtoFile"
and add $attachment into the Send function, but that didn't work...
Use Send-MailMessage with the Attachments and Cc parameter:
Send-MailMessage -Attachments "C:\path\to\attachment.ext" -Cc "myboss#gmail.com"
You can also specify an encoding (you mentioned special characters):
Send-MailMessage -Encoding UTF8
In general, I would recommend splatting the parameters, so it ends up looking like this:
$MyAttachments = ".\a\relative\path.ext","C:\another\file.ext"
$MailParams = #{
SmtpServer = "smtp.server"
From = "PROD <email#gmail.com>"
To = "me#gmail.com"
Subject = "Weekly List "+$day
Body = "Hi User, Please find attached document. Thank you."
Attachments = $MyAttachments
Encoding = [System.Text.Encoding]::UTF8
}
Send-MailMessage #MailParams
I have a Powershell script that automates a process and emails the report of what happened.
Send-MailMessage -To $toAddress -From "no-reply#domain.org" -subject "Automation status" -body $bodystr -SmtpServer SERVER1 -EA Stop
So $bodystr is essentially an appended string throughout the script to report what happened and has multiple lines. Things like:
$bodystr = $bodystr + "Line found: 305`n"
$bodystr = $bodystr + "Moving line 305 to 574`n"
The Send-MailMessage command is at the bottom of the script outside any function. But most other code is in various different functions.
The issue is $bodystr does not seem accessible inside functions, and so the email is lacking a lot of information.
I believe I could use Set-Variable or passing arguments, but there are so many arguments it seems farther away from best practice to add a new argument for each function just to keep the string updated.
What's the best practice to handle this?
As a general rule, don't write data back to variables outside the scope of your function.
If you are compiling an email by gathering data from multiple sources, abstract it away in multiple functions that does one thing each and have them return a multiline string with the relevant output.
At the end of your script, collect the different message body parts and join them to a single string before sending.
In this example, we have a script that takes a path to a log file, defines a function to extract errors from a log file, and send an email with the errors in the body:
param(
[ValidateScript({Test-Path $_ -PathType Leaf })]
[string]$LogPath = 'C:\Path\To\File.log',
[string]$From = 'noreply#company.example',
[string]$To = #('ceo#company.example','finance#company.example'),
[string]$Subject = 'Super Important Weekly Report',
[string]$SmtpServer = $PSEmailServer,
[string]$Credential
)
# Define functions with a straight forward purpose
# e.g. Searching a logfile for errors
function Parse-Logfile {
param($LogPath)
[string[]]$LogErrors = #()
Get-Content $LogPath |ForEach-Object{
if($_ -contains $Error){
$LogErrors += $_
}
}
# Create and return a custom object has the error details as properties
New-Object psobject -Property #{
ErrorCount = $LogErrors.Count
Errors = $LogErrors
}
}
# Create a email template that's easy to maintain
# You could store this in a file and add a $TemplateFile parameter to the script ;-)
$EmailTemplate = #'
Hi there!
Found {0} errors in log file: {1}
{2}
Regards
Zeno
'#
# Use your function(s) to create and gather the details you need
$ErrorReport = Parse-Logfile -LogPath $LogPath
# If necessary, concatenate strings with -join
$ErrorString = $ErrorReport.Errors -join "`n"
# Use the format operator to the final Body string
$Body = $EmailTemplate -f $ErrorReport.ErrorCount, $LogPath, $ErrorString
# Set up a splatting table (Get-Help about_Splatting)
$MailParams = #{
To = $To
From = $From
Subject = $Subject
Body = $Body
SmtpServer = $SmtpServer
}
if($PSBoundParameters.ContainsKey('Credential')){
$MailParams['Credential'] = $Credential
}
# Send mail
Send-MailMessage #MailParams
I am trying to make a button open an outlook draft that we can type in the "To:" and click on send.
I got most of it working with the following code:
$SUBJECT = ('Ticket: ' + $textticketnumber.text)
CreateLink #Function that gets a weblink and stores it to variable $rtblink.Text
$BODY = $rtblink.Text
$EMAILSIG = Get-Content ($env:USERPROFILE + "\AppData\Roaming\Microsoft\Signatures\*.htm")
$ol = New-Object -comObject Outlook.Application
$mail = $ol.CreateItem(0)
$mail.Subject = "$SUBJECT"
$mail.Body = "`n$BODY`n$EMAILSIG"
$inspector = $mail.GetInspector
$inspector.Display()
The issue is that the body of the email has the raw HTML code not the proper signature. I can change the get-content to *.txt instead of .htm but then there is no formatting in the signature, plus it puts it all on one line.
Is there a way to make the body of the code work with html or is there another way to insert the signature into the email with proper formatting?
The following code is from one of my scripts:
$sMsg = Get-Content template.html
$sRecipientAddr = "someone#example.com"
$sMsgSubject = "Subject"
$oOutlook = New-Object -ComObject Outlook.Application
$oMapiNs = $oOutlook.GetNameSpace("MAPI")
$oMailMsg = $oOutlook.CreateItem(0)
$oMailMsg.GetInspector.Activate()
$sSignature = $oMailMsg.HTMLBody
[Void]$oMailMsg.Recipients.Add($sRecipientAddr)
$oMailMsg.Subject = $sMsgSubject
$oMailMsg.HTMLBody = $sMsg + $sSignature
$oMailMsg.Save()
I use it with Outlook 2007 and it works. Outlook is configured to automatically add a signature to new messages. template.html is a pre-formatted Outlook message saved as HTML.
The idea is not mine but I honestly can't remember where I found the snippet so my apologies to the author in advance.