Funny issue using + in mail body - powershell

List item
Here is a weird one. $body is buildt with
a loop adding 30 - 100 lines:
$body += "+ $stuff `n"
The problem is if I use in $body a plus (+), it takes each line in the body and splits it to half the line size and continues it on the next line:
Example,
The line is actually:
moon|glowing so nice today|buy gold now and get really rich soon
It gets changed to (stackoverflow changed my (+) to a bullet. Just note that there is a plus in front of the next two lines).
moon|glowing so nice today|buy gold now
moon|and get really rich soon
If I change the plus (+) to the word Add, I get in the email body:
Add moon|glowing so nice today|buy gold now and get really rich soon
I would like to use the plus (+) as that is the same format another program uses with +/- of lines in the body of the email. Any ideas how to get this working?
function mailalert($body) {
$SMTPserver = "mailhost.domain.com"
$from = "replies-disabled#domain.com"
$to = "joe#domain.com"
$subject = "Report for Stuff"
$mailer = new-object Net.Mail.SMTPclient($SMTPserver)
$msg = new-object Net.Mail.MailMessage($from, $to, $subject, $body)
$mailer.send($msg)
}

Okay, I abandoned Net.Mail.SMTPclient and decided to use html as body of text to get around this:
function mailalert($diff) {
$SMTPserver = "mailhost.domain.com"
$smtp = New-Object system.Net.Mail.SmtpClient($SMTPserver)
$mail = New-Object System.Net.Mail.MailMessage
$mail.From = "replies-disabled#domain.com"
$mail.To.Add("joe#domain.com")
$mail.Subject = "Report for stuff"
$mail.Body = $diff
$mail.IsBodyHtml = $true
$smtp.Send($mail)
}
I changed all use of `n to and tada it works. It still is a bit perplexing why the other way did not work. I see another issue where email addresses with pluses in them was being addressed, so I wonder if fixing that broke this. :)

Try:
$body = "$body $stuff `n"
in your loop.
Escape any troublesome characters using a " ` ".
$body = "$body `+ $stuff `n"

Related

How to send an email with embedded images using PowerShell

I want to send an automated email report with some embedded images that cannot be accessed externally from our network.
Google has lead me towards attaching the images and referencing them using CID Embedding in the body of the email using HTML.
I cannot find any guidance on how to do this, how do I set the content ID on an attached image so that it can be displayed in the HTML body?
Something along the lines of:
$html = "<ul><li><img src='cid:att'/></li><li>next img</li><li>another img</li></ul>"
Send-MailMessage -SmtpServer "stuff.co.uk" -to "person.co.uk" -from "mailbox.co.uk" -Subject "Report" -body $html -BodyAsHtml -Attachments \\some image from a server location.jpg
I got there in the end by adapting some code I found on reddit, it could definitely be improved but worked perfectly for my situation and because it's not the Base64 method, it shows the images on Outlook and Apple devices etc.
Hopefully this will help someone else in the future.
### Create a new mailmessage ###
$msg = new-object net.mail.mailmessage
$msg.From = 'email#address'
$msg.To.Add('email1, email2')
$msg.CC.Add('ccemail');
$msg.Subject = 'Daily Performance Report' + $(get-date -format dd/MM/yyyy)
$msg.IsBodyHtml = $true
#### Attach images with individual Content IDs (ContentId is used to refer to attachement inline in the email HTML body) ###
$attachment = New-Object System.Net.Mail.Attachment -ArgumentList "attachment file location e.g. C:\Users\username\documents\image.jpg"
$attachment.ContentDisposition.Inline = $true
$attachment.ContentId = 'image.jpg' #can be anything as long as it matches the CID reference in the HTML
$attachment.ContentDisposition.DispositionType = "Inline"
$attachment.ContentType.MediaType = "image/jpg"
$msg.Attachments.Add($attachment)
#repeat the above to add another attachment.
### Create the html body of the email ###
$msg.Body = "<p>Please see todays performance dashboards below. <p/>
<h2>Compliance Scores <h2/>
<h4 style='font-weight:normal' >Logon compliance scores for each environment<h4/>
<img src='cid:image.jpg' />"
### Create connection to smtp server and send the mail ###
$smtp = New-Object Net.Mail.SmtpClient('yoursmtp.server.com')
$smtp.Send($msg)
#$attachment.Dispose()
#$msg.Dispose()
Base64 might work for you. Just tried this code working with my client
function ImageToBase64($FilePath) {
$type = (dir $FilePath).extension -replace "\.",""
return $("data:image/$type;base64," + $([Convert]::ToBase64String([IO.File]::ReadAllBytes($FilePath))))
}
$html = "<ul><li><img src=`"" + $(ImageToBase64("c:\temp\image.jpg")) + "`"/></li><li><img src=`"" + $(ImageToBase64("c:\temp\nextimage.png")) + "`"/></li><li><img src=`"" + $(ImageToBase64("c:\temp\anotherimg.jpeg")) + "`"/></li></ul>"
Send-MailMessage -SmtpServer "stuff.co.uk" -to "person.co.uk" -from "mailbox.co.uk" -Subject "Report" -body $html -BodyAsHtml -Attachments \\some image from a server location.jpg
--Edit--
ATTENTION: I forgot to mention that not all clients will display base64 embedded images - thanks #Nathan

