Guide

iCloud Mail CLI: Send Email from Terminal

Use an iCloud Mail CLI to send email from terminal without SMTP config or app passwords. iCloud Mail has one programmatic entry point: SMTP on smtp.mail.me.com:587, guarded by an app-specific password. This guide covers terminal sends, HTML bodies, CC/BCC, scheduling, and iCloud-specific limits without that setup.

Written by Qasim Muhammad Staff SRE

Reviewed by Nick Barraclough

VerifiedCLI 3.1.1 · iCloud · last tested April 11, 2026

How do you use an iCloud Mail CLI to send email from terminal?

Connect iCloud Mail once, then send with nylas email send --to user@example.com --subject "Hello" --body "Hi" --yes. This gives you an iCloud Mail CLI send workflow without direct SMTP setup, app-specific passwords, or per-script Apple credential storage.

iCloud Mail is awkward to send from the terminal because Apple exposes SMTP instead of a public mail API.

Apple requires an app-specific password for any third-party access to iCloud Mail, 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. 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 connected iCloud mailbox through the same command surface used for Gmail, Outlook, Yahoo, and IMAP.

1. Install the Nylas CLI

The Nylas CLI is a single binary under 30 MB that installs in one command on macOS, Linux, and Windows. Homebrew is the fastest method — it resolves the correct architecture automatically and places the binary on your PATH. This one-liner pulls the latest stable release from the nylas/nylas-cli tap.

brew install nylas/nylas-cli/nylas

For shell script, PowerShell, and go install options, see the getting started guide.

2. Authenticate your iCloud account

Authentication connects your iCloud mailbox to the Nylas CLI through an OAuth flow that replaces Apple's 16-character app-specific passwords with managed tokens. The entire process takes under 2 minutes: create a Nylas application, connect the mailbox, and store the API key locally. After that single setup, the CLI handles token refresh automatically.

Create a Nylas application at dashboard-v3.nylas.com, connect your iCloud mailbox, and copy the API key. The nylas auth config command stores the key in your system keyring, while nylas auth whoami confirms the connection.

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

The key lands in your system keyring — not in dotfiles, environment variables, or plaintext config files.

3. Send: basic, HTML, CC/BCC

The nylas email send command uses the same flags for iCloud as it does for Gmail, Outlook, or any other connected provider. One command handles plain text, HTML bodies through --body, and CC/BCC routing. The --yes flag skips the interactive confirmation prompt, which is required for scripts and CI/CD pipelines.

These 3 examples show the most common send patterns: plain text, HTML, and CC/BCC. For full flag documentation, see the send email from the command line guide.

# 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" \
  --body "<h1>This Week</h1><p>Here's what happened.</p>" \
  --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 when you send through Apple clients. Apple's Mail Drop absorbs files up to 5 GB, but it runs only in Apple Mail and at iCloud.com. It isn't exposed through SMTP or any public API, so terminal workflows should upload large files elsewhere and send a link in the body.

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

iCloud+ subscribers can configure up to 5 custom domains and an unlimited number of Hide My Email relay addresses in Apple's account settings. An iCloud+ plan starts at $0.99/month for the 50 GB tier. The current CLI send command does not expose a --from override, so connect and verify the mailbox identity you intend to send from before automating a workflow.

# Send from the connected iCloud mailbox identity
nylas email send \
  --to client@example.com \
  --subject "Invoice #1042" \
  --body "Invoice #1042 is ready: <invoice-download-link>" \
  --yes

# Confirm the active mailbox before scripts run
nylas auth whoami

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:

RecordPurposeValue Apple provides
MXRoute inbound mail to iCloudmx01.mail.icloud.com and mx02.mail.icloud.com (priority 10)
TXT (SPF)Authorize Apple to send on your behalfv=spf1 include:icloud.com ~all
TXT (DKIM)Sign outbound messagesUnique 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

The --json flag returns structured JSON from any Nylas CLI command, replacing the default human-readable output. The response includes the message ID, thread ID, send timestamp, and a list of recipients — typically 8-12 fields per message. JSON output is useful when piping into jq for extraction, logging send results to a file, or feeding message IDs into downstream automation.

This example sends an email and extracts only the message ID from the JSON response. The same pattern works with nylas email list --json and nylas email get --json.

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

iCloud SMTP vs the CLI

The traditional iCloud SMTP path requires 4 manual steps before sending a single message: enabling 2FA, generating an app-specific password, configuring the SMTP host and port, and storing the password securely. The Nylas CLI reduces that to 1 step — authenticating once with an API key. There are 8 capability differences between the two approaches, from token refresh to JSON output support.

StepiCloud SMTPNylas CLI
Enable 2FA on Apple IDRequiredHandled by the Nylas OAuth flow
Generate app-specific passwordRequired per scriptNot used
SMTP host/portsmtp.mail.me.com:587 (STARTTLS)Not exposed
Token refreshNo (static password)Automatic
Custom domain sendingPer-domain SMTP configUse the connected sender identity; no CLI --from override
Hide My Email sendNot possible via SMTPUse Apple-managed relay workflows outside CLI send
Scheduled deliveryNot supported--schedule flag
JSON outputNot supported--json flag

Apple-specific sending details

iCloud Mail enforces account-level limits on outbound messages, custom domains, and Hide My Email relays that don't apply to other email providers. Apple publishes some of these limits in its iCloud system requirements documentation, but others — like short-burst throttling — are undocumented. There are 4 key constraints that affect CLI-based sending workflows: daily message caps, Hide My Email address limits, custom domain caps, and Mail Drop unavailability.

Daily sending limits

Apple's iCloud system requirements 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 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

iCloud Mail errors fall into 5 common categories: DNS verification failures for custom domains, outbound content filtering (SMTP 550 rejections), daily volume cap hits at 1,000 messages, OAuth consent problems during initial setup, and Hide My Email relay bounces from deactivated addresses. Each error includes the exact error message or symptom and a specific fix.

"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

With iCloud sending working, you can extend the CLI to read your inbox, manage calendars, or connect your mailbox to AI agents. The Nylas CLI supports 6 email providers through the same command set, so the patterns from this iCloud workflow transfer directly to Gmail, Outlook, Yahoo, Exchange, and IMAP accounts.