Source: https://cli.nylas.com/guides/send-outlook-email-cli

# Send Outlook Email from the CLI

Microsoft retired Basic Auth for Exchange Online in October 2022 and has scheduled EWS retirement for October 2026, leaving Microsoft Graph as the supported send path — the same Graph that Outlook scripts often only need for one-off send calls. This guide covers send, attach, schedule, and shared-mailbox flows from the terminal without standing up an Azure AD app for each one.

Written by [Caleb Geene](https://cli.nylas.com/authors/caleb-geene) Director, Site Reliability Engineering

Reviewed by [Hazik](https://cli.nylas.com/authors/hazik)

Updated May 2, 2026

> **TL;DR:** Install Nylas CLI (`brew install nylas/nylas-cli/nylas`), authenticate once, then send with `nylas email send --to user@example.com`. Works with Outlook, M365, Gmail, Exchange, Yahoo, iCloud, and IMAP. No Graph API, no SMTP config.

## The problem with sending Outlook email programmatically

Microsoft's recommended way to send email from Outlook is the [Graph API /sendMail endpoint](https://learn.microsoft.com/en-us/graph/api/user-sendmail). That means registering an app in Azure AD, configuring `Mail.Send` permissions, getting admin consent, and handling MSAL token acquisition and refresh. According to [Microsoft's OAuth 2.0 documentation](https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-auth-code-flow), access tokens expire after 60-90 minutes and require refresh token rotation.

For a quick send from your terminal or a shell script, that's too much setup. SMTP via `smtp.office365.com` on port 587 still works, but [Microsoft retired Basic Auth for Exchange Online in October 2022](https://learn.microsoft.com/en-us/exchange/clients-and-mobile-in-exchange-online/deprecation-of-basic-authentication-exchange-online). You can't use username/password anymore.

Nylas CLI bypasses all of this. It talks to the Nylas API, which handles OAuth2 token refresh, provider routing, and connection management. Authenticate once, then send with one command.

## 1. Install

Run `brew install nylas/nylas-cli/nylas` ([other methods](https://cli.nylas.com/guides/getting-started)). On Windows, use `irm https://cli.nylas.com/install.ps1 | iex` since most Outlook users are on Windows.

## 2. Authenticate your Outlook account

Go to [dashboard-v3.nylas.com](https://dashboard-v3.nylas.com/), create an application, and connect your Outlook or M365 mailbox. Then grab your API key:

```bash
nylas auth config
# Paste your API key when prompted

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

Credentials are stored in your system keyring. You won't need to re-authenticate unless you revoke the grant.

## 3. Send from a user mailbox, alias, or shared mailbox

This is the first place Outlook differs from the generic terminal guide. Microsoft 365 teams frequently send from role accounts, shared mailboxes, and department identities. The key question is not just "can I send a message?" It is "which mailbox identity should this message come from?"

```bash
# Send from your own Outlook mailbox
nylas email send \
  --to "colleague@company.com" \
  --subject "Q2 planning doc" \
  --body "Hi — the planning doc is ready for review." \
  --yes

# Send from a shared mailbox grant
nylas email send <shared-mailbox-grant-id> \
  --to "vendor@partner.com" \
  --subject "PO #4521" \
  --body "Purchase order attached." \
  --attach ./po-4521.pdf \
  --yes
```

If `send-as` or shared mailbox rights are wrong, Microsoft 365 rejects the send even though the command syntax is fine. That is an Exchange Online policy issue, not a shell issue.

## 4. Distribution lists, aliases, and team queues

Outlook distribution lists, M365 groups, recruiting inboxes, support queues, and finance aliases are common enterprise workflows. The generic terminal page does not need to spend much time there; the Outlook page does.

```bash
# Send to a distribution list
nylas email send \
  --to "engineering-all@company.com" \
  --subject "Deployment window tonight" \
  --body "Production deploy starts at 22:00 UTC. Freeze all PRs by 21:00." \
  --yes

# Include compliance or archive recipients
nylas email send \
  --to "contracts@company.com" \
  --cc "legal@company.com" \
  --bcc "compliance@company.com" \
  --subject "Contract update" \
  --body "Updated terms attached." \
  --attach ./contract-v3.pdf \
  --yes
```

## 5. HTML, attachments, and business workflow email

Outlook mail often carries invoices, approvals, statements of work, or procurement documents. That is different from the shell-centric here-doc examples in the generic command-line guide.

```bash
nylas email send \
  --to "client@example.com" \
  --subject "Invoice #1042" \
  --html "<h1>Invoice #1042</h1><p>Amount due: <strong>$2,400.00</strong></p><p>Payment link: <a href='https://pay.example.com/1042'>pay.example.com/1042</a></p>" \
  --attach ./invoice-1042.pdf \
  --yes
```

Outlook and M365 accounts support attachments up to 25 MB per message. The CLI auto-detects MIME type, while tenant DLP or transport rules still apply after the send.

## 6. Schedule delivery and respect Microsoft 365 limits

Outlook automation is also more likely to run into tenant sending limits than the consumer-provider pages. Microsoft 365 enforces per-minute and per-day sending caps, so scheduled or bulk workflows should pace themselves deliberately.

```bash
# Schedule a follow-up
nylas email send \
  --to "client@example.com" \
  --subject "Follow-up" \
  --body "Checking in on the proposal." \
  --schedule "tomorrow 9am" \
  --yes

# Rate-limit a mailbox automation loop
while read -r recipient; do
  nylas email send --to "$recipient" --subject "Status update" --body "See attached notes." --yes
  sleep 2
done < recipients.txt
```

## 7. JSON output for scripting and audit trails

Add `--json` to capture the exact message object, message ID, and mailbox context for logs, queue processors, or compliance-sensitive workflows:

```bash
nylas email send \
  --to "user@example.com" \
  --subject "Test" \
  --body "Hello." \
  --json --yes
```

```json
{
  "id": "a1b2c3d4e5f6g7h8",
  "grant_id": "d3f4a5b6-c7d8-9e0f-a1b2-c3d4e5f6g7h8",
  "thread_id": "x9y8z7w6v5u4t3s2",
  "subject": "Test",
  "from": [{"name": "Dev User", "email": "dev@company.com"}],
  "to": [{"name": "", "email": "user@example.com"}],
  "date": "2026-03-28T10:30:00-04:00",
  "object": "message"
}
```

Use this in shell scripts to capture the message ID, verify delivery, or log sends:

```bash
# Capture the message ID after sending
msg_id=$(nylas email send \
  --to "user@example.com" \
  --subject "Automated" \
  --body "This is automated." \
  --json --yes | jq -r '.id')

echo "Sent message: $msg_id"
```

## Graph API vs. Nylas CLI

Here's what sending an Outlook email looks like with Graph API versus Nylas CLI:

| Step | Graph API | Nylas CLI |
| --- | --- | --- |
| App registration | Azure AD portal, configure redirect URIs | Not needed |
| Permissions | Add Mail.Send, get admin consent | Not needed |
| Authentication | MSAL library, acquire tokens, handle refresh | `nylas auth config` (once) |
| Send email | POST to /me/sendMail with JSON body | `nylas email send --to...` |
| Attachments | Base64-encode in JSON, upload session for >3 MB | `--attach./file.pdf` |
| Token refresh | Handle 401, rotate refresh tokens | Automatic |
| Multi-provider | Microsoft only | Gmail, Outlook, Exchange, Yahoo, iCloud, IMAP |
| Lines of code | 50-100+ (Python/Node with MSAL) | 1 command |

## Outlook-specific tips

### Read receipts

Outlook supports read receipt requests via the `Disposition-Notification-To` header. When you send through Nylas CLI, the recipient's Outlook client may prompt them to send a read receipt depending on their settings.

### Sensitivity labels

M365 sensitivity labels (Confidential, Internal, etc.) are applied at the tenant level by Microsoft Information Protection. Messages sent through Nylas CLI respect your tenant's default labeling policy. If your org requires a specific label, your Exchange admin can set auto-labeling rules that apply to all outbound email.

### Shared mailbox sending

To send from a shared mailbox, connect it as a separate grant:

```bash
# Connect the shared mailbox
nylas auth login
# Follow the OAuth flow for the shared mailbox

# Send from the shared mailbox using its grant ID
nylas email send <shared-mailbox-grant-id> \
  --to "vendor@partner.com" \
  --subject "PO #4521" \
  --body "Purchase order attached." \
  --attach ./po-4521.pdf
```

### Outlook sending limits

Microsoft 365 enforces a limit of 10,000 recipients per day and 30 messages per minute for most plans. According to [Microsoft's Exchange Online limits documentation](https://learn.microsoft.com/en-us/office365/servicedescriptions/exchange-online-service-description/exchange-online-limits#receiving-and-sending-limits), exceeding these triggers a temporary block. For bulk sends, add a `sleep 2` between messages in your script.

### Transport rules, journaling, and send-as policy

Outlook and Microsoft 365 mail flows are often shaped by tenant-wide Exchange Online rules long before a message reaches the recipient. Transport rules, journaling, DLP, quarantine policies, and send-as permissions can all change delivery outcomes even when the send command succeeds. That is a Microsoft-specific operational concern that the Yahoo and iCloud send guides simply do not have.

If an Outlook send behaves differently across two mailboxes, the cause is often mailbox policy or tenant routing policy, not the body or attachment syntax.

### Shared mailbox and team queue workflows

Outlook teams also use shared mailboxes for procurement, support, recruiting, and executive operations far more than consumer providers do. Sending from `support@company.com` or `ap@company.com` is a normal Microsoft 365 workflow, not an edge case. That is why this page goes deeper on grants, shared identities, and organization-owned senders than the generic terminal guide.

## Next steps

- [Send email from terminal](https://cli.nylas.com/guides/send-email-from-terminal) — cross-provider guide covering Linux, macOS, and Windows
- [List Outlook emails from terminal](https://cli.nylas.com/guides/list-outlook-emails) — read, search, and filter your Outlook inbox
- [Manage Outlook calendar from CLI](https://cli.nylas.com/guides/manage-outlook-calendar-cli) — create events, check availability, schedule meetings
- [Give AI agents email access via MCP](https://cli.nylas.com/guides/ai-agent-email-mcp) — connect Claude, Cursor, or VS Code to your Outlook inbox
- [Full command reference](https://cli.nylas.com/docs/commands) — every flag and subcommand documented