Send mail via powershell without authentication

I was using nant to send mail and it is working fine - something like
<mail
from="Test#b.c"
tolist="A#b.c"
subject="Test"
mailhost="myhost.mydomain.com"
isbodyhtml="true"
message= "${Test}">
</mail>
I didn't have to use any kind of authentication.
Now when using powershell it seems I am forced to use authentication - something like this would fail:
Send-MailMessage -To $to -From $from -Subject "Test" –Body “Test (body) -SmtpServer "myhost.mydomain.com"
I would get the following message:
Send-MailMessage : No credentials are available in the security package
Am I missing some way to send mails without specifying credentials if the server supports that?
Edit:
I've also tried the answer here to send anonymous mails but it just times out:
send anonymous mails using powershell
Sending mails using Powershell v1 method works fine without authentication as shown here
My Powershell version is 5 yet this is apparently the way to go, unless someone has another idea.
$smtpServer = "ho-ex2010-caht1.exchangeserverpro.net"
$smtpFrom = "reports#exchangeserverpro.net"
$smtpTo = $to
$messageSubject = $subject
$messageBody = $body
$smtp = New-Object Net.Mail.SmtpClient($smtpServer)
$smtp.Send($smtpFrom,$smtpTo,$messagesubject,$messagebody)
I was looking for another issue and found this question here...
As #AngelicCore already explained one approach,
Here is another one if someone using Outlook dektop app...
The mail sent will appear in your outbox.
using outlook object
Try
{
#Email structure
$Outlook = New-Object -ComObject Outlook.Application
$Mail = $Outlook.CreateItem(0)
#Email Recipients
$Mail.To = "abc#domain.com;xyz#domain.com"
$Mail.Cc = "tuv#domain.com; pqr#domain.com"
#Email Subject
$date = Get-Date -Format g
$Mail.Subject = "Subject here $date"
#Email Body
$Mail.Body = "Body Here"
#Html Body
$Mail.HTMLBody == "<html> HTML Body Here </html>"
#Email Attachment
$file = "C:\path\xyz.txt"
$Mail.Attachments.Add($file)
$Mail.Send()
Write-Host -foreground green "Mail Sent Successfully"
}
Catch
{
write-host -foreground red $error[0].Exception.Message
}
pause
exit

function to send email multiple times

