# Send-MailMessage alternative in 2026

Source: https://developer.nylas.com/docs/cookbook/email/send-mailmessage-alternative/

Microsoft marked `Send-MailMessage` obsolete years ago, and the warning still sits at the top of the [Send-MailMessage cmdlet reference](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/send-mailmessage): "The `Send-MailMessage` cmdlet is obsolete. This cmdlet doesn't guarantee secure connections to SMTP servers." It still runs, but Microsoft won't fix bugs or add features, and it can't talk to modern OAuth mailboxes. So if you've got a PowerShell script that fires off alerts or reports, you're now picking a replacement you'll actually maintain.

The usual reflexes are `System.Net.Mail.SmtpClient` (also marked obsolete) or wiring up SMTP credentials by hand. Both leave you managing app passwords, TLS settings, and a relay host. This guide shows a REST replacement you call straight from `Invoke-RestMethod`, and it's honest about the cases where plain SMTP is still the better call.

## What can I use instead of Send-MailMessage in PowerShell?

The supported replacement is a REST email API you call with `Invoke-RestMethod`, not another SMTP cmdlet. Microsoft's own guidance points to MailKit or Microsoft Graph because both `Send-MailMessage` and `System.Net.Mail.SmtpClient` are obsolete. A unified send endpoint goes further: one `POST` reaches Gmail, Microsoft 365, Yahoo, and IMAP without per-host SMTP config.

`Send-MailMessage` was convenient because it shipped in the box. Its replacement has to keep that one-liner feel while fixing the security gap. A hosted API does this by moving authentication off your script: you send JSON to `POST /v3/grants/{grant_id}/messages/send` with a bearer token, and the provider's OAuth, TLS, and DKIM are handled upstream. No app password sits in your `.ps1` file, and the same call works whether the connected mailbox is Google or Microsoft. The send request caches its response for 1 hour per grant when you pass an `Idempotency-Key`, so a retried scheduled task won't double-send.

## How do I send email from a PowerShell script on Windows?

Build a hashtable, convert it to JSON, and `POST` it to the send endpoint with `Invoke-RestMethod`. On Windows PowerShell 5.1 or PowerShell 7, this replaces the obsolete `Send-MailMessage` in about eight lines. The API accepts `to`, `subject`, and `body` at minimum, and a single bearer token authenticates every request instead of a stored SMTP password.

The call below sends one message through a connected mailbox. It targets `POST /v3/grants/{grant_id}/messages/send`, which works identically across Google, Microsoft 365, and Yahoo, so the same script serves any team regardless of provider. Read the API key from an environment variable so it never lands in source control.

```powershell
$headers = @{
    "Authorization" = "Bearer $env:NYLAS_API_KEY"
    "Content-Type"  = "application/json"
}

$body = @{
    to      = @(@{ name = "Dana Operator"; email = "dana@example.com" })
    subject = "Nightly backup completed"
    body    = "All 14 jobs finished successfully at $(Get-Date -Format o)."
} | ConvertTo-Json -Depth 4

Invoke-RestMethod -Method Post `
    -Uri "https://api.us.nylas.com/v3/grants/$env:NYLAS_GRANT_ID/messages/send" `
    -Headers $headers `
    -Body $body
```

Schedule it with Task Scheduler the same way you ran the old cmdlet. The deeper walkthrough, including storing the key securely and adding `schtasks` triggers, lives in [send email from a PowerShell script](/docs/cookbook/cli/send-email-powershell/).

## How do I send email from a bash script or cron job?

Use `curl` to `POST` JSON to the same send endpoint, then drop the line into crontab. The REST approach means a Linux cron job and a Windows scheduled task hit identical infrastructure, so one mailbox integration covers both. No `sendmail` binary, no local MTA, and no `/etc/postfix` to configure on the host.

This `curl` call posts to `POST /v3/grants/{grant_id}/messages/send` with the same JSON shape the PowerShell version uses. It's handy for cron-driven reports or alerting from a CI runner, and the response returns the sent message ID for logging. Pass an `Idempotency-Key` header (max 256 characters) if a flaky cron host might retry within the hour.

```bash
curl --request POST \
  --url "https://api.us.nylas.com/v3/grants/${NYLAS_GRANT_ID}/messages/send" \
  --header "Authorization: Bearer ${NYLAS_API_KEY}" \
  --header "Content-Type: application/json" \
  --data '{
    "to": [{ "name": "Dana Operator", "email": "dana@example.com" }],
    "subject": "Nightly backup completed",
    "body": "All 14 jobs finished successfully."
  }'
```

To run the same logic inside a container instead of a host cron, the [transactional send](/docs/cookbook/email/transactional-send/) guide covers sending from a verified domain without a user mailbox, which suits unattended notification workloads.

## Send-MailMessage vs a REST email API

`Send-MailMessage` authenticates with a plaintext SMTP password and can only reach a host you configure. A REST API authenticates with a bearer token and reaches every connected provider through one call. The table below compares the obsolete cmdlet, raw SMTP through MailKit, and the unified send endpoint on the work a script actually does.

| Task | Send-MailMessage (obsolete) | SMTP through MailKit | **Unified REST API** |
| --- | --- | --- | --- |
| **Status** | Deprecated, no fixes | Supported | **Supported** |
| **Auth** | Plaintext SMTP password | App password or OAuth token | **One bearer token** |
| **Modern OAuth mailboxes** | No | Manual XOAUTH2 setup | **Built in** |
| **Multiple providers** | One SMTP host | One host per provider | **Gmail, Microsoft, Yahoo, IMAP** |
| **Delivery tracking** | None | None | **`tracking_options` for opens and links** |

The `tracking_options` row is the practical reason teams switch: SMTP gives you no read receipt or click data, while the send endpoint accepts an `opens` and `links` flag in the same payload. That said, the comparison isn't one-sided, which the next section covers.

## When does System.Net.Mail or plain SMTP still work?

Plain SMTP still works when you send to one internal relay that allows anonymous or basic auth, and you don't need OAuth, tracking, or multi-provider reach. A locally hosted SMTP server on port 25 inside a trusted network is a legitimate case where `System.Net.Mail` or MailKit stays simpler than any API call. Don't add a dependency you won't use.

`System.Net.Mail.SmtpClient` is marked obsolete, but obsolete means unmaintained, not removed: it still compiles and runs on .NET and Windows PowerShell today. If your script sends to a fixed corporate Exchange relay over the LAN, with no public mailbox and no delivery analytics, the obsolete path costs nothing extra. That equation changes once you need to send through a Google or Microsoft 365 mailbox that requires OAuth, want per-message open and link tracking, or have to support more than one provider. At that point the 8-line `Invoke-RestMethod` replacement removes the app-password and TLS maintenance that basic SMTP keeps handing you.


> **Info:** 
> **New to Nylas?** Start with the [quickstart guide](/docs/v3/getting-started/) to set up your app and connect a test account before continuing here.


## What's next

- [Send email from a PowerShell script](/docs/cookbook/cli/send-email-powershell/) for the full Task Scheduler and secure-key setup
- [Transactional send](/docs/cookbook/email/transactional-send/) to send from a verified domain without a user mailbox
- [Microsoft Graph API alternative](/docs/cookbook/email/microsoft-graph-api-alternative/) if your scripts target Outlook and Microsoft 365
- [Getting started with Nylas](/docs/v3/getting-started/) to create a project, connect a mailbox, and get your first grant