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

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

After (Nylas CLI)

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)

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)

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)

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)

$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)

# 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)

# 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

FeatureGraph PowerShellNylas CLI
AuthenticationAzure AD app + Connect-MgGraph + MSALOne-time nylas auth config
Setup stepsRegister app, grant permissions, admin consentInstall + authenticate
Send workflowTwo-step: New-MgUserMessage then Send-MgUserMessageSingle command: nylas email send
AttachmentsBase64-encode, annotate @odata.type--attach file.pdf
HTML bodySet ContentType = "HTML" in hashtableAuto-detected
Shared mailboxMail.Send.Shared permission + -UserId--grant-id
Email schedulingNot supported natively--schedule
Read inboxGet-MgUserMessage (separate cmdlet)nylas email list
Cross-providerMicrosoft onlyGmail, Outlook, Exchange, Yahoo, iCloud, IMAP
Token managementManual (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