MailSlurp logo

blog

PowerShell Send Email SMTP Guide (Send-MailMessage, API, and Testing)

Send email from PowerShell with Send-MailMessage, SMTP auth, multiple recipients, attachments, API sends, and MailSlurp receive-side testing.

If you searched for "powershell send email smtp", you likely need one of three things: a quick Send-MailMessage example, a safer replacement for a production script, or a way to prove that the message actually arrived.

PowerShell can still send SMTP mail, but the script should not hide credentials in source code or stop at "command returned successfully". A reliable workflow sends with explicit server settings, captures failures, and checks a real inbox with MailSlurp before the job is trusted.

Quick answer

  • Send-MailMessage still works for many Windows scripts, but Microsoft marks it obsolete because it cannot guarantee secure SMTP connections in every scenario.
  • For existing scripts, use explicit SMTP host, port, TLS, and credentials from environment variables or a secret store.
  • For new production automation, prefer an email API or SDK when you need clearer retries, auditing, and test evidence.
  • For CI and release checks, send to a MailSlurp inbox and wait for the received email before passing the job.

Choose the right PowerShell email path

Need Best starting point Why
Maintain an existing Windows alert script Send-MailMessage with explicit SMTP settings Lowest-change path for legacy jobs.
Send a scheduled report with attachments SMTP or API send with a real inbox check Confirms the file and recipient list work end to end.
Build a new production workflow MailSlurp API, SMTP inbox, or SDK Keeps credentials, logs, and receive-side assertions in one workflow.
Test signup, reset, or OTP email MailSlurp sandbox inbox plus wait-for-email checks Verifies content, links, codes, headers, and delivery timing.

If you are still choosing between SMTP and HTTP APIs, read SMTP vs HTTP email APIs before locking in the transport.

Set SMTP credentials without hardcoding secrets

Use your CI secret store, Windows credential store, or shell environment to supply SMTP settings. This example shows the values the later snippets expect:

$env:SMTP_HOST = "smtp.example.com"
$env:SMTP_PORT = "587"
$env:SMTP_USER = "smtp-user"
$env:SMTP_PASS = "smtp-password"
$env:SMTP_FROM = "alerts@example.com"

For MailSlurp API examples, keep the API key and inbox ID outside source control too:

$env:MAILSLURP_API_KEY = "your-api-key"
$env:MAILSLURP_INBOX_ID = "your-sending-inbox-id"

Send email with Send-MailMessage

Use this pattern when you need to keep an existing Send-MailMessage script running while you plan a safer long-term path:

$securePassword = ConvertTo-SecureString $env:SMTP_PASS -AsPlainText -Force
$credential = [System.Management.Automation.PSCredential]::new(
  $env:SMTP_USER,
  $securePassword
)

Send-MailMessage `
  -SmtpServer $env:SMTP_HOST `
  -Port ([int]$env:SMTP_PORT) `
  -UseSsl `
  -Credential $credential `
  -From $env:SMTP_FROM `
  -To "ops@example.com" `
  -Subject "Nightly job completed" `
  -Body "The nightly job completed successfully."

This is intentionally explicit. Do not rely on a machine-level $PSEmailServer value unless every environment is controlled and documented.

Send to multiple recipients, CC, and BCC

Many existing scripts need to notify more than one person. PowerShell accepts arrays for -To, -Cc, and -Bcc:

$to = @("ops@example.com", "qa@example.com")
$cc = @("team-lead@example.com")
$bcc = @("audit@example.com")

Send-MailMessage `
  -SmtpServer $env:SMTP_HOST `
  -Port ([int]$env:SMTP_PORT) `
  -UseSsl `
  -Credential $credential `
  -From $env:SMTP_FROM `
  -To $to `
  -Cc $cc `
  -Bcc $bcc `
  -Subject "PowerShell report ready" `
  -Body "The attached report is ready for review."

When recipient privacy matters, test To, Cc, and Bcc behavior with separate MailSlurp inboxes before sending to customers. Use BCC and CC in SMTP emails for the SMTP-level behavior to check.

Send attachments from PowerShell

Attach files with the -Attachments parameter. Keep attachment paths deterministic so scheduled jobs do not silently send yesterday's file:

$attachments = @(
  "C:\reports\nightly-summary.csv",
  "C:\reports\errors.txt"
)

foreach ($path in $attachments) {
  if (!(Test-Path $path)) {
    throw "Missing attachment: $path"
  }
}