I am working on a PowerShell script which sends emails multiple times with different subject and body each time.
I am trying to move Send-MailMessage into a function or something that I could use to reduce the code lines.
$Sender = 'jones#example.com'
$text = "<html><body>"
$text += "<p>Welcome</p>"
### A cmdlet that would give recipient email address
$Recipient = (Get-Details -user $user).email
$smtp = "server.example.com"
$subject = "welcome email"
Send-MailMessage -BodyAsHtml $text -from $Sender -SmtpServer $smtp -Priority high -to $Recipient -Subject $subject
Write-Output "executing commands to capture results"
Write-Output ""
### Few Commands executed in this step
Write-Output "Analyzing results"
### Few commands executed in this step
$newtext = "<html><body>"
$newtext += "Congrats, you are selected"
$newsubject = "results email"
Send-MailMessage -BodyAsHtml $newtext -from $Sender -SmtpServer $smtp -Priority high -to $Recipient -Subject $subject
You could create a function like this:
Function Send-Email($text,$subject,$recipient)
{
Send-MailMessage -BodyAsHtml $text -From "jones#example.com"
-SmtpServer "server.example.com" -Priority High -To $recipient -Subject $subject
}
You can call it like:
Send-Email -text "Hello" -subject "Test" -recipient "test#example.com"
You can add or remove arguments depending on what will change though. Assuming the smtp server won't change for example, this isn't needed as a parameter.
I am trying to move Send-MailMessage into a function or something that I could use to reduce the code lines.
Writing a function for one line can be useful if the options are many and never change. However you do have one that changes. There is another PowerShell feature that would work here just as well. Splatting!
$emailParameters = #{
From = $Sender
SmtpServer = $smtp
Priority = "high"
To = $Recipient
Subject = $subject
}
Send-MailMessage -BodyAsHtml $text #emailParameters
# ... other code and stuff
Send-MailMessage -BodyAsHtml $newtext #emailParameters
Now you still only have to make changes in one place and the code is arguably more terse.
Another point is that when you are making multi-line strings all at once, as supposed to building over the course of the script you can always use here strings. You only have two lines but if you code evolves over time it is a good tactic to start early instead of many $object += "string" lines
$text = #"
<html><body>
<p>Welcome</p>
"#
Note that indentation is preserved in the resulting here-string. The "# has to appear on its own line with no leading whitespace. Using double quotes means you can still expand variables as well in there.

Cannot Get Send-MailMessage to Send Multiple Lines

