PowerShell script to send email with attachment

How to start PowerShell?

We are going to use the PowerShell console to send an email message with attachments. First, open the PowerShell window from the Start Menu. Type PowerShell and click on the app.
Screenshot: Start PowerShell from Start Menu

How to send email from PowerShell?

The following script allows you to send an email message using PowerShell. It uses, FROM and TO fields to set the sender and recipient, as well as the subject, body, attachment arguments to create an email message. An SMTP server, username and password are required for the PowerShell script to send email using an SMTP server.

Send-MailMessage -From "Bob <bob@example.com>" `
                 -To "Lee <lee.sanders@example.com>", `
                     "Zoe <zoe.dow@example.com>" `
                 -Subject "Sending the Attachment from PowerShell" `
                 -Body "The body of email goes here." `
                 -Attachment "invoice-001.pdf" `
                 -SmtpServer smtp.example.com `
                 -Port 587 `
                 -UseSsl `
                 -Credential (New-Object `
                   -TypeName System.Management.Automation.PSCredential `
                   -ArgumentList "Your-username-goes-here", `
                   (ConvertTo-SecureString `
                     -String "replace-this-with-your-password" `
                     -AsPlainText -Force))

How to test your script in the command line?

Just copy/paste the script into the PowerShell window you opened in the first step. But keep in mind that you need to adjust some command line arguments and switches. Otherwise the script will not work in your environment.
Screenshot: PowerShell email example

At least, change the following parameters to the values of your email:

  • From address
  • To address
  • SMTP server address and port number
  • SMTP username and password

If you don’t know which values to use for SMTP server and port, check this page for SMTP settings for popular email providers.

How to use PowerShell to send email from a single-line command?

If you look at the example above, you will notice the grave accent (backtick) characters at the end of each line. This is a PowerShell way to split one long command to multiple lines. If you want to use the command as a single line, copy/paste the following code:

Send-MailMessage -From "Bob <bob@example.com>" -To "Lee <lee.sanders@example.com>", "Zoe <zoe.dow@example.com>" -Subject "Sending the Attachment from PowerShell" -Body "The body of email goes here." -Attachment "invoice-001.pdf" -SmtpServer smtp.example.com -Port 587 -UseSsl -Credential (New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "Your-username-goes-here", (ConvertTo-SecureString -String "replace-this-with-your-password" -AsPlainText -Force))

PowerShell · the send email function explained

As you noticed, we are using a PowerShell built-in function Send-MailMessage. In the PowerShell world such functions are called cmdlets. Here is an official documentation of PowerShell Email.

Argument Help
-From from address
-To one or more recipients
-Subject subject text
-Body email body plain text
-Attachment or -Attachments one or multiple attachments
-SmtpServer address or IP of the mail server
-Port port number, usually 587 or 465
-UseSsl switch to enable TLS or SSL
-Credential PSCredential object

A little bizarre part that sets SMTP server’s username and password is explained below. The PowerShell’s send email credentials require a PSCredential object, which we construct using a combo of commands that at the end creates the PSCredential object instance from the System.Management.Automation namespace.

Argument/Command Help
New-Object creates an object
-TypeName .NET framework class name
-ArgumentList array of arguments for the object constructor
ConvertTo-SecureString plain text to secure string*
-String input for the ConvertTo function
-AsPlainText  the input is plain text
-Force confirms that you are using a plain text password

* PSCredential class expects us to provide a secure password or string, but what we want is to pass a plain text string, thus we need to convert it.

PowerShell script to send HTML email

With a small change to the above script we can send rich formatted emails in the HTML format. It is easy! Just add a -BodyAsHtml switch, and you can start adding HTML tags in the body text. See the example below.

