Source: https://cli.nylas.com/guides/replace-send-mgusermessage

Guide

# Replace Send-MgUserMessage

Microsoft replaced the deprecated Send-MailMessage with Graph PowerShell cmdlets, but the replacement is more complex, not simpler. This guide shows side-by-side before/after examples so you can drop the Azure AD ceremony and send email in one command. Works with Gmail, Outlook, Exchange, Yahoo, iCloud, and IMAP.

Written by [Prem Keshari](https://cli.nylas.com/authors/prem-keshari) • Senior SRE

Reviewed by [Caleb Geene](https://cli.nylas.com/authors/caleb-geene)

Updated April 11, 2026

Verified

 —

CLI

3.1.1

 ·

Outlook

 ·

last tested

April 11, 2026

> **TL;DR:** `Send-MgUserMessage` requires Azure AD app registration, Graph API permissions, and a two-step create-then-send workflow. Replace it with `nylas email send` -- one command, OAuth2 built-in, works across Gmail, Outlook, Exchange, Yahoo, iCloud, and IMAP. Looking for the older deprecated cmdlet? See [Replace Send-MailMessage](https://cli.nylas.com/guides/replace-send-mailmessage).

## The problem with Send-MgUserMessage

Microsoft deprecated `Send-MailMessage` and pointed everyone to the Graph PowerShell SDK. But the replacement is harder, not easier. `Send-MgUserMessage` sends an existing draft -- it can't send a new email directly. You first create a draft with `New-MgUserMessage`, then send it in a second call. According to [Microsoft's official documentation](https://learn.microsoft.com/en-us/powershell/module/microsoft.graph.mail/send-mgusermessage), the full workflow looks like this:

- **Register an Azure AD app** in portal.azure.com with the correct redirect URIs
- **Grant Mail.Send permission** (delegated or application scope) and get admin consent
- **Authenticate every session** with `Connect-MgGraph -Scopes "Mail.Send"`
- **Two-step send**: create a draft with `New-MgUserMessage`, then fire it with `Send-MgUserMessage`
- **Token management** via MSAL -- handle token refresh, expiry, and caching yourself
- **Nested hashtables** for message body, recipients, and attachments

That's 6 steps and roughly 20 lines of PowerShell just to send one email. The basic send example below shows the full cost.

## One-time setup

Run `irm https://cli.nylas.com/install.ps1 | iex` on Windows or `brew install nylas/nylas-cli/nylas` on macOS/Linux ([all methods](https://cli.nylas.com/guides/getting-started)). No Azure AD apps, no Graph permissions, no MSAL tokens -- the whole point is skipping that.

```powershell
# Authenticate (one-time)
nylas auth config
# Paste your API key from dashboard-v3.nylas.com

# Verify
nylas auth whoami
# => Authenticated as you@company.com (Microsoft 365)
```

That's it. No app registration, no permission grants, no `Connect-MgGraph`.

## Pattern 1: Basic email send

### Before (Graph PowerShell)

```powershell
# Connect to Microsoft Graph
Connect-MgGraph -Scopes "Mail.Send"

# Build the message body as a nested hashtable
$message = @{
  Subject = "Quarterly report"
  Body = @{
    ContentType = "Text"
    Content = "Please review the Q4 numbers."
  }
  ToRecipients = @(
    @{ EmailAddress = @{ Address = "colleague@company.com" } }
  )
}

# Create the draft, then send it
$draft = New-MgUserMessage -UserId "you@company.com" -BodyParameter $message
Send-MgUserMessage -UserId "you@company.com" -MessageId $draft.Id
```

### After (Nylas CLI)

```powershell
nylas email send `
  --to "colleague@company.com" `
  --subject "Quarterly report" `
  --body "Please review the Q4 numbers." `
  --yes
```

Four lines instead of fifteen. No hashtables, no two-step workflow, no user ID parameter.

## Pattern 2: Send with attachment

### Before (Graph PowerShell)

```powershell
Connect-MgGraph -Scopes "Mail.Send"

# Read and base64-encode the file
$fileBytes = [System.IO.File]::ReadAllBytes("C:\Reports\invoice-march.pdf")
$base64 = [System.Convert]::ToBase64String($fileBytes)

$message = @{
  Subject = "Invoice attached"
  Body = @{
    ContentType = "Text"
    Content = "Please find the March invoice."
  }
  ToRecipients = @(
    @{ EmailAddress = @{ Address = "client@example.com" } }
  )
  Attachments = @(
    @{
      "@odata.type" = "#microsoft.graph.fileAttachment"
      Name = "invoice-march.pdf"
      ContentType = "application/pdf"
      ContentBytes = $base64
    }
  )
}

$draft = New-MgUserMessage -UserId "you@company.com" -BodyParameter $message
Send-MgUserMessage -UserId "you@company.com" -MessageId $draft.Id
```

### After (Nylas CLI)

```powershell
nylas email send `
  --to "client@example.com" `
  --subject "Invoice attached" `
  --body "Please find the March invoice." `
  --attach "C:\Reports\invoice-march.pdf" `
  --yes
```

No base64 encoding, no `@odata.type` annotations, no content type guessing. The CLI handles file reading and MIME detection automatically.

## Pattern 3: HTML email

### Before (Graph PowerShell)

```powershell
Connect-MgGraph -Scopes "Mail.Send"

$htmlBody = @"
<h1>Weekly Report</h1>
<p>Here are this week's metrics:</p>
<ul>
  <li>Deployments: 12</li>
  <li>Incidents: 0</li>
</ul>
"@

$message = @{
  Subject = "Weekly report"
  Body = @{
    ContentType = "HTML"
    Content = $htmlBody
  }
  ToRecipients = @(
    @{ EmailAddress = @{ Address = "team@company.com" } }
  )
}

$draft = New-MgUserMessage -UserId "you@company.com" -BodyParameter $message
Send-MgUserMessage -UserId "you@company.com" -MessageId $draft.Id
```

### After (Nylas CLI)

```powershell
$htmlBody = @"
<h1>Weekly Report</h1>
<p>Here are this week's metrics:</p>
<ul>
  <li>Deployments: 12</li>
  <li>Incidents: 0</li>
</ul>
"@

nylas email send `
  --to "team@company.com" `
  --subject "Weekly report" `
  --body $htmlBody `
  --yes
```

No `ContentType = "HTML"` required. The CLI auto-detects HTML content and sets the correct MIME type.

## Pattern 4: Send on behalf of / shared mailbox

### Before (Graph PowerShell)

```powershell
# Requires Mail.Send.Shared permission in Azure AD
Connect-MgGraph -Scopes "Mail.Send.Shared"

$message = @{
  Subject = "Team update"
  Body = @{
    ContentType = "Text"
    Content = "This week's progress summary."
  }
  ToRecipients = @(
    @{ EmailAddress = @{ Address = "stakeholders@company.com" } }
  )
}

# Send as the shared mailbox by specifying its UserId
$draft = New-MgUserMessage -UserId "shared-inbox@company.com" -BodyParameter $message
Send-MgUserMessage -UserId "shared-inbox@company.com" -MessageId $draft.Id
```

### After (Nylas CLI)

```powershell
# Use a different grant connected to the shared mailbox
nylas email send `
  --to "stakeholders@company.com" `
  --subject "Team update" `
  --body "This week's progress summary." `
  --grant-id <shared-mailbox-grant-id> `
  --yes
```

No extra Graph permissions needed. Connect the shared mailbox as a separate grant, then reference it with `--grant-id`.

## Side-by-side comparison

| Feature | Graph PowerShell | Nylas CLI |
| --- | --- | --- |
| Authentication | Azure AD app + Connect-MgGraph + MSAL | One-time `nylas auth config` |
| Setup steps | Register app, grant permissions, admin consent | Install + authenticate |
| Send workflow | Two-step: New-MgUserMessage then Send-MgUserMessage | Single command: `nylas email send` |
| Attachments | Base64-encode, annotate @odata.type | `--attach file.pdf` |
| HTML body | Set ContentType = "HTML" in hashtable | Auto-detected |
| Shared mailbox | Mail.Send.Shared permission + -UserId | `--grant-id` |
| Email scheduling | Not supported natively | `--schedule` |
| Read inbox | Get-MgUserMessage (separate cmdlet) | `nylas email list` |
| Cross-provider | Microsoft only | Gmail, Outlook, Exchange, Yahoo, iCloud, IMAP |
| Token management | Manual (MSAL refresh, caching) | Automatic |

## Frequently asked questions

### What is Send-MgUserMessage?

`Send-MgUserMessage` is a Microsoft Graph PowerShell cmdlet that sends an existing draft message. It's part of the `Microsoft.Graph.Mail` module and replaced the deprecated `Send-MailMessage`. The cmdlet requires Azure AD app registration with `Mail.Send` permission and a two-step workflow: create a draft with `New-MgUserMessage`, then send it.

### Why does Send-MgUserMessage need Azure AD app registration?

The cmdlet calls the Microsoft Graph API under the hood. Graph API access requires an Azure AD app registration with the correct permissions. You register the app in portal.azure.com, configure `Mail.Send` as a delegated or application permission, and get admin consent before sending any email.

### Can I use Nylas CLI with Microsoft 365?

Yes. The CLI works with Microsoft 365, Exchange Online, and every other major provider. It handles OAuth2 token management and Graph API authentication automatically, so you don't need to register Azure AD apps or manage permissions yourself.

### Does Nylas CLI work with Graph API permissions?

The CLI abstracts away Graph API permissions entirely. Instead of configuring `Mail.Send`, `Mail.ReadWrite`, or other Microsoft Graph scopes, you authenticate once with `nylas auth config`. It manages provider-specific authorization for Gmail, Outlook, Exchange, Yahoo, iCloud, and IMAP.

## Next steps

- [Replace Send-MailMessage](https://cli.nylas.com/guides/replace-send-mailmessage) -- migrating from the older deprecated cmdlet instead?
- [Manage Office 365 email from PowerShell](https://cli.nylas.com/guides/office365-email-powershell) -- read, search, and organize your Microsoft 365 inbox
- [Send email from PowerShell](https://cli.nylas.com/guides/send-email-powershell) -- advanced patterns, scheduling, and scripting
- [Read and search email in PowerShell](https://cli.nylas.com/guides/read-email-powershell) -- list unread, search by sender, export to CSV
- [Download email attachments in PowerShell](https://cli.nylas.com/guides/download-attachments-powershell) -- filter by type, batch download, rename
- [Full command reference](https://cli.nylas.com/docs/commands) -- every flag and subcommand documented
