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

# Send iCloud Mail from the CLI

iCloud Mail has one programmatic entry point: SMTP on smtp.mail.me.com:587, guarded by an app-specific password. This guide covers sending from @icloud.com, iCloud+ custom domains, and Hide My Email relays without that setup.

Written by [Qasim Muhammad](https://cli.nylas.com/authors/qasim-muhammad) Staff SRE

Reviewed by [Nick Barraclough](https://cli.nylas.com/authors/nick-barraclough)

Updated May 2, 2026

> **TL;DR:** Install the CLI (`brew install nylas/nylas-cli/nylas`), authenticate once, then send with `nylas email send --to user@example.com`. No app-specific passwords, no SMTP config.

## Why iCloud Mail is awkward to send from the terminal

Apple requires an app-specific password for any third-party access to [iCloud Mail](https://support.apple.com/en-us/102525), a policy bundled with mandatory two-factor authentication on Apple IDs. The only programmatic route is SMTP on `smtp.mail.me.com:587`, protected by one of those passwords generated at [appleid.apple.com](https://appleid.apple.com/account/manage). Reset the Apple ID password or revoke the app-specific password and every script breaks at once.

The static-password model makes multi-account work painful. Each Apple ID needs its own 16-character password stored somewhere in plaintext. There's no refresh, no scope, and no rotation that doesn't force you to touch every downstream consumer.

The CLI talks to the Nylas API instead. Nylas handles the iCloud auth dance, manages refresh tokens, and pools connections. You authenticate once and sends work from the primary mailbox, iCloud+ custom domains, and Hide My Email relays through the same command.

## 1. Install

```bash
brew install nylas/nylas-cli/nylas
```

For shell script, PowerShell, and `go install` options, see the [getting started guide](https://cli.nylas.com/guides/getting-started).

## 2. Authenticate your iCloud account

Create a Nylas application at [dashboard-v3.nylas.com](https://dashboard-v3.nylas.com/), connect your iCloud mailbox, and copy the API key. Then:

```bash
nylas auth config
# paste API key when prompted
nylas auth whoami
# => Authenticated as you@icloud.com (iCloud)
```

The key lands in your system keyring. No plaintext credentials sit in your dotfiles or environment.

## 3. Send: basic, HTML, attachments, CC/BCC

The `nylas email send` command behaves the same across providers. See [send email from the command line](https://cli.nylas.com/guides/send-email-from-terminal) for full flag documentation. The short version:

```bash
# Basic send (use --yes in scripts to skip the confirmation prompt)
nylas email send \
  --to friend@example.com \
  --subject "Quick update" \
  --body "Hey, just wanted to share this link." \
  --yes

# HTML body
nylas email send --to subscriber@example.com \
  --subject "Weekly digest" \
  --html "<h1>This Week</h1><p>Here's what happened.</p>" \
  --yes

# Attachments (repeat --attach for multiple files)
nylas email send --to team@company.com \
  --subject "March report" \
  --body "Attached is the report." \
  --attach ./march-report.pdf --attach ./appendix.xlsx \
  --yes

# CC and BCC
nylas email send --to alice@team.com \
  --cc bob@team.com --bcc manager@team.com \
  --subject "Project status" \
  --body "All tasks on track for Friday." \
  --yes
```

iCloud Mail caps attachments at 20 MB per message. Apple's Mail Drop (which absorbs files up to 5 GB) runs only in Apple Mail and at iCloud.com. It isn't exposed through SMTP or any public API, so it isn't available from the terminal either.

## 4. Send from a custom domain or Hide My Email alias

This is the iCloud-specific feature that matters most. An iCloud+ subscription (starting at $0.99/month for the 50 GB tier) unlocks up to 5 custom email domains and unlimited Hide My Email relay addresses. Once a domain is verified in iCloud settings, you can send from any address on it with `--from`:

```bash
# Send from your custom domain
nylas email send \
  --to client@example.com \
  --from hello@yourdomain.com \
  --subject "Invoice #1042" \
  --body "Please find your invoice attached." \
  --attach ./invoice-1042.pdf \
  --yes

# Send from a Hide My Email relay
nylas email send \
  --to newsletter@service.com \
  --from abc123@privaterelay.appleid.com \
  --subject "Unsubscribe" \
  --body "Please remove me from your list." \
  --yes
```

Hide My Email relays forward incoming mail to your real inbox; recipients only see the relay address. The same mechanism powers Sign in with Apple's private relay.

### Custom domain DNS setup

Before a domain can send, Apple requires three DNS records at your registrar. From [Apple's iCloud custom domain docs](https://support.apple.com/guide/icloud/set-up-a-custom-email-domain-mm9ac9480988/icloud):

| Record | Purpose | Value Apple provides |
| --- | --- | --- |
| MX | Route inbound mail to iCloud | `mx01.mail.icloud.com` and `mx02.mail.icloud.com` (priority 10) |
| TXT (SPF) | Authorize Apple to send on your behalf | `v=spf1 include:icloud.com ~all` |
| TXT (DKIM) | Sign outbound messages | Unique per domain; Apple generates when you add the domain |

Propagation usually finishes inside an hour but Apple can take up to 72 hours to verify. The CLI surfaces a clean "sender domain not verified" error until verification completes, so it's safe to queue sends before DNS finishes propagating.

## 5. JSON output for scripting

Add `--json` to any command for structured output. Useful when piping into `jq`, logging, or feeding another process.

```bash
nylas email send --to user@example.com \
  --subject "Automated alert" \
  --body "Build failed: see logs." \
  --yes --json | jq '.id'
```

---

## iCloud SMTP vs the CLI

| Step | iCloud SMTP | Nylas CLI |
| --- | --- | --- |
| Enable 2FA on Apple ID | Required | Handled by the Nylas OAuth flow |
| Generate app-specific password | Required per script | Not used |
| SMTP host/port | smtp.mail.me.com:587 (STARTTLS) | Not exposed |
| Token refresh | No (static password) | Automatic |
| Custom domain sending | Per-domain SMTP config | `--from` flag |
| Hide My Email send | Not possible via SMTP | `--from` flag |
| Scheduled delivery | Not supported | `--schedule` flag |
| JSON output | Not supported | `--json` flag |

## Apple-specific sending details

### Daily sending limits

Apple's [iCloud system requirements](https://support.apple.com/en-us/102149) page caps iCloud Mail at 1,000 outbound messages per day and 500 recipients per message (To + CC + BCC combined). The 24-hour window is rolling, not a calendar-day reset. Apple doesn't publish the short-burst throttle, so sustained bursts can trigger temporary delays before you hit the daily cap.

### Hide My Email limits

Paid iCloud+ plans get unlimited Hide My Email addresses. Generate them from Settings > Apple ID > iCloud > Hide My Email on iOS, or from [icloud.com/settings](https://www.icloud.com/settings/) on the web. Once a relay is deactivated, new mail to that address stops forwarding.

### Custom domain caps

iCloud+ permits 5 custom domains per account. Custom domains are included with iCloud+ features that can be shared through Family Sharing. If DNS records change after verification, Apple suspends outbound sending on that domain until the records match again.

### Why Mail Drop doesn't work from the terminal

Apple's Mail Drop uploads attachments over 20 MB to iCloud servers and sends a download link instead of the file. The feature is bolted onto Apple Mail and the iCloud.com web client; it isn't exposed through SMTP or any public API. For large files from the terminal, upload to a shareable location and send the link in the body.

## Troubleshooting iCloud sends

### "Sender domain not verified" on custom-domain sends

Apple won't let a custom domain send until its MX, SPF, and DKIM records are all visible at the authoritative nameservers. Check propagation with `dig MX yourdomain.com +short` and `dig TXT yourdomain.com +short`. If the records look right but Apple still rejects, wait. Apple re-checks DNS periodically, and verification can take up to 72 hours.

### "550 5.7.1 Message rejected due to local policy"

iCloud's outbound filter flagged the message. Common causes: the body contains URL shorteners (`bit.ly`, `tinyurl`), the subject is a single word, or the message went to a large BCC list with identical body text. Rewrite the body with the real destination URL and break up large BCC runs.

### Sending suddenly stops after a batch run

You've tripped the 1,000-message daily cap. The block lasts 24 hours from the 1,001st message, not from midnight Pacific. For higher throughput, connect a second iCloud+ account or move bulk email to a dedicated transactional provider. iCloud Mail isn't designed for campaign traffic.

### OAuth consent loop during the initial mailbox connection

If Apple's consent screen shows "Something went wrong" while connecting the mailbox in the Nylas dashboard, the Apple ID likely has a pending 2FA trust prompt on another device. Open Settings > Apple ID on any signed-in device, accept any pending prompts, then retry the mailbox connection.

### Replies to a Hide My Email send bounce back

If replies are bouncing, check Settings > Apple ID > iCloud > Hide My Email and confirm the address isn't set to "Deactivate". The UI shows deactivated addresses greyed out but still lists them, so it's easy to miss that a relay was turned off earlier.

## Next steps

- [Send email from the command line](https://cli.nylas.com/guides/send-email-from-terminal) -- the general guide covering all providers
- [List iCloud emails from terminal](https://cli.nylas.com/guides/list-icloud-emails) -- read and search your iCloud inbox
- [Manage iCloud calendar from the CLI](https://cli.nylas.com/guides/manage-icloud-calendar-cli) -- events, reminders, and scheduling
- [Give AI agents email access via MCP](https://cli.nylas.com/guides/ai-agent-email-mcp) -- connect Claude, Cursor, or VS Code to your mailbox
- [Full command reference](https://cli.nylas.com/docs/commands) -- every flag and subcommand documented
