Guide
Replace Send-MgUserMessage with Nylas CLI
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.
By Prem Keshari
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, 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 withSend-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
Install Nylas CLI and authenticate once. No Azure AD apps, no Graph permissions, no MSAL tokens.
# Install Nylas CLI (one-liner for PowerShell)
irm https://cli.nylas.com/install.ps1 | iex
# Or install with Homebrew on macOS/Linux
# brew install nylas/nylas-cli/nylas# 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)
# 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.IdAfter (Nylas CLI)
nylas email send `
--to "colleague@company.com" `
--subject "Quarterly report" `
--body "Please review the Q4 numbers." `
--yesFour lines instead of fifteen. No hashtables, no two-step workflow, no user ID parameter.
Pattern 2: Send with attachment
Before (Graph 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.IdAfter (Nylas CLI)
nylas email send `
--to "client@example.com" `
--subject "Invoice attached" `
--body "Please find the March invoice." `
--attach "C:\Reports\invoice-march.pdf" `
--yesNo 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)
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.IdAfter (Nylas CLI)
$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 `
--yesNo 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)
# 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.IdAfter (Nylas CLI)
# 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> `
--yesNo 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 with Nylas CLI -- migrating from the older deprecated cmdlet instead?
- Manage Office 365 email from PowerShell -- read, search, and organize your Microsoft 365 inbox
- Send email from PowerShell -- advanced patterns, scheduling, and scripting
- Full command reference -- every flag and subcommand documented