I apologize for this in advance because I see plenty of questions regarding it throughout the web but for some reason I'm still having issues.
I have a script that creates an array that has information dynamically added to it. When the script completes, I need it to email that information to me. The problem is that each line is combined to that I get 1 line. For example:
$Body = #()
$Body += "1"
$Body += "2"
$Body += "3"
$Body += "4"
Here's my send command:
Send-MailMessage -To $Recipients -From $Sender -Smtp $SMTP $Subject "Test" -Body ($Body | Out-String)
What I get in the email body is: 1234
I've tried this for loop to append `n to the beginning of each line (except the 1st) like so:
for ($i = 0; $i -lt Body.Count; $i++){
if($i -eq 0){
Write-Host $i
}else{
$Body[$i] = "`n" + $Body[$i]
Write-Host $Body[$i]
}
}
The results of that are better but I get an extra line:
1
2
3
4
Ultimately I just want this:
1
2
3
4
In the past, I've gotten the format I want by creating the variable like this:
$Body = #"
This is the email I want to send. It formats great if:
1) I want to make all the content static.
Is it possible to create the `$Body variable like this but add line by line dynamically and maintain a serpate line. (without extra lines)?
"#
What am I missing? It HAS to be something simple... Thanks for your help!
WOW so it's such a finicky thing... I found that using this would get everything to look right (as suggested by Ryan, above):
-Body ($Body -Join "`r`n")
But in the context of my actual script it wasn't working. Well, it appears that it all had to do with the way the date was going in there. Here's a reduction to show:
DOES NOT WORK
$Body = #()
$Body += "Beginning processing on: " + (Get-Date)
$Body += "No advertisements found, exiting"
ALSO DOES NOT WORK
$Body = #()
$DateTime = Get-Date
$Body += "Beginning processing on: $DateTime"
$Body += "No advertisements found, exiting"
When I removed anything that had to do with the Date, formatting was correct. Ultimately it just took a simple "." to make it work right.
WORKS - NOTE THE 3RD LINE
$Body = #()
$DateTime = Get-Date
$Body += "Beginning processing on: $DateTime." #Note the period at the end of the line.
$Body += "No advertisements found, exiting"
Presumably I could just concatenate and it would work but oh well, I'm keeping it as it. I didn't think that it would be that finicky about a period but now I know.

Create Outlook email draft using PowerShell

I'm creating a PowerShell script to automate a process at work. This process requires an email to be filled in and sent to someone else. The email will always roughly follow the same sort of template however it will probably never be the same every time so I want to create an email draft in Outlook and open the email window so the extra details can be filled in before sending.
I've done a bit of searching online but all I can find is some code to send email silently. The code is as follows:
$ol = New-Object -comObject Outlook.Application
$mail = $ol.CreateItem(0)
$Mail.Recipients.Add("XXX#YYY.ZZZ")
$Mail.Subject = "PS1 Script TestMail"
$Mail.Body = "
Test Mail
"
$Mail.Send()
In short, does anyone have any idea how to create and save a new Outlook email draft and immediately open that draft for editing?
Based on the other answers, I have trimmed down the code a bit and use
$ol = New-Object -comObject Outlook.Application
$mail = $ol.CreateItem(0)
$mail.Subject = "<subject>"
$mail.Body = "<body>"
$mail.save()
$inspector = $mail.GetInspector
$inspector.Display()
This removes the unnecessary step of retrieving the mail from the drafts folder. Incidentally, it also removes an error that occurred in Shay Levy's code when two draft emails had the same subject.
$olFolderDrafts = 16
$ol = New-Object -comObject Outlook.Application
$ns = $ol.GetNameSpace("MAPI")
# call the save method yo dave the email in the drafts folder
$mail = $ol.CreateItem(0)
$null = $Mail.Recipients.Add("XXX#YYY.ZZZ")
$Mail.Subject = "PS1 Script TestMail"
$Mail.Body = " Test Mail "
$Mail.save()
# get it back from drafts and update the body
$drafts = $ns.GetDefaultFolder($olFolderDrafts)
$draft = $drafts.Items | where {$_.subject -eq 'PS1 Script TestMail'}
$draft.body += "`n foo bar"
$draft.save()
# send the message
#$draft.Send()
I think Shay Levy's answer is almost there: the only bit missing is the display of the item.
To do this, all you need is to get the relevant inspector object and tell it to display itself, thus:
$inspector = $draft.GetInspector
$inspector.Display()
See the MSDN help on GetInspector for fancier behaviour.
if you want to use HTML template please use HTMLbody instead of Body , please find sample code below:
$ol = New-Object -comObject Outlook.Application
$mail = $ol.CreateItem(0)
$mail.Subject = "Top demand apps-SOURCE CLARIFICATION"
$mail.HTMLBody="<html><head></head><body><b>Joseph</b></body></Html>"
$mail.save()
$inspector = $mail.GetInspector
$inspector.Display()
Thought I would add in to this as well. There are a few steps you can save yourself if you know a lot of the basics (subject, recipients, or other aspects). First create the template of the email and save that, e.g. somewhere maybe with the code?
As to the code itself, it follows much the same that others have posted.
Borrowing from Jason:
$ol = New-Object -comObject Outlook.Application
$msg = $ol.CreateItemFromTemplate(<<Path to template file>>)
Modify as needed. Append fields or modify body. The message can still be viewed prior to sending the same way $msg.GetInspector.Display(). Then call $msg.send() to send away!