Skill flagged — suspicious patterns detected

ClawHub Security flagged this skill as suspicious. Review the scan results before using.

Zoho Mail CLI

v0.1.4

Read, search, send, and manage Zoho Mail from the terminal. JSON output for scripting and agents. No third-party service required.

1· 599·2 current·2 all-time
byrobsanna@robsannaa
Security Scan
VirusTotalVirusTotal
Suspicious
View report →
OpenClawOpenClaw
Benign
medium confidence
Purpose & Capability
The name/description (Zoho Mail CLI) match the runtime instructions: the skill expects the 'zoho' CLI, performs mail list/search/get/download/send operations, and requires OAuth credentials for Zoho. No unrelated service credentials or binaries are requested.
Instruction Scope
SKILL.md stays within the mail-CLI scope (running 'zoho' commands, checking config, and using OS keyring). It documents one-time interactive OAuth login ('zoho login' opens a browser), local config and keyring storage, and optional env vars. Note: the SKILL.md header sets 'user-invocable: false' while registry metadata indicates the skill is user-invocable/autonomously callable — an inconsistency to resolve. Also, interactive browser login cannot be completed by an autonomous agent without extra steps, which limits autonomous use until login is done.
Install Mechanism
This is instruction-only (no platform install spec). SKILL.md shows typical user install paths (Homebrew, uv, pipx from a GitHub repo). Because the platform will not itself download/extract code, the risk is low from the skill bundle; however installing the CLI from the referenced GitHub repo will pull code from that repo — users should vet the upstream source before running install commands.
Credentials
The registry lists no required env vars, while SKILL.md documents optional envs (ZOHO_ACCOUNT, ZOHO_CONFIG, ZOHO_TOKEN_PASSWORD) and clarifies that OAuth client_id/client_secret and access/refresh tokens are sensitive and stored locally. These credentials are proportionate to the stated purpose, but the discrepancy between registry metadata and SKILL.md (no primary credential declared vs. SKILL.md describing OAuth tokens) should be noted.
Persistence & Privilege
The skill does not request 'always: true' or other elevated persistent privileges, nor does it claim to modify other skills or system-wide configs. It operates by invoking an external CLI and using local config/keyring, which is expected for this function.
Assessment
This skill appears to be what it says: a wrapper that calls the 'zoho' CLI and uses local OAuth tokens. Before installing or invoking: 1) Verify the upstream repo (https://github.com/robsannaa/zoho-cli) and Homebrew tap (robsannaa/tap) — installing via pipx/uv/homebrew will run code from that repo, so review it if you don't trust the author. 2) Understand OAuth sensitivity — the CLI stores client_id/client_secret and tokens locally (config.json and OS keyring); protect those files and avoid putting ZOHO_TOKEN_PASSWORD or client secrets into shared CI without encryption. 3) Note the metadata mismatch: SKILL.md sets user-invocable: false while registry metadata allows invocation; confirm whether you want the agent to call the CLI autonomously (an agent cannot complete the interactive 'zoho login' browser flow without manual steps). 4) If you deploy this in shared environments, restrict access to the config path and keyring entries. If you want me to, I can fetch and summarize the GitHub repo contents (setup files, install scripts) so you can inspect what would be installed.

Like a lobster shell, security has layers — review code before you run it.

latestvk97e3jfss06g23gyszy9yfrxh181jh7p
599downloads
1stars
3versions
Updated 5h ago
v0.1.4
MIT-0

zoho — Zoho Mail CLI

Requirements: the zoho binary (install via brew/uv/pipx below), one-time OAuth setup, and local credential storage (config + OS keyring).

zoho is a command-line tool for Zoho Mail. All output is JSON by default — structured, pipe-friendly, and agent-ready. Use --md for markdown tables.

Install

Requires Python 3.11+. Works on macOS, Linux, and Windows.

# Homebrew (macOS / Linux)
brew install robsannaa/tap/zoho-cli

# uv (all platforms)
uv tool install git+https://github.com/robsannaa/zoho-cli

# pipx (all platforms)
pipx install git+https://github.com/robsannaa/zoho-cli

After install, run the one-time setup:

zoho config init   # save your Zoho OAuth client_id / client_secret
zoho login         # open browser, region auto-detected

See the full setup guide in the README.


Prerequisites

  • zoho must be installed and authenticated (zoho login completed).
  • Check: zoho config show — must return a JSON object with default_account and a non-empty accounts map.
  • If not logged in: tell the user to follow the setup in the README.

Output

  • stdout → JSON (default) or Markdown (--md). Always machine-readable.
  • stderr → errors (as JSON), debug logs, interactive prompts. Never in stdout.
  • Exit 0 = success. Exit 1 = error (JSON error object on stderr).
# errors land on stderr, not stdout
zoho mail list 2>/dev/null          # stdout empty on error
zoho mail list 2>&1 >/dev/null      # see error JSON

Authentication

Tokens are stored in the OS keyring and refreshed automatically before every command. No manual token management needed.

Credential storage (sensitive): Users must be aware that the CLI stores sensitive data locally:

  • OAuth client_id and client_secret — saved via zoho config init in the config file (e.g. ~/.config/zoho-cli/config.json).
  • Access and refresh tokens — stored in the OS keyring (or, if ZOHO_TOKEN_PASSWORD is set, in an encrypted file). These are used to access Zoho Mail on the user's behalf.

Do not expose config files or keyring entries to untrusted parties.

If a command fails with not_logged_in or token_refresh_failed, tell the user to run:

zoho login

Global flags

--account EMAIL    select account (env: ZOHO_ACCOUNT)
--config PATH      config file path (env: ZOHO_CONFIG)
--md               markdown table output instead of JSON
--debug            HTTP + debug logs to stderr

Commands

zoho mail list

List messages in a folder.

zoho mail list                               # Inbox, 50 messages
zoho mail list --folder Sent --limit 20
zoho mail list -f "My Project" -n 100

Output — array of message summaries:

[
  {
    "messageId": "1771333290108014300",
    "folderId": "8072279000000002014",
    "subject": "Q1 invoice",
    "from": "billing@acme.com",
    "to": ["you@example.com"],
    "date": "1740067200000",
    "unread": true,
    "hasAttachments": true,
    "tags": []
  }
]

date is a Unix timestamp in milliseconds.

zoho mail search

zoho mail search "invoice 2025"
zoho mail search "from:boss@example.com" --limit 10

Same output shape as mail list.

zoho mail get

Full message content including body.

zoho mail get MESSAGE_ID
zoho mail get MESSAGE_ID --folder-id FOLDER_ID    # faster: skips auto-scan
zoho mail get MESSAGE_ID | jq '.textBody'

Output:

{
  "messageId": "...",
  "folderId": "...",
  "subject": "Q1 invoice",
  "from": "billing@acme.com",
  "to": ["you@example.com"],
  "cc": [],
  "bcc": [],
  "date": "1740067200000",
  "unread": false,
  "hasAttachments": true,
  "tags": [],
  "textBody": "Please find the invoice attached.",
  "htmlBody": "<p>Please find...</p>"
}

zoho mail attachments

zoho mail attachments MESSAGE_ID
zoho mail attachments MESSAGE_ID --folder-id FOLDER_ID

Output:

[
  { "attachmentId": "256063600000020001", "fileName": "invoice.pdf", "size": 123456 }
]

zoho mail download-attachment

zoho mail download-attachment MESSAGE_ID ATTACHMENT_ID --out /tmp/invoice.pdf

Output:

{ "status": "ok", "path": "/tmp/invoice.pdf", "size": 123456 }

zoho mail send

zoho mail send --to alice@example.com --subject "Hi" --text "Hello!"

# HTML + multiple recipients + attachments
zoho mail send \
  --to alice@example.com --to bob@example.com \
  --cc manager@example.com \
  --subject "Report" \
  --html-file report.html \
  --attach report.pdf --attach data.csv

Output:

{ "status": "ok", "messageId": "..." }

Flag / move / delete operations

All accept one or more MESSAGE_ID arguments.

zoho mail mark-read   ID [ID …]
zoho mail mark-unread ID [ID …]
zoho mail move        ID [ID …] --to "Archive"
zoho mail spam        ID [ID …]
zoho mail not-spam    ID [ID …]
zoho mail archive     ID [ID …]
zoho mail unarchive   ID [ID …]
zoho mail delete      ID [ID …]              # → Trash
zoho mail delete      ID [ID …] --permanent  # hard delete

Output:

{ "status": "ok", "updated": ["ID1", "ID2"], "failed": [] }

zoho folders list

zoho folders list

Output:

[
  { "folderId": "8072279000000002014", "folderName": "Inbox", "folderType": "Inbox",
    "path": "/Inbox", "isArchived": 0, "unreadCount": 3, "messageCount": 42 }
]

zoho folders create / rename / delete

zoho folders create "Project X" [--parent-id FOLDER_ID]
zoho folders rename FOLDER_ID "New Name"
zoho folders delete FOLDER_ID

zoho config show / path / init

zoho config show     # JSON config dump (secret redacted)
zoho config path     # {"config_path": "...", "exists": true}
zoho config init     # interactive wizard (prompts on stderr)

Common patterns for agents

# All unread message subjects
zoho mail list | jq -r '.[] | select(.unread) | .subject'

# Get the latest message ID
zoho mail list -n 1 | jq -r '.[0].messageId'

# Get plain-text body of a specific message
zoho mail get "$MSG_ID" | jq -r '.textBody'

# Download all attachments from a message
zoho mail attachments "$MSG_ID" | jq -r '.[].attachmentId' | while read id; do
  zoho mail download-attachment "$MSG_ID" "$id" --out "/tmp/${id}"
done

# Find unread emails from a sender
zoho mail search "from:boss@example.com" | jq '[.[] | select(.unread)]'

# Mark all results as read
zoho mail search "invoice" | jq -r '.[].messageId' | xargs zoho mail mark-read

# Move search results to a folder
zoho mail search "newsletter" | jq -r '.[].messageId' | xargs zoho mail move --to "Archive"

# Send with computed body
zoho mail send \
  --to report-reader@example.com \
  --subject "Daily digest $(date +%F)" \
  --text "$(zoho mail list | jq -r '.[].subject' | head -10 | nl)"

Error response shape

All errors are JSON on stderr:

{
  "status": "error",
  "error": "not_logged_in",
  "details": "No stored token for you@example.com. Run: zoho login --account you@example.com"
}

Common error codes:

CodeMeaning
not_logged_inNo token stored — user must run zoho login
token_refresh_failedToken revoked — user must run zoho login
no_account_idaccountId not saved — run zoho login again
folder_not_foundFolder name doesn't match any folder
message_not_foundMessage ID not found in any folder
api_errorUpstream Zoho API error (details in message)

Comments

Loading comments...