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.
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.