agent-workflows: workspace-context-organization autonomous-ai-agents: hermes-agent computer-use devops: hermes-config-bulk-update, hermes-profile-management, holographic-memory, telegram-integration, webhook-subscriptions email: himalaya mcp: native-mcp, searxng-smart-search media: voice-systems, youtube-content mlops: local-vector-memory, qdrant-collection-management productivity: maps, notion, ocr-and-documents project-knowledge-base research: arxiv, blogwatcher, ecosystem-surveillance save-agents-md social-media: social-media-scraping, xurl software-development: agent-self-audit, simplify-code, spike, subagent-driven-development, systematic-debugging, test-driven-development, writing-plans user-response-style
385 lines
10 KiB
Markdown
385 lines
10 KiB
Markdown
---
|
|
name: himalaya
|
|
description: "Himalaya CLI: IMAP/SMTP email from terminal."
|
|
version: 1.1.0
|
|
author: community
|
|
license: MIT
|
|
platforms: [linux, macos, windows]
|
|
metadata:
|
|
hermes:
|
|
tags: [Email, IMAP, SMTP, CLI, Communication]
|
|
homepage: https://github.com/pimalaya/himalaya
|
|
prerequisites:
|
|
commands: [himalaya]
|
|
---
|
|
|
|
# Himalaya Email CLI
|
|
|
|
Himalaya is a CLI email client that lets you manage emails from the terminal using IMAP, SMTP, Notmuch, or Sendmail backends.
|
|
|
|
This skill is separate from the Hermes Email gateway adapter. The gateway
|
|
adapter lets people email the agent and uses Hermes' built-in IMAP/SMTP
|
|
adapter; this skill lets the agent operate a mailbox from terminal tools and
|
|
requires the external `himalaya` CLI.
|
|
|
|
## References
|
|
|
|
- `references/configuration.md` (config file setup + IMAP/SMTP authentication)
|
|
- `references/message-composition.md` (MML syntax for composing emails)
|
|
- `references/attachment-extraction.md` (Python recipe for extracting attachments from .eml files)
|
|
|
|
## Scripts
|
|
|
|
- `scripts/bulk-export.py` (multi-folder bulk export with folder-relative ID handling)
|
|
|
|
## Prerequisites
|
|
|
|
1. Himalaya CLI installed (`himalaya --version` to verify)
|
|
2. A configuration file at `~/.config/himalaya/config.toml`
|
|
3. IMAP/SMTP credentials configured (password stored securely)
|
|
|
|
### Installation
|
|
|
|
```bash
|
|
# Pre-built binary (Linux/macOS — recommended)
|
|
curl -sSL https://raw.githubusercontent.com/pimalaya/himalaya/master/install.sh | PREFIX=~/.local sh
|
|
|
|
# macOS via Homebrew
|
|
brew install himalaya
|
|
|
|
# Or via cargo (any platform with Rust)
|
|
cargo install himalaya --locked
|
|
```
|
|
|
|
## Configuration Setup
|
|
|
|
Run the interactive wizard to set up an account:
|
|
|
|
```bash
|
|
himalaya account configure
|
|
```
|
|
|
|
Or create `~/.config/himalaya/config.toml` manually:
|
|
|
|
```toml
|
|
[accounts.personal]
|
|
email = "you@example.com"
|
|
display-name = "Your Name"
|
|
default = true
|
|
|
|
backend.type = "imap"
|
|
backend.host = "imap.example.com"
|
|
backend.port = 993
|
|
backend.encryption.type = "tls"
|
|
backend.login = "you@example.com"
|
|
backend.auth.type = "password"
|
|
backend.auth.cmd = "pass show email/imap" # or use keyring
|
|
|
|
message.send.backend.type = "smtp"
|
|
message.send.backend.host = "smtp.example.com"
|
|
message.send.backend.port = 587
|
|
message.send.backend.encryption.type = "start-tls"
|
|
message.send.backend.login = "you@example.com"
|
|
message.send.backend.auth.type = "password"
|
|
message.send.backend.auth.cmd = "pass show email/smtp"
|
|
|
|
# Folder aliases (himalaya v1.2.0+ syntax). Required whenever the
|
|
# server's folder names don't match himalaya's canonical names
|
|
# (inbox/sent/drafts/trash). Gmail is the common case — see
|
|
# `references/configuration.md` for the `[Gmail]/Sent Mail` mapping.
|
|
folder.aliases.inbox = "INBOX"
|
|
folder.aliases.sent = "Sent"
|
|
folder.aliases.drafts = "Drafts"
|
|
folder.aliases.trash = "Trash"
|
|
```
|
|
|
|
> **Heads up on the alias syntax.** Pre-v1.2.0 docs used a
|
|
> `[accounts.NAME.folder.alias]` sub-section (singular `alias`).
|
|
> v1.2.0 silently ignores that form — TOML parses fine, but the
|
|
> alias resolver never reads it, so every lookup falls through to
|
|
> the canonical name. On Gmail this means save-to-Sent fails *after*
|
|
> SMTP delivery succeeds, and `himalaya message send` exits non-zero.
|
|
> Any caller (agent, script, user) that retries on that exit code
|
|
> will re-run the entire send — including SMTP — producing duplicate
|
|
> emails to recipients. Always use `folder.aliases.X` (plural, dotted
|
|
> keys, directly under `[accounts.NAME]`).
|
|
|
|
## Hermes Integration Notes
|
|
|
|
- **Reading, listing, searching, moving, deleting** all work directly through the terminal tool
|
|
- **Composing/replying/forwarding** — piped input (`cat << EOF | himalaya template send`) is recommended for reliability. Interactive `$EDITOR` mode works with `pty=true` + background + process tool, but requires knowing the editor and its commands
|
|
- Use `--output json` for structured output that's easier to parse programmatically
|
|
- The `himalaya account configure` wizard requires interactive input — use PTY mode: `terminal(command="himalaya account configure", pty=true)`
|
|
|
|
## Common Operations
|
|
|
|
### List Folders
|
|
|
|
```bash
|
|
himalaya folder list
|
|
```
|
|
|
|
### List Emails
|
|
|
|
List emails in INBOX (default):
|
|
|
|
```bash
|
|
himalaya envelope list
|
|
```
|
|
|
|
List emails in a specific folder:
|
|
|
|
```bash
|
|
himalaya envelope list --folder "Sent"
|
|
```
|
|
|
|
List with pagination:
|
|
|
|
```bash
|
|
himalaya envelope list --page 1 --page-size 20
|
|
```
|
|
|
|
### Search Emails
|
|
|
|
```bash
|
|
himalaya envelope list from john@example.com subject meeting
|
|
```
|
|
|
|
### Read an Email
|
|
|
|
Read email by ID (shows plain text):
|
|
|
|
```bash
|
|
himalaya message read 42
|
|
```
|
|
|
|
Export raw MIME:
|
|
|
|
```bash
|
|
himalaya message export 42 --full
|
|
```
|
|
|
|
### Reply to an Email
|
|
|
|
To reply non-interactively from Hermes, read the original message, compose a reply, and pipe it:
|
|
|
|
```bash
|
|
# Get the reply template, edit it, and send
|
|
himalaya template reply 42 | sed 's/^$/\nYour reply text here\n/' | himalaya template send
|
|
```
|
|
|
|
Or build the reply manually:
|
|
|
|
```bash
|
|
cat << 'EOF' | himalaya template send
|
|
From: you@example.com
|
|
To: sender@example.com
|
|
Subject: Re: Original Subject
|
|
In-Reply-To: <original-message-id>
|
|
|
|
Your reply here.
|
|
EOF
|
|
```
|
|
|
|
Reply-all (interactive — needs $EDITOR, use template approach above instead):
|
|
|
|
```bash
|
|
himalaya message reply 42 --all
|
|
```
|
|
|
|
### Forward an Email
|
|
|
|
```bash
|
|
# Get forward template and pipe with modifications
|
|
himalaya template forward 42 | sed 's/^To:.*/To: newrecipient@example.com/' | himalaya template send
|
|
```
|
|
|
|
### Write a New Email
|
|
|
|
**Non-interactive (use this from Hermes)** — pipe the message via stdin:
|
|
|
|
```bash
|
|
cat << 'EOF' | himalaya template send
|
|
From: you@example.com
|
|
To: recipient@example.com
|
|
Subject: Test Message
|
|
|
|
Hello from Himalaya!
|
|
EOF
|
|
```
|
|
|
|
Or with headers flag:
|
|
|
|
```bash
|
|
himalaya message write -H "To:recipient@example.com" -H "Subject:Test" "Message body here"
|
|
```
|
|
|
|
Note: `himalaya message write` without piped input opens `$EDITOR`. This works with `pty=true` + background mode, but piping is simpler and more reliable.
|
|
|
|
### Move/Copy Emails
|
|
|
|
Move to folder (target folder comes first, then the message ID):
|
|
|
|
```bash
|
|
himalaya message move "Archive" 42
|
|
```
|
|
|
|
Copy to folder (target folder comes first, then the message ID):
|
|
|
|
```bash
|
|
himalaya message copy "Important" 42
|
|
```
|
|
|
|
### Delete an Email
|
|
|
|
```bash
|
|
himalaya message delete 42
|
|
```
|
|
|
|
### Manage Flags
|
|
|
|
Add flag:
|
|
|
|
```bash
|
|
himalaya flag add 42 --flag seen
|
|
```
|
|
|
|
Remove flag:
|
|
|
|
```bash
|
|
himalaya flag remove 42 --flag seen
|
|
```
|
|
|
|
## Multiple Accounts
|
|
|
|
List accounts:
|
|
|
|
```bash
|
|
himalaya account list
|
|
```
|
|
|
|
Use a specific account:
|
|
|
|
```bash
|
|
himalaya --account work envelope list
|
|
```
|
|
|
|
## Attachments
|
|
|
|
Save attachments from a message:
|
|
|
|
```bash
|
|
himalaya attachment download 42
|
|
```
|
|
|
|
Save to specific directory:
|
|
|
|
```bash
|
|
himalaya attachment download 42 --downloads-dir ~/Downloads
|
|
```
|
|
|
|
## Output Formats
|
|
|
|
Most commands support `--output` for structured output:
|
|
|
|
```bash
|
|
himalaya envelope list --output json
|
|
himalaya envelope list --output plain
|
|
```
|
|
|
|
## Debugging
|
|
|
|
Enable debug logging:
|
|
|
|
```bash
|
|
RUST_LOG=debug himalaya envelope list
|
|
```
|
|
|
|
Full trace with backtrace:
|
|
|
|
```bash
|
|
RUST_LOG=trace RUST_BACKTRACE=1 himalaya envelope list
|
|
```
|
|
|
|
## Bulk Export (Multi-Folder)
|
|
|
|
When exporting emails from multiple folders into a single directory, use a shell
|
|
script that pairs each ID with its source folder. **Message IDs are
|
|
folder-relative** — an ID from `--folder "GirlsMom"` will fail with "cannot
|
|
find message" unless you also pass `--folder "GirlsMom"` to `message export`.
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
OUTDIR=/tmp/export
|
|
mkdir -p "$OUTDIR"
|
|
|
|
# For each folder, list then export with matching --folder
|
|
himalaya envelope list --folder "GirlsMom" --page-size 200 2>/dev/null \
|
|
| grep '^|' | grep -v '^|---' | grep -v '^| ID' \
|
|
| while read line; do
|
|
id=$(echo "$line" | awk -F'|' '{gsub(/ /,"",$2); print $2}')
|
|
himalaya message export "$id" --full --folder "GirlsMom" 2>/dev/null \
|
|
> "$OUTDIR/${id}.eml"
|
|
done
|
|
```
|
|
|
|
See `scripts/bulk-export.py` for a complete multi-folder Python template that handles folder-relative IDs, pagination, and empty-file verification.
|
|
|
|
## Read-Only Gmail Setup
|
|
|
|
For read-only access (no SMTP), omit the `message.send` block entirely:
|
|
|
|
```toml
|
|
[accounts.personal]
|
|
email = "you@gmail.com"
|
|
display-name = "Your Name"
|
|
default = true
|
|
|
|
backend.type = "imap"
|
|
backend.host = "imap.gmail.com"
|
|
backend.port = 993
|
|
backend.encryption.type = "tls"
|
|
backend.login = "you@gmail.com"
|
|
backend.auth.type = "password"
|
|
backend.auth.cmd = "echo YOUR_APP_PASSWORD" # inline for quick setup
|
|
|
|
folder.aliases.inbox = "INBOX"
|
|
folder.aliases.sent = "[Gmail]/Sent Mail"
|
|
folder.aliases.drafts = "[Gmail]/Drafts"
|
|
folder.aliases.trash = "[Gmail]/Trash"
|
|
```
|
|
|
|
Generate an App Password at https://myaccount.google.com/apppasswords (select
|
|
"Mail", name it "Himalaya").
|
|
|
|
## Pitfalls
|
|
|
|
- **Folder-relative IDs**: Message IDs from `envelope list --folder "X"` only
|
|
work with `message export --folder "X"`. Without `--folder`, you get "cannot
|
|
find message". This is the #1 cause of silent empty exports.
|
|
- **Search query ordering**: Flags like `--page-size` must come BEFORE search
|
|
terms. `himalaya envelope list from foo@bar.com --page-size 5` fails; use
|
|
`himalaya envelope list --page-size 5 "from foo@bar.com"` instead.
|
|
- **`--output json` breaks with search queries**: When a search query returns
|
|
no results or an error, `--output json` produces empty output that fails
|
|
`json.load()`. Always test with plain-text output first, or wrap JSON parsing
|
|
in try/except.
|
|
- **`[Gmail]/All Mail` search syntax differs**: The All Mail folder uses a
|
|
different search parser than regular folders. `himalaya envelope list
|
|
--folder "[Gmail]/All Mail" "pandaneuro"` fails with a parse error. Use
|
|
specific folders (INBOX, Sent Mail) with explicit `from`/`to` queries
|
|
instead.
|
|
- **Gmail folder names**: Gmail uses `[Gmail]/Sent Mail`, `[Gmail]/Drafts`,
|
|
`[Gmail]/Trash` — not plain `Sent`/`Drafts`/`Trash`. The folder aliases
|
|
handle this mapping.
|
|
- **Empty exports are silent**: `himalaya message export` writes nothing and
|
|
exits 0 when it can't find a message. Always verify with `wc -c` or
|
|
`find -empty` after bulk exports.
|
|
|
|
## Tips
|
|
|
|
- Use `himalaya --help` or `himalaya <command> --help` for detailed usage.
|
|
- Message IDs are relative to the current folder; re-list after folder changes.
|
|
- For composing rich emails with attachments, use MML syntax (see `references/message-composition.md`).
|
|
- Store passwords securely using `pass`, system keyring, or a command that outputs the password.
|