Send-MailMessage -From "Bob <bob@example.com>" `
                 -To "Lee <lee.sanders@example.com>", `
                     "Zoe <zoe.dow@example.com>" `
                 -Subject "Sending the Attachment from PowerShell" `
                 -Body "The text now can be <b>bold</b> or <i>italic</i>." `
                 -BodyAsHtml `
                 -Attachment "invoice-001.pdf" `
                 -SmtpServer smtp.example.com `
                 -Port 587 `
                 -UseSsl `
                 -Credential (New-Object `
                   -TypeName System.Management.Automation.PSCredential `
                   -ArgumentList "Your-username-goes-here", `
                   (ConvertTo-SecureString `
                     -String "replace-this-with-your-password" `
                     -AsPlainText -Force))

Notice that the body text contains HTML markup. There is an italic and bold text. As you can imagine, it will appear with a cursive font or as a thicker text than the surrounding text. Here is an HTML code:

The text now can be <b>bold</b> or <i>italic</i>.

And this is how it looks in the final email:
The text now can be bold or italic.

You can add other HTML tags too, for example, A, BR, DIV, FONT, H1, IMG, and much more. Ranadeep Bhuyan has compiled a list of allowed HTML tags in the email body.
But of course you need to test it out yourself, because email clients and the internet are evolving rapidly, and the things that work today, may not work at the time of reading this article.

Fine-tune the Send-MailMessage cmdlet

There are more command line arguments to adjust your email message:

  • -Bcc specifies the email address of a blind carbon copy. The address which will receive a copy of email but will not be listed as a recipient of the email message.
  • -Encoding specifies the character set for the email message. The default is UTF-8 without a Byte Order Mark or BOM. To send a plain text message, use -Encoding ASCII argument.
  • -Priority allows to set the priority of the email message. Use -Priority High, or -Priority Low to change the default (normal) priority.
Send-MailMessage -From "John <john@example.com>" `
                 -To "Linda <linda@example.com>"
                 -Priority High `
                 -Encoding ASCII `
                 -Subject "This is a plain text message" `
                 -Body "Notice the priority and encoding arguments..."

How to send email automatically from a PowerShell script?

The obvious choice is to use the Windows built-in Task Scheduler. Just use the “Start a program” action to start your PowerShell script. It does its job, if you need to start a task on a simple schedule, but if you need to react on local files or on remote files that are located on an FTP server, you may need to use the commercial solution.
Screenshot: Start a program from Windows Task Scheduler

To launch the cmdlet from Task Scheduler, you need to adjust your command:

  1. Copy the one-line command example I provided above.
  2. Use this syntax: PowerShell.exe -Command "&{ the_command_goes_here }"
  3. Make sure to change all double quotes ” to single quotes ‘

This is how it looks when the quotes are changed, and the command is ready to be launched from Scheduled Tasks or from the Windows command line:

PowerShell.exe -Command "&{ Send-MailMessage -From 'Bob <bob@example.com>' -To 'Lee <lee@example.com>' -Subject 'Sending the Attachment from Schedulet Tasks' -Body 'The body of email goes here.' -Attachment 'invoice-002.pdf' -SmtpServer smtp.example.com -Port 587 -UseSsl -Credential (New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList 'Your-username-goes-here', (ConvertTo-SecureString -String 'replace-this-with-your-password' -AsPlainText -Force)) }"

In the “Start a program” action you must separate the command into two parts, the PowerShell app and the arguments. Just copy/paste the whole command argument into the small “Add arguments” box. And don’t forget to provide the path where your attachments are located.
Screenshot: Start a program from Windows Task Scheduler with arguments

Alternatives to Windows Task Scheduler

Is PowerShell script to send email deprecated?

As you may noticed the official Microsoft documentation article of the PowerShell script says:

The Send-MailMessage cmdlet is obsolete. This cmdlet does not guarantee secure connections to SMTP servers. While there is no immediate replacement available in PowerShell, we recommend you do not use Send-MailMessage.

You are not in the immediate danger if you are using the PowerShell script to send email automatically on a Local Area Network or LAN. Because no one is sniffing your local network traffic.
But if you are planning to use the PowerShell on the Internet to send out emails, I recommend to use the app called Command Line Email. It is a ready-to-use alternative, that is updated together with Windows Update.

How to automate emails with attachments, but without using scripts?

To use the automation without writing a single line of code, I recommend the intelligent automation solution called Automation Workshop. It is a Windows app that can automate any Windows tasks including email sending.

Screenshot: Automation Workshop Send Email Action

It is available as a Free to try version or a Free for non-commercial use edition. View the detailed step-by-step tutorials on email automation below. You will learn how to send automatic emails with attachments using a point-and-click user interface.

Is PowerShell a good tool for scripting and automation?

If you still prefer to use PowerShell instead of no-code solution Automation Workshop, the question remains: Is it good for automation?
If you are a programmer or software developer, and you can live with the fact that Microsoft sometimes breaks stuff (the Send-MailMessage cmdlet is obsolete and a fix is not available), then the answer is – probably.

Pros of using PowerShell:

  • It is mature – 14 years old scripting language.
  • It is open-source and cross-platform as of 2016.
  • It has reached version v7.1.2 and is still being actively developed.

Cons of using PowerShell:

  • It is not a very popular language. The TIOBE lists it as a number 50 with a very low usage of 0.21% as of Feb 25, 2021. If you are a PowerShell programmer yourself, this may not be a problem. But if you want to hire one, then its low usage may come at the cost of less available workforce.
  • It lacks error handling and logging capabilities that are present in no-code and low-code automation solutions. For example, the Log Manager of Automation Workshop.
  • Writing a program code is a long process, and there are always bugs. Industry average experience is about 1-25 errors per 1000 lines of code for delivered software. This a quote from the book called Code Complete that is written by Steve McConnell. On the other hand, automated tasks that are created using a no-code solution have less defects, because there is no code.

Credits and thanks goes to:

Do you still have unanswered PowerShell questions?

The best place to ask programming questions, including ones that relates to using PowerShell, is the StackOverflow website. As of 2021 they have more than 80,000 questions and answers related to the Microsoft cross-platform scripting tool.