[June 27, 2014] Update: I’ve made several updates, including multiple recipients and sending attachments.
If you’ve created a PowerShell script that runs as a scheduled task, you may want to have it send you an e-mail with a log file or other notification about what the script did or didn’t do (i.e. error notification). PowerShell version 2 provides the Send-MailMessage
cmdlet to do this, but in some cases the older System.Net.Mail
.NET namespace is a more desirable approach (System.Net.Mail
also works in PowerShell version 1).
The Send-MailMessage Method
Here is an example of the Send-MailMessage
cmdlet:
$emailSmtpServer = "mail.somewhere.com" $emailFrom = "John Smith <john@somewhere.com>" $emailTo = "jane@somewhere.com" $emailSubject = "Testing e-mail" $emailBody = @" Here is a message From your friendly neighborhood IT guy "@ Send-MailMessage -To $emailTo -From $emailFrom -Subject $emailSubject -Body $emailBody -SmtpServer $emailSmtpServer
Some notes:
- On line 1,
$emailSmtpServer
is the mail server that you will be using to send the message. - On line 2,
$emailFrom
contains a friendly name (i.e. “John Smith”) followed by John’s e-mail addressed, enclosed in <>.
You can use HTML formatting in the $emailBody
if you specify the -BodyAsHTML
flag in the Send-MailMessage command, like this:
$emailBody = @" <p>Here is a message that is <strong>HTML formatted</strong>.</p> <p>From your friendly neighborhood IT guy</p> "@ Send-MailMessage -To $emailTo -From $emailFrom -Subject $emailSubject -Body $emailBody -BodyAsHTML -SmtpServer $emailSmtpServer
That message will come out looking something like this:
Here is a message that is HTML formatted.
From your friendly neighborhood IT guy
If you need to send an attachment, change your Send-MailMessage
command to something like this:
$attachment = "C:\myfile.txt" #Or do multiple attachments like this: $attachment = "C:\myfile1.txt","C:\myfile2.txt" Send-MailMessage -To $emailTo -From $emailFrom -Subject $emailSubject -Body $emailBody -BodyAsHTML -Attachments $attachment -SmtpServer $emailSmtpServer
The System.Net.Mail Method
The Send-MailMessage
method works well, if you have an SMTP server that does not require authentication and works on the standard SMTP port (port 25). If you need to send the message through an e-mail system such as GMail or Exchange Online which requires authentication and TLS on port 587, then using the System.Net.Mail
.NET namespace is a good way to go.
$emailSmtpServer = "mail.somewhere.com" $emailSmtpServerPort = "587" $emailSmtpUser = "username" $emailSmtpPass = "password" $emailMessage = New-Object System.Net.Mail.MailMessage $emailMessage.From = "John Smith <john@somewhere.com>" $emailMessage.To.Add( "jane@somewhere.com" ) $emailMessage.Subject = "Testing e-mail" $emailMessage.IsBodyHtml = $true $emailMessage.Body = @" <p>Here is a message that is <strong>HTML formatted</strong>.</p> <p>From your friendly neighborhood IT guy</p> "@ $SMTPClient = New-Object System.Net.Mail.SmtpClient( $emailSmtpServer , $emailSmtpServerPort ) $SMTPClient.EnableSsl = $true $SMTPClient.Credentials = New-Object System.Net.NetworkCredential( $emailSmtpUser , $emailSmtpPass ); $SMTPClient.Send( $emailMessage )
Essentially, what we are doing is building the mail message $emailMessage
with its various components, building the $SMTPClient
with the server and credential information, and then using that to send the mail message. This obviously takes some more code, but it is more flexible than the Send-MailMessage
method.
To send attachments using this method, add this before the $SMTPClient.Send
line:
$attachment = "C:\myfile.txt" $emailMessage.Attachments.Add( $attachment )
For multiple attachments, just repeat those two lines of code, with the new file name.
Multiple Recipients
If you need to your message to multiple recipients, for the Send-MailMessage
method:
$emailTo = "jane@somewhere.com","jim@somewhere.com"
For the System.Net.Mail
method:
$emailMessage.To.Add( "jane@somewhere.com" ) $emailMessage.To.Add( "jim@somewhere.com" )
Here-Strings
On a side note, I’ve used a Here-String for the $emailBody
variable. When sending a non-HTML formatted message, this allows you to easily insert line breaks without having to use `n
notation. Even when sending an HTML formatted message, it makes it easier to read in your code.
Permalink
Thanks for the TLS example. There were a couple of bugs though:
1. The following needs to be inserted at line 14:
2. Line 19 should read:
Permalink
I apologize for the oversight. You are absolutely correct. I have made the corrections in the TLS example.
I had originally used the code in a more complex script and consequently missed a piece when I posted it here.
As far as the SMTPClient.Send portion, I notice that you suggest removing the spaces from before and within the parentheses. The only space that actually NEEDS to be removed is the one between “Send” and the opening parenthesis.
I tend to use spaces within the parentheses to make the code a little more legible (especially in the case of nested parentheses), but they are certainly not necessary.
Permalink
how about multiple recipient?
i tried
$emailTo = @(“nick.ry.khor@carlsberg.asia”, “nick_khor@hotmail.com”)
it doesn’t work.
Permalink
Hey Nick,
Just tried it here and that format worked for me. From your script, are you able to send mail to each of these accounts when you have them in as single recipients (i.e. try once for the first account and then try again for the second account)? I’m wondering if there’s something else going on with mail delivery.
Permalink
Correction – it works in my first example, the unauthenticated method using Send-MailMessage. I will check on the proper syntax to add multiple recipients for System.Net.Mail.MailMessage.
Permalink
Hi Phil, sorry that i forgotten to reply.
It is working now.
THanks 😀
Permalink
I’ve updated the post to show the proper way to do multiple recipients when using System.Net.Mail.
Permalink
how to send attachment using the above code. I am able to send the mail
Permalink
I apologize for the delay in answering your question. I’ve made some updates to this post, including how to send attachments.
Permalink
This was beautiful. Thanks a bunch, Phil!
Permalink
I get the following error
Exception calling “Send” with “1” argument(s): “Failure sending mail.”
At C:\Scripts\Send-Email02.ps1:21 char:17
+ $SMTPClient.Send <<<< ($emailMessage )
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
Permalink
Hey James,
Can you provide a little more information about your code? If you don’t want to paste parts of your code publicly here, feel free use my contact form and I’ll see if I can find anything.
Also, what version of Windows and PowerShell are you testing this on?
Permalink
Thank you for the quick response. It works on my Windows 8.1 machine. But the script is for a general users that is running a Windows 7 PC and we have a Exchange 2010 environment.
$emailSmtpServer = “mail.xyz.com”
$emailSmtpServerPort = “587”
$emailSmtpUser = “xyz\jdoe”
$emailSmtpPass = “password”
$emailMessage = New-Object System.Net.Mail.MailMessage
$emailMessage.From = “jdoe@xyz.org”
$emailMessage.To.Add( “kdoe@xyz.org” )
$emailMessage.Subject = “Testing e-mail”
$emailMessage.IsBodyHtml = “True”
$emailMessage.Body = $emailBody
$emailMessage.Body = @”
Here is a message that is HTML formatted.
From your friendly neighborhood IT guy
“@
$SMTPClient = New-Object System.Net.Mail.SmtpClient( $emailSmtpServer , $emailSmtpServerPort )
$SMTPClient.EnableSsl = $true
$SMTPClient.Credentials = New-Object System.Net.NetworkCredential( $emailSmtpUser , $emailSmtpPass );
$SMTPClient.Send($emailMessage )
Permalink
Hey James,
I took your code, plugged in my server info (an on-prem 2007 Exchange system, in this case) and credentials and the message sent without any issues. I made a few tweaks to my environment to try to reproduce the error (i.e. setting the Exchange Receive Connector to not accept my IP address, using bad credentials, etc.) and I couldn’t get that exact message.
A few things to try:
1) The line “$emailMessage.Body = $emailBody” is unnecessary, but I verified that it’s not causing the issue.
2) Make sure that all of your quotes are standard “non-curly” quotes – especially when copying from web pages, they can get a little wonky. In my experience, even if they look like they pasted fine into PowerShell, there might still be an issue, so put them into Notepad first and check them out.
3) Check to ensure that you can communicate to your Exchange server on port 587 from your client IP address. In particular, the Exchange Receive Connectors need to accept authenticated messages from your IP and any firewalls in between you and the mail server also need to allow the communication. The best way I can think to test this is to configure a mail client on your computer to point to the server/port that you’re trying to use in the script. Also, ensure that you’re pointing to the right Exchange server (if there are multiple in your environment) – my standard Exchange build, for instance, has the hub transport role on a different set of servers than the mailbox role. I can’t guarantee that any of this is the culprit – as the error messages for these issues should be more descriptive, but it’s worth checking. Been there.
I’m curious about your problem. Please let me know if you track it down or come across more information that I could help with.
Permalink
Another thought just occurred to me – some antivirus programs can be configured to block SMTP connections, so that’s something else to check. Basically, make sure that you can communicate with the mail server from your client system before doing more code troubleshooting. System.Net.Mail.MailMessage will through similar errors whenever it can’t communicate with the mail server or if it receives an error from the mail server (can’t relay, unauthenticated, etc.), though it normally regurgitates that error message to the screen and doesn’t leave you hanging with a vague error.
Permalink
I needed the script but using port 25 with auth so I just changed the port and removed the SSL line and worked a treat much appreciated great solution.
Permalink
Thanks for this! Really helpful.
Permalink
The information on enabling SSL helped me a lot. Thanks. I still have one issue needs to work out and hope you can help me out here. We are using Office 365 to host mailbox, and zscaler for proxy. The script works great when it is not behind proxy, but fail with time out when it runs behind a proxy.
Thanks
-Byron
Permalink
Byron – sorry for not seeing this. I haven’t had to run this from behind a proxy to this point. Have you found any further information? I’ll have to see if I can get a test system behind a proxy to give it a shot. I assume that the proxy is allowing port 587 outbound to Office 365 (dumb question, most likely, but start with the obvious)? From the system running PowerShell, are you able to telnet to port 587 on outlook.office365.com?
Permalink
Hi Phil,
My requirement is I will get to list email ids in flat file, I need to send a mail to all the users in flat file in one go, can you please help me if there is any way to achieve this.
Thanks
Gopal
Permalink
Do you want to send an e-mail to each one individually? Or do you want one e-mail with all recipients on the same e-mail? Both can be accomplished, just different methods.
Permalink
Worked perfectly – thank you so much!!!
Permalink
Hi Phil, I tried this code more than 25 times with tweaks each time, and never got it to work:
$emailSmtpServer = “206.46.232.100”
$emailSmtpServerPort = “465”
$emailSmtpUser = “joepica”
$emailSmtpPass = “mypassword”
$emailMessage = New-Object System.Net.Mail.MailMessage
$emailMessage.From = “gg@verizon.net”
$emailMessage.To.Add(“olivia@metonto.com”)
$emailMessage.Subject = “Testing e-mail”
$emailMessage.IsBodyHtml = $true
$emailMessage.Body = @”
Here is a message that is HTML formatted.
From your friendly neighborhood IT guy
“@
$SMTPClient = New-Object System.Net.Mail.SmtpClient($emailSmtpServer, $emailSmtpServerPort)
$SMTPClient.EnableSsl = $true
$SMTPClient.Credentials = New-Object System.Net.NetworkCredential($emailSmtpUser, $emailSmtpPass)
$SMTPClient.Send($emailMessage)
The error I get is this:
PS C:\users\admin> .\email6.ps1
Exception calling “Send” with “1” argument(s): “The operation has timed out.”
At C:\users\admin\email6.ps1:19 char:1
+ $SMTPClient.Send($emailMessage)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : SmtpException
Can you help? I’m really frustrated. I copied the params right out of Thunderbird which I have been using for years. I also turned off my virus protection. Thanks Very Greatly in advance!! Stephen F.
Permalink
First thing I’d recommend is a basic connectivity test with telnet. Try this from a command line:
telnet 206.46.232.100 465
If that doesn’t time out, then you’re connectivity is fine. It’ll go to a blank screen if the connection is successful. Chances are, if you’re using Thunderbird on the same system to connect to this server, the telnet connection should be successful (but just checking).
Note that the telnet client needs to be enabled on Windows 7 and above (go to Control Panel > Programs and Features > Turn Windows Features on or off).
How about the SSL setting? I’m assuming that the server requires it (I hope so!), but try disabling it.
Permalink
Change port 465 to 587. 587 – starttls, 465 – tls. This script uses starttls port (587) or smtp (25), and not tls (465).
Permalink
Thank you so much Phil, after years this post keeps helping people 🙂 this is the best post I found for sending emails with powershell, specially talking abouth the TLS method. Works perfectly! Elizabeth