Send-MailMessage `
  -SmtpServer $env:SMTP_HOST `
  -Port ([int]$env:SMTP_PORT) `
  -UseSsl `
  -Credential $credential `
  -From $env:SMTP_FROM `
  -To "ops@example.com" `
  -Subject "Nightly report" `
  -Body "Report files are attached." `
  -Attachments $attachments

After changing attachment logic, send to a MailSlurp inbox and check that the expected filenames and content types arrive.

Send HTML email from PowerShell

Use -BodyAsHtml only when the body is valid HTML and your test checks the rendered content:

$htmlBody = @"
<h1>Deployment complete</h1>
<p>Environment: production</p>
<p>Status: green</p>
"@

Send-MailMessage `
  -SmtpServer $env:SMTP_HOST `
  -Port ([int]$env:SMTP_PORT) `
  -UseSsl `
  -Credential $credential `
  -From $env:SMTP_FROM `
  -To "release@example.com" `
  -Subject "Deployment complete" `
  -Body $htmlBody `
  -BodyAsHtml

If the message reaches users, run it through email client testing and a deliverability test before a broad send.

Why Send-MailMessage is not the final answer

Send-MailMessage is convenient, but it is obsolete in current PowerShell guidance. That does not mean every old script must be rewritten today; it does mean new automation should have a migration path.

For scripts that continue to use it:

  • require TLS with -UseSsl and the expected submission port
  • keep credentials out of the script file
  • fail the job when SMTP auth, DNS, or attachment checks fail
  • send test messages to MailSlurp and assert the inbox result
  • monitor sender authentication with SMTP authentication and STARTTLS vs SSL vs TLS

For new work, use an API or a supported SDK when you need stronger delivery controls, queue behavior, bounce handling, or test assertions.

Send email from PowerShell with the MailSlurp API

MailSlurp inboxes can send and receive messages through the API. This keeps the email flow easy to test from any PowerShell environment:

$apiKey = $env:MAILSLURP_API_KEY
$inboxId = $env:MAILSLURP_INBOX_ID

$sendOptions = @{
  to = @("recipient@example.com")
  subject = "PowerShell API smoke test"
  body = "Sent from a PowerShell job through MailSlurp."
} | ConvertTo-Json

$response = Invoke-RestMethod `
  -Method Post `
  -Uri "https://api.mailslurp.com/inboxes/$inboxId/confirm" `
  -ContentType "application/json" `
  -Headers @{ "x-api-key" = $apiKey } `
  -Body $sendOptions

$response.id

Use this for smoke tests, support scripts, and scheduled automation where you want API response data instead of a local SMTP-only result.

Wait for the received email

A send command only proves the provider accepted the request. For tests, wait for MailSlurp to receive the message and assert the content:

$receiveInboxId = $env:MAILSLURP_RECEIVE_INBOX_ID

$latestEmail = Invoke-RestMethod `
  -Method Get `
  -Uri "https://api.mailslurp.com/waitForLatestEmail?inboxId=$receiveInboxId&timeout=120000&unreadOnly=true" `
  -Headers @{ "x-api-key" = $apiKey }

if ($latestEmail.subject -ne "PowerShell API smoke test") {
  throw "Unexpected subject: $($latestEmail.subject)"
}

if ($latestEmail.body -notmatch "PowerShell job") {
  throw "Expected body text was not found."
}

That receive-side check is the difference between "PowerShell did not throw" and "the email workflow works".

Troubleshooting PowerShell SMTP errors

535 authentication failed

Check the SMTP username, password, tenant policy, and app-password requirement. Then confirm the port and TLS mode match the provider. Use SMTP authentication errors for a deeper checklist.

Connection timed out

Check firewall rules, outbound port restrictions, and whether your provider expects port 587 with STARTTLS rather than port 25. Use SMTP ports when validating the decision.

Message accepted but never arrives

Inspect SPF, DKIM, DMARC, headers, spam score, and blacklist status. MailSlurp tools for email headers, SPF, DKIM, DMARC, and blacklist checks help isolate where the message failed.

Attachment missing or empty

Check the file path before sending, avoid relative paths in scheduled jobs, and assert the attachment list on the received MailSlurp email.

Production checklist for PowerShell email jobs

Before relying on a PowerShell email script:

  • store SMTP and API secrets outside the script
  • log the message ID or API response ID
  • send at least one test message to a MailSlurp inbox
  • assert subject, body, recipient, and attachment evidence
  • verify sender authentication and TLS settings
  • monitor bounces and webhook events for production workflows

Start with Email Sandbox for isolated end-to-end validation, email integration testing for CI assertions, and email webhooks when messages trigger downstream workflows.

Final take

Use Send-MailMessage when you need to maintain an existing PowerShell script, but treat it as a legacy path. For new automation, use an API or supported SDK, keep secrets out of the script, and make MailSlurp inbox receipt part of the test.