Home/Transactional Email/SMTP ports/PowerShell send email SMTP

PowerShell send email SMTP

Sending email over SMTP in PowerShell is done with the Send-MailMessage cmdlet, which Microsoft has formally marked obsolete. Microsoft states that the cmdlet does not guarantee secure connections to SMTP servers and recommends against using it, while noting that no immediate replacement exists in PowerShell.

VerifiedBy Kam Low, Co-founder·Updated

The obsolete cmdlet and what its status means

Microsoft's reference for Send-MailMessage carries an explicit warning rather than a soft deprecation note. The cmdlet remains present and functional in PowerShell, so existing scripts continue to run, but its documented status is obsolete and its use is not recommended.

The reason given is the security guarantee, not the feature set. Send-MailMessage cannot guarantee an encrypted connection to the server, which is what disqualifies it for anything carrying credentials or personal data across an untrusted network.

The absence of a built-in replacement is why the cmdlet is still encountered. Microsoft's guidance points to the platform compatibility note DE0005 rather than to another cmdlet, so replacing it means adopting an external library or a service API rather than a different built-in command.

Required parameters

Three parameters are mandatory: From, To and Subject. A message missing any of them fails before a connection is attempted.

A server must also be specified, either through the SmtpServer parameter or by setting the $PSEmailServer preference variable, which supplies the default for the session. Without one, the command fails.

The Port parameter selects the submission port, and UseSsl enables TLS. The cmdlet's encryption behaviour is what Microsoft's warning concerns, so neither switch makes the cmdlet suitable for sensitive traffic on an untrusted path.

Common parameters

Body carries the message text, and BodyAsHtml marks that text as HTML rather than plain text. Without the switch, HTML markup is delivered literally as characters.

Attachments takes one or more file paths. Cc and Bcc take additional recipient addresses, following the same address rules as To.

Credential accepts a PSCredential object rather than a plaintext password argument. Building one from a hardcoded string in the script defeats the purpose, so the credential belongs in a secret store or an encrypted file read at runtime.

Authentication failures on major providers

An account password fails against Google and Microsoft accounts with multi-factor authentication enabled. The SMTP client cannot complete the second factor, so the provider rejects the credential outright rather than prompting.

The working credential on those providers is an application-specific password generated in the account security settings, or an OAuth token. Send-MailMessage supports the former through the Credential parameter and does not implement OAuth.

Credential scope produces the same symptom from the other direction. George, our CEO, hit it wiring up a provider check on our side: the SendGrid connection test probed an endpoint that requires the Sender Authentication scope, so a valid least-privilege Mail-Send key returned a 403 and was reported invalid. He swapped the probe to an endpoint any valid key can read, so invalid keys still fail with a 401 and valid narrow keys pass. A rejected credential is not always a wrong credential.

Microsoft has been retiring basic authentication for client SMTP submission, pointing at OAuth instead. A script authenticating with a password against Microsoft 365 is running against a mechanism scheduled for removal rather than a stable interface.

Where an internal relay still fits

An unauthenticated internal relay remains common in IT automation, where a server on a trusted network accepts mail from known internal hosts without credentials. That is a network-boundary control rather than an authentication one.

Its scope is narrow. Alerts to internal recipients through an internal relay never traverse the public internet, and the mail is not subject to another organisation's filtering.

A relay that faces anything wider than a trusted network needs the opposite posture. On our own relay, TCP 2525 is firewall-restricted to our API host, TLS and exact SMTP authentication are mandatory, every one-recipient route and MX snapshot is HMAC-signed, and arbitrary destinations, MX loops, extra recipients and unsigned or replayed requests are rejected.

Scripted alerting is a real job and worth taking seriously rather than treating as a lesser use of email. George's version of the requirement is specific: every error message emailed immediately, a daily digest that surfaces things like signup counts with the notable ones named, and alerts when a threshold moves. His reasoning is that silent failure is the hard problem, and an alert that never arrives is indistinguishable from a system that is working.

That is the argument for caring how the alert channel is built. A script that sends through an obsolete cmdlet against a mechanism a provider is retiring will eventually stop sending, and the way you find out is that the alerts you had stopped noticing were also the alerts that stopped arriving. Alerting infrastructure fails quietly by construction, because nobody misses a message they never expected to see.

Mail leaving the organisation is a different problem. Once a message goes to an external recipient, domain authentication and sender reputation govern whether it arrives, and an internal relay provides neither delivery status nor bounce handling.

Why application mail moves off SMTP cmdlets

The cmdlet reports whether the server accepted the message and nothing after that. Bounces, deferrals and spam-folder placement all happen after acceptance, so a script that completes without error has not established that anything was delivered.

Obsolete · no built-in replacement
PS> Send-MailMessage -SmtpServer …
WARNING: This cmdlet is obsolete and does not guarantee secure connections. There is no built-in replacement.
The replacement · authenticated API
POST /v1/messages
Idempotency-Key: reset-8842
202 accepted · id: msg_01HQX4…
per-message status, safe to retry
The cmdlet still runs, which is the trap: nothing breaks on the day the mail stops arriving.
Microsoft marked the cmdlet obsolete and shipped no successor. Application mail moves to an authenticated API with per-message status.

There is no retry, queue or idempotency behaviour. A transient failure surfaces as a terminating error for the script to handle, and a re-run after a partial failure can duplicate messages already accepted.

An HTTP API replaces both gaps. A request returns a message identifier that can be queried for status and accepts an idempotency key so a retried request does not send twice, neither of which the SMTP conversation provides.

Authentication changes shape with it. An API key held server-side in the script's environment does the authenticating, which is what API keys are for, and no mailbox credential or second factor is involved.

We run our own operational alerting this way rather than through a mail client, using the transactional send path for platform-originated flows. That is a deliberate choice about where the alerting sits: the same interface that reports per-message status for customer mail reports it for our own, so an alert that fails to send is a visible failure rather than an absence nobody notices.

Go deeper

First send in thirty seconds.

Simple pricing. Unlimited contacts.

Every plan includes full stack emailing: Flows, Newsletter Campaigns and Transactional Email, plus our NitroWheel LLM and all agent integrations (Claude, ChatGPT, Codex, Cursor and others). Pay for what you send, not who you store.

Free
$0
forever
  • Emails 8,000then 500/mo
  • Email types Transactional & Marketing
  • AI actions 20/mo
  • Contacts Free & Unlimited
  • Brands 3 · Custom domain 1
  • Seats 1
  • Recipients / rolling 24h 100–5,000
  • Email validation Prepaid only
Start free
Ultra
$100
per month
  • Emails 125,000/month
  • AI actions 5,000/mo
  • Brands 10 · Domains 10
  • Seats 10
  • Frontier AI Included
  • Dedicated IP Available
  • Recipients / rolling 24h 1,000–625,000
  • Email validation Prepaid only
Get started
Enterprise
$300
per month
  • AI actions Unlimited
  • Unlimited brands & domains Included
  • SSO / SAML Included
  • 99.9% SLA Included
  • Recipients / rolling 24h Contracted
  • Email validation Prepaid only
Get started

Daily allowances depend on your plan and sender standing. Strong list, domain and delivery evidence can raise standing, including on day one. Trusted receives the full plan allowance; available email credits, safety checks and delivery pacing still apply.

Free forever. No credit card required. See full comparison →