{"id":"89181b33-db56-4318-9f1e-3a2718dbf417","entityType":"agent","slug":"clawhub-aggrrrh-imap-client","name":"IMAP Client","canonicalUrl":"https://www.xpersona.co/agent/clawhub-aggrrrh-imap-client","canonicalPath":"/agent/clawhub-aggrrrh-imap-client","generatedAt":"2026-10-11T16:01:20.117Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T13:01:16.763Z","emptyReason":null},"description":"Read, search, and download email over IMAP from the command line using the `myl` CLI client. Use this skill whenever the user wants to interact with their ma...","descriptionLabel":"Source description","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 1.1K downloads reported by the source. Last updated 10/11/2026.","installCommand":"clawhub skill install s17e5jak0ty2ag4w69xnz7k06n85hfnm:imap-client","sourceUrl":"https://clawhub.ai/aggrrrh/imap-client","homepage":"https://clawhub.ai/aggrrrh/skills/imap-client","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/aggrrrh/imap-client","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/aggrrrh/skills/imap-client","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":61,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"IMAP Client technical dossier on Xpersona with agent coverage, OPENCLEW support, and live trust metadata."},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-11T13:01:16.763Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T13:01:16.763Z","emptyReason":null},"stars":null,"forks":null,"downloads":1061,"packageName":null,"latestVersion":"0.1.3","tractionLabel":"1.1K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T13:01:16.749Z","emptyReason":null},"lastUpdatedAt":"2026-10-11T13:01:16.763Z","lastCrawledAt":"2026-10-11T13:01:16.749Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-12T13:01:16.749Z","lastVerifiedAt":null,"highlights":[{"version":"0.1.3","createdAt":"2026-04-26T09:46:40.962Z","changelog":"Fix misleading security claim in Principle 1: accurately document that the password is passed via myl argv and is visible in /proc/<pid>/cmdline.","fileCount":11,"zipByteSize":28909},{"version":"0.1.2","createdAt":"2026-04-25T21:58:26.397Z","changelog":"Remove third-party repo links; promote codd-tech/imap-client.","fileCount":10,"zipByteSize":27495},{"version":"0.1.1","createdAt":"2026-04-25T21:15:30.408Z","changelog":"Fix homepage to point to codd-tech/imap-client.","fileCount":10,"zipByteSize":27031},{"version":"0.1.0","createdAt":"2026-04-25T21:01:10.015Z","changelog":"Initial release. Read, search, and download email over IMAP via myl. Supports Gmail, Yandex, Mail.ru, Fastmail, iCloud, autodiscovery.","fileCount":10,"zipByteSize":27021}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s17e5jak0ty2ag4w69xnz7k06n85hfnm:imap-client","setupComplexity":"low","setupSteps":["Install using `clawhub skill install s17e5jak0ty2ag4w69xnz7k06n85hfnm:imap-client` in an isolated environment before connecting it to live workloads.","No published capability contract is available yet, so validate auth and request/response behavior manually.","Review the upstream CLAWHUB listing at https://clawhub.ai/aggrrrh/imap-client before using production credentials."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-aggrrrh-imap-client/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-aggrrrh-imap-client/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-aggrrrh-imap-client/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-aggrrrh-imap-client/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-aggrrrh-imap-client/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-aggrrrh-imap-client/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-11T16:01:20.112Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-aggrrrh-imap-client/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-aggrrrh-imap-client/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-aggrrrh-imap-client/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-aggrrrh-imap-client/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T13:01:16.763Z","emptyReason":null},"readme":"Skill: IMAP Client\n\nOwner: aggrrrh\n\nSummary: Read, search, and download email over IMAP from the command line using the `myl` CLI client. Use this skill whenever the user wants to interact with their ma...\n\nTags: latest:0.1.3\n\nVersion history:\n\nv0.1.3 | 2026-04-26T09:46:40.962Z | user\n\nFix misleading security claim in Principle 1: accurately document that the password is passed via myl argv and is visible in /proc/<pid>/cmdline.\n\nv0.1.2 | 2026-04-25T21:58:26.397Z | user\n\nRemove third-party repo links; promote codd-tech/imap-client.\n\nv0.1.1 | 2026-04-25T21:15:30.408Z | user\n\nFix homepage to point to codd-tech/imap-client.\n\nv0.1.0 | 2026-04-25T21:01:10.015Z | user\n\nInitial release. Read, search, and download email over IMAP via myl. Supports Gmail, Yandex, Mail.ru, Fastmail, iCloud, autodiscovery.\n\nArchive index:\n\nArchive v0.1.3: 11 files, 28909 bytes\n\nFiles: README.md (8149b), references/authentication.md (8797b), references/installation.md (3734b), references/operations.md (8075b), references/recipes.md (6338b), references/troubleshooting.md (8165b), scripts/check_myl.sh (979b), scripts/imap.sh (4090b), skill-card.md (2412b), SKILL.md (8941b), _meta.json (130b)\n\nFile v0.1.3:SKILL.md\n\n---\nname: imap-client\ndescription: 'Read, search, and download email over IMAP from the command line using the `myl` CLI client. Use this skill whenever the user wants to interact with their mailbox from a terminal — checking the inbox, listing or searching messages, reading a specific email, opening HTML or raw source, or saving attachments. Trigger on any of these cues even when `myl` is not named explicitly — \"check my email\", \"look in my inbox\", \"search my mail for X\", \"find the email from Y\", \"download the attachment\", \"is there an email about Z\", \"read the latest message\", \"show me unread\", \"connect to my IMAP server\", \"imap.gmail.com\", \"imap.yandex.com\", \"imap.yandex.ru\", \"imap.mail.ru\", \"imap.fastmail.com\", \"Yandex Mail\", \"Mail.ru\", \"Gmail IMAP\", \"проверить почту\", \"новые письма\", \"найти письмо\", and similar. Also trigger when the user asks to script or automate any of the above. Do not trigger for outgoing mail (sending, SMTP, drafting) — `myl` is read-only — or for desktop/GUI mail clients.'\nlicense: MIT\nhomepage: https://github.com/codd-tech/imap-client\nmetadata: {\"openclaw\":{\"emoji\":\"📬\",\"requires\":{\"bins\":[\"myl\"],\"env\":[\"IMAP_USER\",\"IMAP_PASSWORD\"]},\"primaryEnv\":\"IMAP_PASSWORD\",\"install\":[{\"id\":\"pipx\",\"kind\":\"pipx\",\"package\":\"myl\",\"bins\":[\"myl\"],\"label\":\"Install myl via pipx\"}]}}\n---\n\n# imap-client\n\nRead mailboxes over IMAP from the terminal using `myl`, a small Python CLI client. Maintained and distributed by [codd-tech](https://github.com/codd-tech/imap-client). Designed to drop into [OpenClaw](https://openclaw.ai) and any other AgentSkills-compatible runtime (Claude Code, generic).\n\n`myl` is read-only and intentionally minimal: it lists, searches, and fetches messages and attachments. It does not send mail, manage folders, or modify state beyond optionally marking messages as seen.\n\n## How credentials reach this skill\n\nThis is the most important section. **You do not type passwords on the command line.** Credentials live in environment variables that the runtime injects per agent run. The skill reads them and assembles the right `myl` flags through the wrapper at `{baseDir}/scripts/imap.sh`.\n\nThe variables the wrapper expects:\n\n| Variable | Required | Purpose |\n|---|---|---|\n| `IMAP_USER` | yes | Login (usually full email address) |\n| `IMAP_PASSWORD` | yes | App-specific password (see `references/authentication.md`) |\n| `IMAP_PROVIDER` | no | One of `auto` (default), `gmail`, `yandex`, `mailru`, `manual` |\n| `IMAP_SERVER` | only with `manual` | IMAP host |\n| `IMAP_PORT` | no | Defaults to 993 |\n| `IMAP_STARTTLS` | no | `1` to add `--starttls` (use only with port 143) |\n\n**Set them once, use them every session.** How depends on the runtime — `references/authentication.md` covers OpenClaw's `skills.entries.imap-client.env`, generic shell `export`, and a `~/.config/imap-client/credentials` fallback file. Do not invent your own scheme; use one of those three.\n\nIf the wrapper detects `IMAP_USER` or `IMAP_PASSWORD` is missing, it prints the setup instructions and exits without contacting any server. That's the signal to stop and walk the user through credential setup before retrying.\n\n## Workflow at a glance\n\n1. **Check that `myl` is installed.** OpenClaw gates this skill on `requires.bins: [\"myl\"]`, so it shouldn't load without it. For non-OpenClaw runtimes, run `bash {baseDir}/scripts/check_myl.sh`. If missing, follow `references/installation.md`.\n2. **Confirm credentials are configured.** Run `bash {baseDir}/scripts/imap.sh --count 1 >/dev/null` once. Success means the env vars are wired and the connection works. Failure means walk the user through `references/authentication.md`.\n3. **Run the requested operation** through the wrapper. Listing, searching, fetching by ID, getting HTML, saving raw `.eml`, or pulling an attachment.\n4. **Summarise the result.** Don't dump full raw email bodies into the chat unless the user asked.\n\nEvery `myl` example in this skill goes through `{baseDir}/scripts/imap.sh`, which expands env vars into the right `myl` flags. You do not need to remember `--google` vs `--auto` vs `--server`/`--port`; the wrapper picks based on `IMAP_PROVIDER`.\n\n## When to read what\n\n| Task involves… | Read |\n|---|---|\n| Detecting or installing `myl`, OpenClaw `requires.bins` gating | `references/installation.md` |\n| Setting up credentials, choosing connection mode, app passwords for Gmail / Yandex / Mail.ru / iCloud / Fastmail | `references/authentication.md` |\n| Any specific CLI flag, listing, searching, fetching, attachments, provider-specific folder names | `references/operations.md` |\n| Multi-step recipes (e.g. \"find the invoice from Acme last month and save the PDF\") | `references/recipes.md` |\n| Errors like SSL failures, \"command not found\", autodiscovery failing, \"AUTHENTICATIONFAILED\", env vars not visible to the wrapper | `references/troubleshooting.md` |\n\n## Principles\n\n### 1. Credentials must not appear in agent-generated commands or logs\n\n**Do not** generate commands like `myl --password hunter2` or `myl --password \"$IMAP_PASSWORD\"` directly — the first hardcodes the secret in shell history and conversation logs; the second exposes it there too and adds no benefit over the wrapper. Always use the wrapper:\n\n```bash\nbash {baseDir}/scripts/imap.sh --count 5\n```\n\nThe wrapper reads credentials from env vars and passes them to `myl` via `--username`/`--password` flags. This means the password **is** briefly visible in `/proc/<pid>/cmdline` and `ps` output to other processes on the same host while `myl` runs — the same exposure as running `myl` directly with env-var expansion. The wrapper's benefit is narrower: the password value never appears in commands the agent generates, in shell history, or in conversation logs. On shared or multi-user machines this argv exposure should be understood as a residual risk.\n\n### 2. Default to small result sets\n\nWhen the user's intent is exploratory (\"any new mail?\"), pass `--count 5` or `--count 10`. Only fetch larger windows on explicit request. This keeps output readable and avoids dumping sensitive content the user didn't ask to see.\n\n### 3. Don't mark as seen by accident\n\n`--mark-seen` mutates state on the server. Only pass it when the user explicitly asked to mark messages read. Listing or reading without this flag is non-destructive.\n\n### 4. Render long bodies to a file, summarise in chat\n\nWhen the user fetches a long message or HTML email, save the raw output to a file (e.g. `/tmp/email-<id>.eml` or `.html`) and give the user a 2–4 sentence summary plus the file path. Do not paste a 500-line HTML body into the conversation.\n\n### 5. Search syntax is server-side IMAP, not Gmail's web UI\n\n`--search \"important\"` issues an IMAP `SEARCH` command. It does not understand Gmail's `from:`, `has:attachment`, or `label:` operators. For complex filtering, fetch a reasonable window with `--count` and filter the listing locally. See `references/operations.md` for what IMAP `SEARCH` supports.\n\n### 6. Never echo, summarise, or persist the password\n\nWhen summarising what you did, refer to the credential as `IMAP_PASSWORD` or \"the password from your OpenClaw config\", never the literal value. If the user pastes a password into chat by mistake, treat it as compromised: tell them to rotate it and update their config. Do not write it to any artifact.\n\n## Quick decision tree\n\n```\nUser asked something email-related from the CLI\n  │\n  ├─ Is `myl` installed and on PATH?  ── No  ──► references/installation.md\n  │   │\n  │   Yes\n  │   ▼\n  ├─ Does the wrapper smoke-test pass?\n  │     bash {baseDir}/scripts/imap.sh --count 1 >/dev/null\n  │   │                       No  ──► references/authentication.md\n  │   Yes\n  │   ▼\n  ├─ What does the user want?\n  │   ├─ Browse / list           ──► imap.sh --count N [--folder F]\n  │   ├─ Search                  ──► imap.sh --search \"TERM\" [--count N]\n  │   ├─ Read one message        ──► imap.sh \"$MAILID\"\n  │   ├─ Read HTML version       ──► imap.sh --html \"$MAILID\"  → save to file\n  │   ├─ Save raw .eml           ──► imap.sh --raw \"$MAILID\" > file.eml\n  │   ├─ Get attachment          ──► imap.sh \"$MAILID\" \"$ATT_NAME\" > file\n  │   └─ Anything multi-step     ──► references/recipes.md\n  │\n  └─ Errors? ─────────────────────► references/troubleshooting.md\n```\n\n## Output style\n\nAfter running the wrapper, present results in this shape:\n\n- **One-line status** of what just ran (e.g. \"Listed the 10 most recent messages in INBOX\").\n- **A compact table or bullet list** of message metadata (date, from, subject, ID).\n- **Any file paths** where larger output was saved.\n- **Suggested next actions** (e.g. \"Want me to open #4582 or save its attachments?\").\n\nKeep it scannable.\n\nFile v0.1.3:README.md\n\n# imap-client\n\n[![Install via ClawHub](https://img.shields.io/badge/install-clawhub-2563eb?style=flat-square)](https://clawhub.ai/aggrrrh/imap-client)\n[![License: MIT](https://img.shields.io/github/license/codd-tech/imap-client?style=flat-square)](./LICENSE)\n[![Maintained by codd.tech](https://img.shields.io/badge/maintained%20by-codd.tech-f97316?style=flat-square)](https://codd.tech)\n[![Stars](https://img.shields.io/github/stars/codd-tech/imap-client?style=flat-square)](https://github.com/codd-tech/imap-client/stargazers)\n\nAn agent skill for [OpenClaw](https://openclaw.ai), Claude Code, and other AgentSkills-compatible runtimes. Lets the agent read, search, and download email over IMAP from the command line via the [`myl`](https://github.com/pschmitt/myl) CLI client.\n\n`myl` is a small read-only IMAP client. This skill teaches the agent **when** to reach for it, **how** to install it, **how to source credentials safely** from the runtime's environment-injection mechanism, and **which** flags to use for common tasks — without ever asking for the password mid-session.\n\n## What this skill enables\n\nOnce installed and configured once, the agent will recognise prompts like:\n\n- *\"check my inbox\"*\n- *\"any new email from Acme today?\"*\n- *\"find the email with the AWS invoice and save the PDF\"*\n- *\"show me the HTML version of the newsletter from yesterday\"*\n- *\"download all unread messages as `.eml` files\"*\n- *\"проверь почту на Яндексе\"*\n- *\"найди письмо от налоговой\"*\n\n…and translate them into safe `myl` invocations through the wrapper at `scripts/imap.sh`, summarising the result back in chat.\n\n## Provider support\n\nFirst-class support, with `IMAP_PROVIDER` shortcuts:\n\n- **Gmail** / Google Workspace (`IMAP_PROVIDER=gmail`)\n- **Yandex Mail** — `@yandex.ru`, `@yandex.com`, Yandex 360 custom domains (`IMAP_PROVIDER=yandex`)\n- **Mail.ru** — `@mail.ru`, `@bk.ru`, `@inbox.ru`, `@list.ru` (`IMAP_PROVIDER=mailru`)\n\nPlus autodiscovery for most other providers (Fastmail, iCloud, ISPs) and explicit `manual` mode for self-hosted / corporate servers.\n\n## Quick start\n\n### 1. Install `myl`\n\n```bash\npipx install myl\n```\n\n(Or `pip install --user myl`, or `nix run github:pschmitt/myl`.)\n\n### 2. Get an app-specific password from your provider\n\nAccount settings → app passwords / external app passwords. Direct links per provider in [`references/authentication.md`](./references/authentication.md).\n\n### 3. Install the skill\n\n**Recommended — via ClawHub:**\n\n```bash\nclawhub install imap-client\n```\n\n**Or clone directly:**\n\n```bash\n# OpenClaw\ngit clone https://github.com/codd-tech/imap-client ~/.openclaw/skills/imap-client\n\n# Claude Code\ngit clone https://github.com/codd-tech/imap-client ~/.claude/skills/imap-client\n\n# Generic AgentSkills runtime — drop the folder anywhere the runtime scans for SKILL.md\n```\n\nRestart the session. OpenClaw picks the skill up automatically. The skill declares `requires.bins: [\"myl\"]` so it filters itself out if `myl` isn't on `PATH` — you'll never get a half-broken state.\n\n### 4. Configure credentials — pick the method for your runtime\n\n**OpenClaw** (recommended for OpenClaw users) — edit `~/.openclaw/openclaw.json`:\n\n```json\n{\n  \"skills\": {\n    \"entries\": {\n      \"imap-client\": {\n        \"enabled\": true,\n        \"env\": {\n          \"IMAP_USER\": \"you@yandex.ru\",\n          \"IMAP_PASSWORD\": \"app-specific-password-here\",\n          \"IMAP_PROVIDER\": \"yandex\"\n        }\n      }\n    }\n  }\n}\n```\n\n```bash\nchmod 600 ~/.openclaw/openclaw.json\n```\n\nOpenClaw injects these into `process.env` per agent run. You configure once; every subsequent session has them.\n\n**Claude Code / generic shell** — export in `~/.bashrc` / `~/.zshrc`:\n\n```bash\nexport IMAP_USER='you@yandex.ru'\nexport IMAP_PASSWORD='app-specific-password-here'\nexport IMAP_PROVIDER='yandex'\n```\n\n**Headless / cron / fallback** — create `~/.config/imap-client/credentials`:\n\n```bash\nmkdir -p ~/.config/imap-client\ncat > ~/.config/imap-client/credentials <<'EOF'\nIMAP_USER='you@yandex.ru'\nIMAP_PASSWORD='app-specific-password-here'\nIMAP_PROVIDER='yandex'\nEOF\nchmod 600 ~/.config/imap-client/credentials\n```\n\nThe wrapper refuses to source this file if its permissions are not `600` or `400`.\n\n### 5. Verify\n\nAsk the agent something like *\"check the latest five emails\"* — or run the wrapper directly:\n\n```bash\nbash ~/.openclaw/skills/imap-client/scripts/imap.sh --count 5\n```\n\n## Repo layout\n\n```\nimap-client/\n├── SKILL.md                       # Frontmatter + workflow + principles\n├── README.md                      # This file\n├── LICENSE                        # MIT\n├── .gitignore\n├── references/\n│   ├── installation.md            # pipx / pip / nix / source install paths + sandbox\n│   ├── authentication.md          # OpenClaw env injection + fallbacks; provider table\n│   ├── operations.md              # Full myl flag reference + folder names per provider\n│   ├── recipes.md                 # 11 multi-step workflows, including Yandex/Mail.ru\n│   └── troubleshooting.md         # Symptom-first error guide\n└── scripts/\n    ├── imap.sh                    # Credential-aware wrapper around myl\n    └── check_myl.sh               # Fast install detection\n```\n\n## Security model\n\nThe skill is opinionated about credentials. The short version:\n\n- Passwords never appear as literals in commands the agent generates.\n- The runtime's environment-injection mechanism (OpenClaw `skills.entries.<key>.env`, or shell `export`, or the `chmod 600` creds file) is the source of truth.\n- The `imap.sh` wrapper reads env vars and constructs `myl` flags internally — the password is in the wrapper's process scope, never in the agent's command history.\n- App-specific passwords from each provider are the default recommendation; the skill explains where to generate them (Gmail, Yandex, Mail.ru, iCloud, Fastmail, Yahoo).\n- The agent is instructed not to echo, summarise, or persist the password anywhere.\n- For OpenClaw users, `apiKey` with a `SecretRef` (`{ source, provider, id }`) keeps the literal password out of `openclaw.json` entirely.\n\nSee [`references/authentication.md`](./references/authentication.md) for the full ruleset.\n\n## Limitations of `myl` itself\n\n`myl` is intentionally minimal. The skill will tell the user explicitly when their request is out of scope and suggest alternatives:\n\n| Want to… | Use instead |\n|---|---|\n| Send mail | `msmtp`, `mutt`, scripted SMTP |\n| Move / delete / label | `imap-tools`, the provider's web UI |\n| Sync to local maildir | `mbsync` (`isync`), `offlineimap`, `getmail` |\n| OAuth2 to Gmail / Outlook | Proton Bridge, `mbsync` + XOAUTH2, or app password fallback |\n\n## Contributing\n\nBug reports and PRs welcome. The skill itself is markdown plus two shell scripts — easy to read, easy to fork.\n\nWhen proposing changes, prefer:\n\n- additions to `references/` over additions to `SKILL.md` (keep the always-loaded part lean)\n- examples that don't paste credentials anywhere\n- behaviour changes that fail safely if the user's `myl` version is older than the skill assumes\n\n## Credits\n\n- [`myl`](https://github.com/pschmitt/myl) by Philipp Schmitt — the underlying CLI this skill wraps.\n- [OpenClaw](https://openclaw.ai) for the AgentSkills runtime, env injection mechanism, and skills format documented at https://docs.openclaw.ai/tools/skills.\n- Anthropic's [Skills documentation](https://docs.claude.com/en/docs/build-with-claude/skills) — structure and best-practice patterns.\n\n## About the maintainer\n\nBuilt and maintained by **[codd.tech](https://codd.tech)** — a boutique technical consultancy specialising in AI agent infrastructure, distributed systems, and platform engineering. We help product teams ship reliable agentic workflows in production: integration design, custom skill packs, OpenClaw / Claude / MCP deployments, and DevOps audits.\n\nHave a use case for agent-driven email automation, or want a custom skill built for your stack? **[Get in touch](https://codd.tech)**.\n\n## License\n\nMIT — see [`LICENSE`](./LICENSE).\n\nFile v0.1.3:_meta.json\n\n{\n  \"ownerId\": \"kn78q4f09z7as2hbshyxss9sk185ht5d\",\n  \"slug\": \"imap-client\",\n  \"version\": \"0.1.3\",\n  \"publishedAt\": 1777196800962\n}\n\nFile v0.1.3:references/authentication.md\n\n# Authentication & Connection\n\nThis is the most security-sensitive part of the skill. Read it before configuring credentials anywhere.\n\n## The model in one paragraph\n\nCredentials live as **environment variables** that the runtime injects per agent run. The wrapper at `scripts/imap.sh` reads those env vars, picks the right `myl` connection flags, and never echoes the password. **You configure once, you read mail forever.**\n\n## Setting up credentials — pick one method\n\n### Method A — OpenClaw (recommended for OpenClaw users)\n\nOpenClaw injects `skills.entries.<key>.env` into `process.env` for the duration of each agent turn, then restores the original environment. This is documented behaviour: see https://docs.openclaw.ai/tools/skills under \"Environment injection (per agent run)\".\n\nEdit `~/.openclaw/openclaw.json` and add an entry under `skills.entries`:\n\n```json\n{\n  \"skills\": {\n    \"entries\": {\n      \"imap-client\": {\n        \"enabled\": true,\n        \"env\": {\n          \"IMAP_USER\": \"you@example.com\",\n          \"IMAP_PASSWORD\": \"app-specific-password-here\",\n          \"IMAP_PROVIDER\": \"auto\"\n        }\n      }\n    }\n  }\n}\n```\n\nThen restart the agent session (or wait for the skills watcher to pick it up if `skills.load.watch` is enabled). The next time the agent runs the skill, `IMAP_USER` and `IMAP_PASSWORD` are already in the environment.\n\n**Permissions matter.** `~/.openclaw/openclaw.json` should not be world-readable:\n\n```bash\nchmod 600 ~/.openclaw/openclaw.json\n```\n\n**Use `apiKey` with a SecretRef for stronger isolation.** OpenClaw supports pulling the password from a separate source rather than inlining it as plaintext in the JSON:\n\n```json\n{\n  \"skills\": {\n    \"entries\": {\n      \"imap-client\": {\n        \"enabled\": true,\n        \"apiKey\": { \"source\": \"env\", \"provider\": \"default\", \"id\": \"MY_IMAP_PASSWORD\" },\n        \"env\": {\n          \"IMAP_USER\": \"you@example.com\",\n          \"IMAP_PROVIDER\": \"auto\"\n        }\n      }\n    }\n  }\n}\n```\n\nThe `apiKey` field maps to whatever env var name is declared in `metadata.openclaw.primaryEnv` of `SKILL.md` — for this skill that's `IMAP_PASSWORD`. So OpenClaw reads `MY_IMAP_PASSWORD` from your shell env (or another secret backend) and exposes it as `IMAP_PASSWORD` to the wrapper. The literal password never appears in `openclaw.json`.\n\n### Method B — Generic shell `export`\n\nFor Claude Code and other AgentSkills runtimes that don't have OpenClaw's injection mechanism, just export the variables in the shell that launches the agent:\n\n```bash\nexport IMAP_USER='you@example.com'\nexport IMAP_PASSWORD='app-specific-password-here'\nexport IMAP_PROVIDER='auto'\n```\n\nPut this in `~/.bashrc` / `~/.zshrc` if you want it to persist. The downside compared to Method A is that the variables are global to that shell, not scoped to the agent run. The upside is no extra config file.\n\n### Method C — Credentials file fallback\n\nWhen neither Method A nor B is convenient (e.g. cron jobs, headless workflows, CI), drop a credentials file at `~/.config/imap-client/credentials`:\n\n```bash\nmkdir -p ~/.config/imap-client\ncat > ~/.config/imap-client/credentials <<'EOF'\nIMAP_USER='you@example.com'\nIMAP_PASSWORD='app-specific-password-here'\nIMAP_PROVIDER='auto'\nEOF\nchmod 600 ~/.config/imap-client/credentials\n```\n\nThe wrapper sources this file when `IMAP_USER`/`IMAP_PASSWORD` are not in the env, **but only if permissions are 600 or 400**. World-readable creds files are ignored with a warning.\n\nTo use a different path, set `IMAP_CREDENTIALS_FILE` in env.\n\n## Per-account: switching mailboxes\n\nFor multiple accounts, declare each one as a separate OpenClaw skill entry under a different agent (per-agent skill allowlists make this clean), or scope the env per shell:\n\n```bash\n# Work\n( export IMAP_USER='kirill@codd.tech' \\\n         IMAP_PASSWORD=\"$WORK_APP_PASSWORD\" \\\n         IMAP_PROVIDER='auto' ; \\\n  bash scripts/imap.sh --count 5 )\n\n# Personal\n( export IMAP_USER='kirill@yandex.ru' \\\n         IMAP_PASSWORD=\"$YANDEX_APP_PASSWORD\" \\\n         IMAP_PROVIDER='yandex' ; \\\n  bash scripts/imap.sh --count 5 )\n```\n\nThe parentheses create a subshell so the exports don't pollute your main session.\n\n## `IMAP_PROVIDER` — what to set\n\n| Value | Effect | When to use |\n|---|---|---|\n| `auto` (default) | `myl --auto` — autodiscovery from username domain | Most modern providers (Fastmail, iCloud, ISPs) |\n| `gmail` | `myl --google` — hardcoded Gmail IMAP | `@gmail.com` / Google Workspace accounts |\n| `yandex` | `--server imap.yandex.com --port 993` | Yandex Mail (`@yandex.ru`, `@yandex.com`, custom domains) |\n| `mailru` | `--server imap.mail.ru --port 993` | Mail.ru (`@mail.ru`, `@bk.ru`, `@inbox.ru`, `@list.ru`) |\n| `manual` | `--server $IMAP_SERVER --port $IMAP_PORT [--starttls]` | Self-hosted, corporate, or anything autodiscovery doesn't recognise |\n\n## App passwords — the credential the user actually needs\n\nAlmost no major provider accepts the account password over IMAP anymore when 2FA is enabled. They require an **app-specific password** generated from the account settings.\n\n| Provider | Where to generate | Notes |\n|---|---|---|\n| **Gmail / Google Workspace** | https://myaccount.google.com/apppasswords | Requires 2-Step Verification on. If the link 404s, your account or organisation has app passwords disabled — switch provider or ask admin. |\n| **Yandex Mail** | https://id.yandex.ru/security/app-passwords | Pick \"Mail (IMAP/POP3, SMTP)\". Works for `@yandex.ru`, `@yandex.com`, and custom domains hosted on Yandex 360. |\n| **Mail.ru** | Account → \"Пароли для внешних приложений\" / \"Passwords for external applications\" | Same password works for `@mail.ru`, `@bk.ru`, `@inbox.ru`, `@list.ru`. |\n| **Fastmail** | Settings → Privacy & Security → App Passwords | Can scope to \"IMAP only\" for least privilege. |\n| **iCloud** | https://appleid.apple.com → Sign-In and Security → App-Specific Passwords | Username is your Apple ID email, even if you use an `@icloud.com` alias. |\n| **Yahoo** | Account Security → Generate app password | |\n| **Proton Mail** | Requires Proton Bridge running locally | Use `IMAP_PROVIDER=manual`, `IMAP_SERVER=127.0.0.1`, `IMAP_PORT=1143`. |\n| **Outlook.com** | Microsoft has been deprecating basic auth | If app passwords are disabled, use `mbsync` with XOAUTH2 instead. `myl` does not do OAuth2. |\n\nWhen the IMAP server returns `AUTHENTICATIONFAILED` and the username is one of the providers above, the cause is almost always that the user is trying their account password instead of an app password. Direct them to the relevant URL and explain why.\n\n## Yandex specifics\n\nYandex Mail is widely used in Russian-speaking contexts and has a few quirks worth knowing:\n\n- **Two server hostnames exist.** `imap.yandex.com` and `imap.yandex.ru` both work; `IMAP_PROVIDER=yandex` defaults to `.com` which serves both account types correctly. To force `.ru`, set `IMAP_SERVER=imap.yandex.ru`.\n- **Mailbox features must be enabled in Yandex web UI.** Settings → \"Почтовые программы\" → tick \"С сервера imap.yandex.ru по протоколу IMAP\". Without this, IMAP login fails with `AUTHENTICATIONFAILED` even with the right app password.\n- **Yandex 360 / business accounts (`@your-company.ru` hosted on Yandex)** use the same `imap.yandex.com:993` endpoint and the same app password mechanism.\n- **Folder names are localised.** See `references/operations.md` for the Russian folder name table.\n\n## Mail.ru specifics\n\n- **One app password covers the whole domain group** — the same credential works against `@mail.ru`, `@bk.ru`, `@inbox.ru`, `@list.ru` if you own multiple addresses on the platform.\n- **IMAP must be explicitly enabled in account settings.** Mail.ru settings → \"Все настройки\" → \"Почтовые программы\" → enable IMAP. Same gotcha as Yandex.\n\n## What to do if the user pastes a password into chat\n\nTreat it as compromised. The password may now sit in:\n\n- the chat transcript / conversation log\n- any analytics or telemetry the runtime captured\n- the user's clipboard history\n\n**Tell the user explicitly:** \"That password is now in the chat history. Rotate it (regenerate the app password from the provider) and put the new one into your `~/.openclaw/openclaw.json` config — not into chat.\" Then walk them through Method A above.\n\nDo not echo the password back, do not write it to any file, do not include it in a summary, and do not silently reuse it for the rest of the session.\n\n## Smoke test\n\nOnce credentials are configured, confirm the connection works with a minimal call:\n\n```bash\nbash scripts/imap.sh --count 1 >/dev/null && echo \"connection OK\"\n```\n\nIf this prints `connection OK`, every other operation in `references/operations.md` will work the same way.\n\nFile v0.1.3:references/installation.md\n\n# Installation\n\n`myl` is a Python package. There are several ways to install it; pick the first one that fits the user's environment.\n\n## How OpenClaw handles this\n\nThis skill declares `requires.bins: [\"myl\"]` in `metadata.openclaw`. OpenClaw checks for `myl` on `PATH` at skill load time and **silently filters this skill out** if it's missing, preventing the agent from invoking it without a working binary.\n\nIt also declares an `install` block:\n\n```json\n{ \"id\": \"pipx\", \"kind\": \"pipx\", \"package\": \"myl\", \"bins\": [\"myl\"] }\n```\n\nIn OpenClaw's macOS Skills UI this surfaces a one-click install button. From the CLI the user installs `myl` themselves with one of the methods below — the install block is hint metadata, not an automated runtime installer.\n\nFor non-OpenClaw runtimes (Claude Code, generic), there's no automatic gating. Run `bash scripts/check_myl.sh` first to confirm `myl` is present.\n\n## Detect what's already there\n\nAlways check before installing:\n\n```bash\nbash scripts/check_myl.sh\n```\n\nOr inline:\n\n```bash\nif command -v myl >/dev/null 2>&1; then\n  echo \"myl is installed: $(command -v myl) ($(myl --version 2>/dev/null || echo 'version unknown'))\"\nelse\n  echo \"myl is not on PATH\"\nfi\n```\n\nIf `myl` is present, skip the rest of this file and move on to `authentication.md`.\n\n## Install paths, in order of preference\n\n### `pipx` — recommended\n\nIsolates `myl` and its dependencies from system Python. This is what the upstream README recommends and what the skill's `install` metadata suggests.\n\n```bash\n# Install pipx itself if missing (Debian/Ubuntu)\nsudo apt update && sudo apt install -y pipx\npipx ensurepath\n\n# Install myl\npipx install myl\n```\n\nOn macOS:\n\n```bash\nbrew install pipx\npipx ensurepath\npipx install myl\n```\n\nAfter `pipx ensurepath`, the user may need to restart their shell or `source ~/.bashrc` / `source ~/.zshrc` for `myl` to appear on `PATH`.\n\n### `pip --user` — fallback when `pipx` isn't available\n\n```bash\npip install --user myl\n```\n\nThe binary lands in `~/.local/bin`, which must be on `PATH`. If not:\n\n```bash\necho 'export PATH=\"$HOME/.local/bin:$PATH\"' >> ~/.bashrc\n```\n\n### Nix flake — for Nix users\n\n```bash\n# One-shot run without installing\nnix run github:pschmitt/myl -- --help\n\n# Or add to a flake\n```\n\n### From source\n\n```bash\ngit clone https://github.com/pschmitt/myl.git\ncd myl\npipx install .\n```\n\n## Sandboxed agent runs\n\nIf the agent runs inside a Docker sandbox (OpenClaw `agents.defaults.sandbox.docker`), `myl` must be installed **inside the container** as well — the host bin doesn't satisfy the in-sandbox requirement. Add to `setupCommand`:\n\n```json\n{\n  \"agents\": {\n    \"defaults\": {\n      \"sandbox\": {\n        \"docker\": {\n          \"setupCommand\": \"pipx install myl || pip install --user --break-system-packages myl\"\n        }\n      }\n    }\n  }\n}\n```\n\nSandbox installs also need network egress, a writable root FS, and root user inside the container. See OpenClaw's sandboxing docs for details.\n\n## Confirm before installing\n\n`myl` is a third-party Python package (GPL-3.0, by Philipp Schmitt). Before running an install command, tell the user what's about to happen:\n\n> \"I'll install `myl` via `pipx install myl`. This is a third-party CLI from https://github.com/pschmitt/myl. OK to proceed?\"\n\nSkip this confirmation only if the user has already explicitly approved installing tools in this session.\n\n## Verify the install worked\n\n```bash\ncommand -v myl && myl --help | head -20\n```\n\nIf `command -v myl` succeeds but `myl --help` fails, there's likely a Python interpreter or dependency mismatch. See `troubleshooting.md`.\n\n## Updating\n\n```bash\npipx upgrade myl       # if installed via pipx\npip install --user --upgrade myl   # if installed via pip --user\n```\n\nFile v0.1.3:references/operations.md\n\n# Operations reference\n\nAll examples use the wrapper at `scripts/imap.sh`. The wrapper reads `IMAP_USER` / `IMAP_PASSWORD` / `IMAP_PROVIDER` from the environment (set up via `references/authentication.md`) and forwards everything else to `myl`.\n\nIf the user has aliased the wrapper, replace `bash scripts/imap.sh` with the alias name. A typical setup:\n\n```bash\nalias imap='bash ~/.openclaw/skills/imap-client/scripts/imap.sh'\n```\n\n…and then `imap --count 5` is enough.\n\n## Listing messages\n\n```bash\n# Most recent N messages in INBOX (default folder)\nbash scripts/imap.sh --count 10\n\n# Specific folder\nbash scripts/imap.sh --folder \"INBOX/Archive\" --count 20\n\n# When --folder is omitted, myl operates on INBOX. To discover what folders\n# exist, run a list against INBOX first; some myl versions surface folder\n# listings in the output, others require the `--list-folders` flag if\n# present in your version.\n```\n\n### Folder names by provider\n\nFolder naming differs per server. When the user names a folder casually (\"sent items\", \"spam\", \"корзина\"), translate to the IMAP path the server expects.\n\n| Provider | Inbox | Sent | Drafts | Archive | Trash | Spam |\n|---|---|---|---|---|---|---|\n| Gmail | `INBOX` | `[Gmail]/Sent Mail` | `[Gmail]/Drafts` | `[Gmail]/All Mail` | `[Gmail]/Trash` | `[Gmail]/Spam` |\n| Yandex | `INBOX` | `Sent` (alias for `Отправленные`) | `Drafts` | n/a | `Trash` | `Spam` |\n| Mail.ru | `INBOX` | `Sent` | `Drafts` | `Archive` | `Trash` | `Spam` |\n| Fastmail | `INBOX` | `Sent` | `Drafts` | `Archive` | `Trash` | `Junk Mail` |\n| iCloud | `INBOX` | `Sent Messages` | `Drafts` | `Archive` | `Deleted Messages` | `Junk` |\n| Generic Dovecot | `INBOX` | `Sent` | `Drafts` | (configurable) | `Trash` | `Junk` |\n\nNotes on Russian providers:\n\n- **Yandex** publishes both English (`Sent`, `Drafts`, `Trash`) and Russian (`Отправленные`, `Черновики`, `Удалённые`) folder names; the English ones are aliases that always work, so prefer those.\n- **Mail.ru** uses English internal folder names over IMAP, even when the web UI shows Russian labels.\n- If a custom folder uses Cyrillic, it may be encoded in modified UTF-7 over IMAP. Pass the **exact string `myl` shows in listings**, not what you see in the web client.\n\nIf the first folder guess fails, list the available folders by running with no `--folder` and inspect the output; do not guess repeatedly.\n\n## Searching\n\n`myl --search` issues an IMAP `SEARCH` command. The argument is interpreted by the server, not by `myl`.\n\n```bash\n# Match against subject + body (default for most servers)\nbash scripts/imap.sh --search \"invoice\"\n\n# Combine with folder + count\nbash scripts/imap.sh --folder \"INBOX\" --search \"Acme\" --count 50\n```\n\n### What IMAP SEARCH actually supports\n\nStandard IMAP `SEARCH` keys (RFC 3501). Widely supported:\n\n| Key | Meaning | Example |\n|---|---|---|\n| `FROM \"x\"` | sender contains x | `FROM \"noreply@github.com\"` |\n| `TO \"x\"` | recipient contains x | `TO \"alice@example.com\"` |\n| `SUBJECT \"x\"` | subject contains x | `SUBJECT \"invoice\"` |\n| `BODY \"x\"` | body contains x | `BODY \"API key\"` |\n| `TEXT \"x\"` | header or body contains x | `TEXT \"kubernetes\"` |\n| `SINCE 1-Jan-2026` | received on or after date | `SINCE 1-Apr-2026` |\n| `BEFORE 1-Apr-2026` | received before date | `BEFORE 1-May-2026` |\n| `UNSEEN` | not yet marked read | `UNSEEN` |\n| `SEEN` | already read | |\n| `FLAGGED` | starred / flagged | |\n| `LARGER 10000000` | size in bytes | `LARGER 5000000` |\n\nIn practice, the safe approaches are:\n\n1. Pass a single keyword or short phrase: `--search \"invoice\"`. The server treats this as `TEXT \"invoice\"`.\n2. For complex filters, fetch a reasonable window and post-process locally with `grep` / `awk` / a small Python helper.\n\nWhat `myl --search` does **not** understand:\n\n- Gmail's web UI operators: `from:`, `has:attachment`, `label:`, `older_than:` — these are Gmail-specific and not part of IMAP SEARCH.\n- Yandex's web search syntax (e.g. `from:`, `subject:`) — also web-only.\n- Boolean operators like `AND` / `OR` / `NOT` directly in the string. IMAP supports them but with different syntax.\n\n### Cyrillic search terms\n\nYandex and Mail.ru both support searching for Cyrillic text via IMAP, but the term must be sent in the right charset. `myl` typically forwards the argument as-is and lets the server figure it out:\n\n```bash\nbash scripts/imap.sh --search \"счёт\" --count 20\n```\n\nIf the server returns no results for a Cyrillic term you know exists, retry with the Latin transliteration of the company name (since most senders include both in subject lines).\n\n## Reading a specific message\n\nEach listing shows a per-folder message ID. Fetch it by passing the ID as a positional argument:\n\n```bash\nbash scripts/imap.sh \"$MAILID\"           # plain text body\nbash scripts/imap.sh --html \"$MAILID\"    # HTML body (if present)\nbash scripts/imap.sh --raw \"$MAILID\"     # full raw RFC 5322 source, including headers\n```\n\nFor HTML and raw, redirect to a file rather than dumping into the terminal:\n\n```bash\nbash scripts/imap.sh --html \"$MAILID\" > \"/tmp/mail-${MAILID}.html\"\nbash scripts/imap.sh --raw  \"$MAILID\" > \"/tmp/mail-${MAILID}.eml\"\n```\n\nTell the user the file path and offer to open or summarise it.\n\n## Marking as seen\n\n```bash\nbash scripts/imap.sh --mark-seen --count 10\n```\n\nMutates server state. Only use when the user explicitly asked to mark messages read. Never combine `--mark-seen` with a search / list that the user is just exploring.\n\n## Attachments\n\n```bash\n# 1. Open the message — myl shows attachment names in the message detail\nbash scripts/imap.sh \"$MAILID\"\n\n# 2. Fetch a specific attachment by name\nbash scripts/imap.sh \"$MAILID\" \"invoice-2026-04.pdf\" > ~/Downloads/invoice-2026-04.pdf\n```\n\nThe second positional argument after `$MAILID` is the attachment filename. Output goes to stdout, so always redirect to a file.\n\nIf the attachment name has spaces or special characters, quote it:\n\n```bash\nbash scripts/imap.sh \"$MAILID\" \"Q1 report.pdf\" > \"$HOME/Downloads/Q1 report.pdf\"\n```\n\nCyrillic attachment names work but the underlying IMAP encoding (RFC 2047 / RFC 2231) varies. If the literal Cyrillic name doesn't match, retry with the encoded form `myl` showed in the message detail.\n\n## Full flag reference\n\nFrom the upstream README (`https://github.com/pschmitt/myl`). All of these forward through the wrapper:\n\n| Flag | Purpose |\n|---|---|\n| `--server HOST` | IMAP server hostname (set via `IMAP_SERVER` env) |\n| `--port N` | IMAP server port (set via `IMAP_PORT` env; default 993) |\n| `--starttls` | Upgrade plain connection to TLS (set via `IMAP_STARTTLS=1`) |\n| `--auto` | Autodiscover server + port (set via `IMAP_PROVIDER=auto`) |\n| `--google` | Hardcode Gmail's IMAP settings (set via `IMAP_PROVIDER=gmail`) |\n| `--username USER` | Login username (set via `IMAP_USER`) |\n| `--password PASS` | Login password (set via `IMAP_PASSWORD`) |\n| `--folder NAME` | IMAP folder to operate on (default `INBOX`) |\n| `--count N` | Number of messages to fetch in listings |\n| `--search QUERY` | Server-side IMAP SEARCH |\n| `--mark-seen` | Mark fetched messages as seen (mutates server state) |\n| `--html` | When fetching a message, output the HTML body |\n| `--raw` | When fetching a message, output the raw RFC 5322 source |\n| `--help` | Print help |\n\nFor the authoritative list on the user's installed version:\n\n```bash\nmyl --help\n```\n\n## What `myl` does not do\n\nIf the user asks for any of these, explain that `myl` is read-only and suggest an alternative:\n\n- **Send mail** — use `msmtp`, `sendmail`, `mutt`, or scripted SMTP via Python's `smtplib` / a small `mailx` wrapper.\n- **Move / copy / delete messages** — use `imap-tools` (Python), `imapcli`, or the provider's web UI.\n- **Manage folders / labels** — same as above.\n- **Sync to local maildir** — use `mbsync` (`isync`), `offlineimap`, or `getmail`.\n- **OAuth2 to Gmail / Outlook** — `myl` uses password auth. For OAuth2 the user typically needs Proton Bridge, `mbsync` with an XOAUTH2 helper, or the provider's app-password fallback.\n\nFile v0.1.3:references/recipes.md\n\n# Recipes\n\nCommon multi-step tasks. Each recipe assumes credentials are already configured per `references/authentication.md` (Method A / B / C). Examples invoke `bash scripts/imap.sh`; substitute your alias if you set one up.\n\n## Recipe 1 — Quick inbox check\n\nThe user asks: \"any new email?\" or \"what's in my inbox?\"\n\n```bash\nbash scripts/imap.sh --count 10\n```\n\nThen summarise the result as a short table: date, from, subject. Don't paste full bodies.\n\n## Recipe 2 — Find a specific email and read it\n\nThe user asks: \"find the email from the GitHub team about the security alert.\"\n\n```bash\n# Step 1 — list candidates\nbash scripts/imap.sh --search \"security alert\" --count 20\n\n# Step 2 — once the user picks an ID, or you pick the most plausible candidate,\n# read the body\nMAILID=12345\nbash scripts/imap.sh \"$MAILID\"\n```\n\nIf the search returns many results, list the top 5–10 and ask the user which one. If it returns one obvious match, read it directly and summarise.\n\n## Recipe 3 — Save an attachment\n\nThe user asks: \"download the PDF attached to that invoice email.\"\n\n```bash\n# Step 1 — open the message to see the attachment names\nMAILID=12345\nbash scripts/imap.sh \"$MAILID\"\n\n# Step 2 — pull the named attachment\nATT=\"invoice-2026-04.pdf\"\nDEST=\"$HOME/Downloads/$ATT\"\nbash scripts/imap.sh \"$MAILID\" \"$ATT\" > \"$DEST\"\n\n# Step 3 — verify\nls -lh \"$DEST\"\nfile \"$DEST\"\n```\n\nIf the user didn't specify a destination, default to `~/Downloads/` (Linux/macOS). Never overwrite an existing file silently — check with `[ -e \"$DEST\" ]` first and append a numeric suffix if needed.\n\n## Recipe 4 — Render an HTML email locally\n\nThe user asks: \"show me the actual newsletter, not the plain text.\"\n\n```bash\nMAILID=12345\nHTML_OUT=\"/tmp/mail-${MAILID}.html\"\nbash scripts/imap.sh --html \"$MAILID\" > \"$HTML_OUT\"\necho \"Saved HTML to $HTML_OUT\"\n\n# Optionally open in a browser\nxdg-open \"$HTML_OUT\"   # Linux\nopen      \"$HTML_OUT\"  # macOS\n```\n\nIn an agent context where there's no browser, summarise the HTML in chat after stripping tags:\n\n```bash\npython3 -c \"\nfrom html.parser import HTMLParser\nimport sys\nclass T(HTMLParser):\n    def __init__(self): super().__init__(); self.out=[]\n    def handle_data(self,d): self.out.append(d)\np=T(); p.feed(sys.stdin.read()); print(' '.join(''.join(p.out).split())[:2000])\n\" < \"$HTML_OUT\"\n```\n\n## Recipe 5 — Archive a message as `.eml`\n\nThe user asks: \"I need that email as a file I can forward / archive / re-import.\"\n\n```bash\nMAILID=12345\nEML_OUT=\"$HOME/Documents/email-${MAILID}.eml\"\nbash scripts/imap.sh --raw \"$MAILID\" > \"$EML_OUT\"\nls -lh \"$EML_OUT\"\n```\n\n`.eml` is the standard portable email format — readable by Outlook, Apple Mail, Thunderbird, and most other clients.\n\n## Recipe 6 — Periodic check (one-shot, not a daemon)\n\nThe user asks: \"ping my inbox every 5 minutes for an hour.\"\n\n```bash\nfor i in $(seq 1 12); do\n  echo \"--- $(date) ---\"\n  bash scripts/imap.sh --count 5\n  sleep 300\ndone\n```\n\nFor real persistent monitoring (cron, systemd timers), prefer `mbsync` + `notmuch` or a dedicated tool. The skill is fine for ad-hoc ticks; it's not built to be a long-running mail daemon.\n\n## Recipe 7 — Filter today's mail by sender, locally\n\n`myl --search` is limited to what IMAP SEARCH supports. For more complex filters, fetch a window and post-process:\n\n```bash\nbash scripts/imap.sh --search \"SINCE $(date +%d-%b-%Y)\" --count 100 \\\n  | grep -i \"from.*acme.com\"\n```\n\nIf the server doesn't accept the `SINCE` syntax through `--search`, drop it and filter the full listing locally.\n\n## Recipe 8 — Count unread\n\n```bash\nbash scripts/imap.sh --search \"UNSEEN\" --count 200 \\\n  | grep -c \"^From:\" 2>/dev/null \\\n  || echo \"no unread (or grep pattern needs adjusting for this myl version)\"\n```\n\nThe exact pattern to grep depends on `myl`'s output format on the user's version — check `bash scripts/imap.sh --count 1` output once and adjust.\n\n## Recipe 9 — Multi-account: work + Yandex personal\n\nThe user has two mailboxes — work on a custom domain, personal on Yandex — and wants to check both.\n\nThe right OpenClaw pattern is **two agents, each with its own env**: define separate skill-allowlist agents and assign different `skills.entries.imap-client.env` per agent. But for a quick CLI check inside a single shell, scope the env per subshell so the exports don't pollute the parent:\n\n```bash\n# Work\n(\n  export IMAP_USER='kirill@codd.tech'\n  export IMAP_PASSWORD=\"$WORK_APP_PASSWORD\"\n  export IMAP_PROVIDER='auto'\n  echo \"=== work ===\"\n  bash scripts/imap.sh --count 5\n)\n\n# Personal — Yandex\n(\n  export IMAP_USER='kirill@yandex.ru'\n  export IMAP_PASSWORD=\"$YANDEX_APP_PASSWORD\"\n  export IMAP_PROVIDER='yandex'\n  echo \"=== yandex ===\"\n  bash scripts/imap.sh --count 5\n)\n```\n\nSuggest the user keep the per-account passwords in a password manager and only put them in env vars for the duration of the operation.\n\n## Recipe 10 — Mail.ru: search across the domain group\n\nMail.ru gives one mailbox access to all four domain aliases (`@mail.ru`, `@bk.ru`, `@inbox.ru`, `@list.ru`) under the same account. So a single `imap-client` config covers all of them:\n\n```bash\nexport IMAP_USER='your-name@mail.ru'   # primary login\nexport IMAP_PASSWORD=\"$MAILRU_APP_PASSWORD\"\nexport IMAP_PROVIDER='mailru'\n\nbash scripts/imap.sh --count 20         # see the latest 20 across all aliases\nbash scripts/imap.sh --search \"счёт\"    # works in Russian\n```\n\nNote that Mail.ru's IMAP requires explicit enablement in the web UI (Settings → \"Все настройки\" → \"Почтовые программы\" → IMAP). Without that, `AUTHENTICATIONFAILED` even with a correct app password.\n\n## Recipe 11 — One-off ad-hoc account without touching config\n\nSometimes the user wants to check a colleague's mailbox or a one-off support address without reconfiguring OpenClaw. Use a subshell with inline env, no persistence:\n\n```bash\n(\n  read -r -p \"Username: \" IMAP_USER\n  read -r -s -p \"App password: \" IMAP_PASSWORD; echo\n  export IMAP_USER IMAP_PASSWORD\n  export IMAP_PROVIDER='auto'\n  bash scripts/imap.sh --count 5\n)\n# When the subshell exits, the password disappears with it.\n```\n\nThe `read -s` flag suppresses echo, so the password doesn't appear on screen or in scrollback. It still ends up in process memory of the subshell — that's unavoidable for any command-line IMAP client.\n\nFile v0.1.3:references/troubleshooting.md\n\n# Troubleshooting\n\nSymptom-first lookup. When the skill misbehaves, find the closest match below before guessing.\n\n## Wrapper says \"missing credentials\" but I configured them\n\nThe wrapper checks `$IMAP_USER` and `$IMAP_PASSWORD` in process env. If they're missing in the agent's process, OpenClaw's injection didn't fire. Likely causes:\n\n1. **You edited `~/.openclaw/openclaw.json` mid-session.** OpenClaw snapshots eligible skills *when a session starts*. Restart the agent session (or rely on the skills watcher if `skills.load.watch: true`).\n2. **The skill key in config doesn't match.** Under `skills.entries`, the key must be `imap-client` exactly (or whatever `metadata.openclaw.skillKey` declares — this skill doesn't override it). Hyphens require quoting in JSON5: `\"imap-client\": { ... }`.\n3. **`skills.entries.imap-client.enabled` is `false`** or the skill is disabled by `skills.allowBundled` allowlist.\n4. **The agent has a per-agent skill allowlist that excludes `imap-client`.** Check `agents.list[].skills` in `openclaw.json`.\n5. **You're not on OpenClaw.** Methods B (`export`) and C (`~/.config/imap-client/credentials`) are the right paths for Claude Code or generic AgentSkills runtimes. See `authentication.md`.\n\nTo verify what env the agent actually sees, run:\n\n```bash\nenv | grep -E '^IMAP_' || echo \"no IMAP_* env vars in this process\"\n```\n\nIf that shows nothing in an OpenClaw agent run, the injection isn't reaching the exec context — file a bug against OpenClaw with `metadata.openclaw` excerpt + your `skills.entries` config (passwords redacted).\n\n## `myl: command not found` (non-OpenClaw)\n\nOpenClaw shouldn't load this skill without `myl` because of `requires.bins: [\"myl\"]`. If you see this on Claude Code or another runtime:\n\n1. Installed via `pip install --user` but `~/.local/bin` is not in `PATH`. Add it:\n   ```bash\n   echo 'export PATH=\"$HOME/.local/bin:$PATH\"' >> ~/.bashrc && source ~/.bashrc\n   ```\n2. Installed via `pipx` but `pipx ensurepath` was never run, or the shell wasn't restarted.\n3. Installed in a virtualenv that isn't currently activated.\n4. Not actually installed. `pip show myl` or `pipx list` to confirm.\n\n## `AUTHENTICATIONFAILED` / `Invalid credentials` / `LOGIN failed`\n\nThe username + password combination was rejected. In order of likelihood:\n\n1. **Wrong credential type.** For Gmail, Yandex, Mail.ru, iCloud, Fastmail, Yahoo — the user must use an **app-specific password**, not the account password. See `authentication.md` for the per-provider links.\n2. **IMAP not enabled at the provider.** The classic Yandex/Mail.ru gotcha:\n   - **Yandex Mail:** web UI → Settings → \"Почтовые программы\" → tick \"С сервера imap.yandex.ru по протоколу IMAP\". Without this, login fails even with a correct app password.\n   - **Mail.ru:** \"Все настройки\" → \"Почтовые программы\" → enable IMAP.\n   - **Gmail Workspace:** the org admin sometimes disables IMAP org-wide.\n3. **Wrong username form.** Most providers want the full email (`alice@example.com`). Yandex 360 / business accounts: use the full address on the custom domain, not just the local part.\n4. **2FA without app password.** Provider has 2FA on but the user generated no app password.\n5. **Typo or expired/rotated app password.** Update `IMAP_PASSWORD` in the runtime's config.\n\n## `SSL: CERTIFICATE_VERIFY_FAILED` / `[SSL: WRONG_VERSION_NUMBER]`\n\nTLS handshake problem.\n\n- `WRONG_VERSION_NUMBER` usually means the wrong port + transport combination. Trying STARTTLS against an IMAPS port (993), or implicit TLS against a STARTTLS port (143), produces this. With `IMAP_PROVIDER=manual`:\n  - port 993, no `IMAP_STARTTLS` (implicit TLS) — the default\n  - port 143 with `IMAP_STARTTLS=1` (explicit upgrade)\n- `CERTIFICATE_VERIFY_FAILED` on a self-hosted server usually means the server uses a self-signed cert. There is no documented `--insecure` flag in `myl`. The proper fix is to add the server's CA to the system trust store. Don't work around this for a third party's server without confirming with the user — it's a real warning.\n\n## `imaplib.error: command SEARCH illegal in state AUTH`\n\n`myl` tried to search before selecting a folder. Pass `--folder INBOX` (or whichever folder) explicitly.\n\n## `BAD [CLIENTBUG]` / `Search criteria not supported`\n\nThe IMAP search expression is malformed or the server doesn't support that key. Simplify to a single quoted word and re-test:\n\n```bash\nbash scripts/imap.sh --search \"invoice\" --count 20\n```\n\nIf a single word works, build complexity back up gradually. See the supported-keys table in `operations.md`.\n\n## Autodiscovery (`IMAP_PROVIDER=auto`) fails\n\n`myl --auto` couldn't determine server + port from the username domain. Switch to a specific provider mode or `manual`:\n\n```bash\n# In config:\n\"IMAP_PROVIDER\": \"yandex\"   # or \"gmail\", \"mailru\", or \"manual\" + IMAP_SERVER\n```\n\nCommon providers with their IMAP endpoints:\n\n| Provider | Server | Port | `IMAP_PROVIDER` |\n|---|---|---|---|\n| Gmail | imap.gmail.com | 993 | `gmail` |\n| Yandex | imap.yandex.com | 993 | `yandex` |\n| Mail.ru | imap.mail.ru | 993 | `mailru` |\n| iCloud | imap.mail.me.com | 993 | `manual` |\n| Fastmail | imap.fastmail.com | 993 | `auto` (works) or `manual` |\n| Outlook.com | outlook.office365.com | 993 | basic auth deprecated; check provider |\n| Yahoo | imap.mail.yahoo.com | 993 | `manual` |\n| Proton (Bridge) | 127.0.0.1 | 1143 | `manual` |\n\n## Connection times out / hangs\n\n- The IMAP port is blocked by a network firewall (common on corporate / hotel WiFi). Test with `nc -vz <host> 993` or `openssl s_client -connect <host>:993`.\n- The server is reachable but slow. Add a timeout wrapper:\n  ```bash\n  timeout 30 bash scripts/imap.sh --count 5\n  ```\n- The server is geo-blocking. Yandex and Mail.ru sometimes throttle / block traffic from certain regions. Try from a different network or via VPN.\n\n## \"Folder not found\" / `NO Mailbox does not exist`\n\nFolder names are case-sensitive and provider-specific. Run with no `--folder` and inspect what the listing surfaces. Common gotchas:\n\n- **Gmail:** `[Gmail]/All Mail` — exact, including brackets and space.\n- **Yandex:** prefer English aliases `Sent` / `Drafts` / `Trash` over the Russian `Отправленные` / `Черновики` / `Удалённые`. Both work, but Cyrillic is sometimes UTF-7 encoded in IMAP.\n- **Mail.ru:** internal IMAP names are English even when the web UI shows Russian.\n- **Custom Cyrillic folders:** pass the exact string `myl` shows in listings, not the human-readable name from the web client.\n\n## Large mailbox is slow\n\n`--count 1000` against a large folder is going to be slow. Server response times for IMAP `FETCH` of message metadata scale roughly linearly. Cap requests at 50–100 and paginate if the user needs more.\n\n## Wrapper says perms warning, ignores creds file\n\nThe wrapper refuses to source `~/.config/imap-client/credentials` (or `$IMAP_CREDENTIALS_FILE`) unless it's `chmod 600` or `chmod 400`. Fix:\n\n```bash\nchmod 600 ~/.config/imap-client/credentials\n```\n\nThis is intentional. A world-readable creds file would be a bigger security regression than the slight inconvenience.\n\n## `myl --version` works but commands fail mysteriously\n\nCould be a stale install. Reinstall:\n\n```bash\npipx reinstall myl\n# or\npip install --user --upgrade --force-reinstall myl\n```\n\nIf reinstall doesn't fix it, file the bug upstream at https://github.com/pschmitt/myl/issues with the failing command (passwords redacted) and `myl --version`.\n\n## Nothing matches the symptom\n\nRun `myl --help` to confirm the version supports the flag the user expects. Then run the command again with shell tracing on:\n\n```bash\nset -x\nbash scripts/imap.sh --count 5\nset +x\n```\n\nIf the issue is server-side, raw `openssl s_client` against the IMAP port often surfaces the actual error:\n\n```bash\n( set +o history; openssl s_client -connect imap.yandex.com:993 -crlf )\n# Then type:  a1 LOGIN you@yandex.ru app-specific-password\n# CTRL+D to disconnect\n```\n\nThe `set +o history` keeps the password out of the shell history file. The session itself is TLS-encrypted to the server.\n\nFile v0.1.3:skill-card.md\n\n## Description:\n\nRead, search, and download email over IMAP from the command line using the `myl` CLI client.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[aggrrrh](https://clawhub.ai/user/aggrrrh)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers, operators, and external users use this skill to let an agent check inboxes, search mailbox contents, read selected messages, and save attachments through a configured read-only IMAP CLI workflow.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The configured mailbox becomes accessible to the agent while the skill is enabled.\n\nMitigation: Install only when that access is acceptable, use a narrowly scoped app password, and prefer short-lived environment injection or OpenClaw SecretRef for credentials.\n\nRisk: Mailbox credentials can be exposed through unsafe argument forwarding or process inspection while the IMAP client runs.\n\nMitigation: Avoid shared or monitored machines and do not allow user-supplied connection or authentication flags until the wrapper validates or rejects them.\n\nRisk: The skill depends on the third-party `myl` package for mailbox access.\n\nMitigation: Pin or review the `myl` dependency before use.\n\n## Reference(s):\n\n- [ClawHub skill page](https://clawhub.ai/aggrrrh/skills/imap-client)\n- [Authentication and connection](references/authentication.md)\n- [Installation](references/installation.md)\n- [Operations](references/operations.md)\n- [Recipes](references/recipes.md)\n- [Troubleshooting](references/troubleshooting.md)\n- [myl IMAP CLI](https://github.com/pschmitt/myl)\n- [OpenClaw skills documentation](https://docs.openclaw.ai/tools/skills)\n\n## Skill Output:\n\n**Output Type(s):** [text, markdown, shell commands, configuration, guidance, files]\n\n**Output Format:** [Markdown summaries with inline shell commands, configuration snippets, and local file paths]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [May create local .eml, .html, or attachment files when the user asks to save message content.]\n\n## Skill Version(s):\n\n0.1.3 (source: server release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v0.1.2: 10 files, 27495 bytes\n\nFiles: README.md (8149b), references/authentication.md (8797b), references/installation.md (3734b), references/operations.md (8075b), references/recipes.md (6338b), references/troubleshooting.md (8165b), scripts/check_myl.sh (979b), scripts/imap.sh (4090b), SKILL.md (8711b), _meta.json (130b)\n\nFile v0.1.2:SKILL.md\n\n---\nname: imap-client\ndescription: 'Read, search, and download email over IMAP from the command line using the `myl` CLI client. Use this skill whenever the user wants to interact with their mailbox from a terminal — checking the inbox, listing or searching messages, reading a specific email, opening HTML or raw source, or saving attachments. Trigger on any of these cues even when `myl` is not named explicitly — \"check my email\", \"look in my inbox\", \"search my mail for X\", \"find the email from Y\", \"download the attachment\", \"is there an email about Z\", \"read the latest message\", \"show me unread\", \"connect to my IMAP server\", \"imap.gmail.com\", \"imap.yandex.com\", \"imap.yandex.ru\", \"imap.mail.ru\", \"imap.fastmail.com\", \"Yandex Mail\", \"Mail.ru\", \"Gmail IMAP\", \"проверить почту\", \"новые письма\", \"найти письмо\", and similar. Also trigger when the user asks to script or automate any of the above. Do not trigger for outgoing mail (sending, SMTP, drafting) — `myl` is read-only — or for desktop/GUI mail clients.'\nlicense: MIT\nhomepage: https://github.com/codd-tech/imap-client\nmetadata: {\"openclaw\":{\"emoji\":\"📬\",\"requires\":{\"bins\":[\"myl\"],\"env\":[\"IMAP_USER\",\"IMAP_PASSWORD\"]},\"primaryEnv\":\"IMAP_PASSWORD\",\"install\":[{\"id\":\"pipx\",\"kind\":\"pipx\",\"package\":\"myl\",\"bins\":[\"myl\"],\"label\":\"Install myl via pipx\"}]}}\n---\n\n# imap-client\n\nRead mailboxes over IMAP from the terminal using `myl`, a small Python CLI client. Maintained and distributed by [codd-tech](https://github.com/codd-tech/imap-client). Designed to drop into [OpenClaw](https://openclaw.ai) and any other AgentSkills-compatible runtime (Claude Code, generic).\n\n`myl` is read-only and intentionally minimal: it lists, searches, and fetches messages and attachments. It does not send mail, manage folders, or modify state beyond optionally marking messages as seen.\n\n## How credentials reach this skill\n\nThis is the most important section. **You do not type passwords on the command line.** Credentials live in environment variables that the runtime injects per agent run. The skill reads them and assembles the right `myl` flags through the wrapper at `{baseDir}/scripts/imap.sh`.\n\nThe variables the wrapper expects:\n\n| Variable | Required | Purpose |\n|---|---|---|\n| `IMAP_USER` | yes | Login (usually full email address) |\n| `IMAP_PASSWORD` | yes | App-specific password (see `references/authentication.md`) |\n| `IMAP_PROVIDER` | no | One of `auto` (default), `gmail`, `yandex`, `mailru`, `manual` |\n| `IMAP_SERVER` | only with `manual` | IMAP host |\n| `IMAP_PORT` | no | Defaults to 993 |\n| `IMAP_STARTTLS` | no | `1` to add `--starttls` (use only with port 143) |\n\n**Set them once, use them every session.** How depends on the runtime — `references/authentication.md` covers OpenClaw's `skills.entries.imap-client.env`, generic shell `export`, and a `~/.config/imap-client/credentials` fallback file. Do not invent your own scheme; use one of those three.\n\nIf the wrapper detects `IMAP_USER` or `IMAP_PASSWORD` is missing, it prints the setup instructions and exits without contacting any server. That's the signal to stop and walk the user through credential setup before retrying.\n\n## Workflow at a glance\n\n1. **Check that `myl` is installed.** OpenClaw gates this skill on `requires.bins: [\"myl\"]`, so it shouldn't load without it. For non-OpenClaw runtimes, run `bash {baseDir}/scripts/check_myl.sh`. If missing, follow `references/installation.md`.\n2. **Confirm credentials are configured.** Run `bash {baseDir}/scripts/imap.sh --count 1 >/dev/null` once. Success means the env vars are wired and the connection works. Failure means walk the user through `references/authentication.md`.\n3. **Run the requested operation** through the wrapper. Listing, searching, fetching by ID, getting HTML, saving raw `.eml`, or pulling an attachment.\n4. **Summarise the result.** Don't dump full raw email bodies into the chat unless the user asked.\n\nEvery `myl` example in this skill goes through `{baseDir}/scripts/imap.sh`, which expands env vars into the right `myl` flags. You do not need to remember `--google` vs `--auto` vs `--server`/`--port`; the wrapper picks based on `IMAP_PROVIDER`.\n\n## When to read what\n\n| Task involves… | Read |\n|---|---|\n| Detecting or installing `myl`, OpenClaw `requires.bins` gating | `references/installation.md` |\n| Setting up credentials, choosing connection mode, app passwords for Gmail / Yandex / Mail.ru / iCloud / Fastmail | `references/authentication.md` |\n| Any specific CLI flag, listing, searching, fetching, attachments, provider-specific folder names | `references/operations.md` |\n| Multi-step recipes (e.g. \"find the invoice from Acme last month and save the PDF\") | `references/recipes.md` |\n| Errors like SSL failures, \"command not found\", autodiscovery failing, \"AUTHENTICATIONFAILED\", env vars not visible to the wrapper | `references/troubleshooting.md` |\n\n## Principles\n\n### 1. Credentials never appear in commands you generate\n\nBecause env vars are injected by the runtime, the wrapper handles them internally. **Do not** generate commands like `myl -p hunter2` or `myl -p \"$IMAP_PASSWORD\"` directly — both leak. The first lands in shell history; the second exposes the password in `/proc/<pid>/cmdline` while myl runs. Use the wrapper, which keeps the password inside its own process scope:\n\n```bash\nbash {baseDir}/scripts/imap.sh --count 5\n```\n\nThe wrapper passes credentials to `myl` via stdin where supported and otherwise via flags it constructs internally — same trade-off as direct `myl` use, but the password literal never appears in any command you wrote, logged, or showed the user.\n\n### 2. Default to small result sets\n\nWhen the user's intent is exploratory (\"any new mail?\"), pass `--count 5` or `--count 10`. Only fetch larger windows on explicit request. This keeps output readable and avoids dumping sensitive content the user didn't ask to see.\n\n### 3. Don't mark as seen by accident\n\n`--mark-seen` mutates state on the server. Only pass it when the user explicitly asked to mark messages read. Listing or reading without this flag is non-destructive.\n\n### 4. Render long bodies to a file, summarise in chat\n\nWhen the user fetches a long message or HTML email, save the raw output to a file (e.g. `/tmp/email-<id>.eml` or `.html`) and give the user a 2–4 sentence summary plus the file path. Do not paste a 500-line HTML body into the conversation.\n\n### 5. Search syntax is server-side IMAP, not Gmail's web UI\n\n`--search \"important\"` issues an IMAP `SEARCH` command. It does not understand Gmail's `from:`, `has:attachment`, or `label:` operators. For complex filtering, fetch a reasonable window with `--count` and filter the listing locally. See `references/operations.md` for what IMAP `SEARCH` supports.\n\n### 6. Never echo, summarise, or persist the password\n\nWhen summarising what you did, refer to the credential as `IMAP_PASSWORD` or \"the password from your OpenClaw config\", never the literal value. If the user pastes a password into chat by mistake, treat it as compromised: tell them to rotate it and update their config. Do not write it to any artifact.\n\n## Quick decision tree\n\n```\nUser asked something email-related from the CLI\n  │\n  ├─ Is `myl` installed and on PATH?  ── No  ──► references/installation.md\n  │   │\n  │   Yes\n  │   ▼\n  ├─ Does the wrapper smoke-test pass?\n  │     bash {baseDir}/scripts/imap.sh --count 1 >/dev/null\n  │   │                       No  ──► references/authentication.md\n  │   Yes\n  │   ▼\n  ├─ What does the user want?\n  │   ├─ Browse / list           ──► imap.sh --count N [--folder F]\n  │   ├─ Search                  ──► imap.sh --search \"TERM\" [--count N]\n  │   ├─ Read one message        ──► imap.sh \"$MAILID\"\n  │   ├─ Read HTML version       ──► imap.sh --html \"$MAILID\"  → save to file\n  │   ├─ Save raw .eml           ──► imap.sh --raw \"$MAILID\" > file.eml\n  │   ├─ Get attachment          ──► imap.sh \"$MAILID\" \"$ATT_NAME\" > file\n  │   └─ Anything multi-step     ──► references/recipes.md\n  │\n  └─ Errors? ─────────────────────► references/troubleshooting.md\n```\n\n## Output style\n\nAfter running the wrapper, present results in this shape:\n\n- **One-line status** of what just ran (e.g. \"Listed the 10 most recent messages in INBOX\").\n- **A compact table or bullet list** of message metadata (date, from, subject, ID).\n- **Any file paths** where larger output was saved.\n- **Suggested next actions** (e.g. \"Want me to open #4582 or save its attachments?\").\n\nKeep it scannable.\n\nFile v0.1.2:README.md\n\n# imap-client\n\n[![Install via ClawHub](https://img.shields.io/badge/install-clawhub-2563eb?style=flat-square)](https://clawhub.ai/aggrrrh/imap-client)\n[![License: MIT](https://img.shields.io/github/license/codd-tech/imap-client?style=flat-square)](./LICENSE)\n[![Maintained by codd.tech](https://img.shields.io/badge/maintained%20by-codd.tech-f97316?style=flat-square)](https://codd.tech)\n[![Stars](https://img.shields.io/github/stars/codd-tech/imap-client?style=flat-square)](https://github.com/codd-tech/imap-client/stargazers)\n\nAn agent skill for [OpenClaw](https://openclaw.ai), Claude Code, and other AgentSkills-compatible runtimes. Lets the agent read, search, and download email over IMAP from the command line via the [`myl`](https://github.com/pschmitt/myl) CLI client.\n\n`myl` is a small read-only IMAP client. This skill teaches the agent **when** to reach for it, **how** to install it, **how to source credentials safely** from the runtime's environment-injection mechanism, and **which** flags to use for common tasks — without ever asking for the password mid-session.\n\n## What this skill enables\n\nOnce installed and configured once, the agent will recognise prompts like:\n\n- *\"check my inbox\"*\n- *\"any new email from Acme today?\"*\n- *\"find the email with the AWS invoice and save the PDF\"*\n- *\"show me the HTML version of the newsletter from yesterday\"*\n- *\"download all unread messages as `.eml` files\"*\n- *\"проверь почту на Яндексе\"*\n- *\"найди письмо от налоговой\"*\n\n…and translate them into safe `myl` invocations through the wrapper at `scripts/imap.sh`, summarising the result back in chat.\n\n## Provider support\n\nFirst-class support, with `IMAP_PROVIDER` shortcuts:\n\n- **Gmail** / Google Workspace (`IMAP_PROVIDER=gmail`)\n- **Yandex Mail** — `@yandex.ru`, `@yandex.com`, Yandex 360 custom domains (`IMAP_PROVIDER=yandex`)\n- **Mail.ru** — `@mail.ru`, `@bk.ru`, `@inbox.ru`, `@list.ru` (`IMAP_PROVIDER=mailru`)\n\nPlus autodiscovery for most other providers (Fastmail, iCloud, ISPs) and explicit `manual` mode for self-hosted / corporate servers.\n\n## Quick start\n\n### 1. Install `myl`\n\n```bash\npipx install myl\n```\n\n(Or `pip install --user myl`, or `nix run github:pschmitt/myl`.)\n\n### 2. Get an app-specific password from your provider\n\nAccount settings → app passwords / external app passwords. Direct links per provider in [`references/authentication.md`](./references/authentication.md).\n\n### 3. Install the skill\n\n**Recommended — via ClawHub:**\n\n```bash\nclawhub install imap-client\n```\n\n**Or clone directly:**\n\n```bash\n# OpenClaw\ngit clone https://github.com/codd-tech/imap-client ~/.openclaw/skills/imap-client\n\n# Claude Code\ngit clone https://github.com/codd-tech/imap-client ~/.claude/skills/imap-client\n\n# Generic AgentSkills runtime — drop the folder anywhere the runtime scans for SKILL.md\n```\n\nRestart the session. OpenClaw picks the skill up automatically. The skill declares `requires.bins: [\"myl\"]` so it filters itself out if `myl` isn't on `PATH` — you'll never get a half-broken state.\n\n### 4. Configure credentials — pick the method for your runtime\n\n**OpenClaw** (recommended for OpenClaw users) — edit `~/.openclaw/openclaw.json`:\n\n```json\n{\n  \"skills\": {\n    \"entries\": {\n      \"imap-client\": {\n        \"enabled\": true,\n        \"env\": {\n          \"IMAP_USER\": \"you@yandex.ru\",\n          \"IMAP_PASSWORD\": \"app-specific-password-here\",\n          \"IMAP_PROVIDER\": \"yandex\"\n        }\n      }\n    }\n  }\n}\n```\n\n```bash\nchmod 600 ~/.openclaw/openclaw.json\n```\n\nOpenClaw injects these into `process.env` per agent run. You configure once; every subsequent session has them.\n\n**Claude Code / generic shell** — export in `~/.bashrc` / `~/.zshrc`:\n\n```bash\nexport IMAP_USER='you@yandex.ru'\nexport IMAP_PASSWORD='app-specific-password-here'\nexport IMAP_PROVIDER='yandex'\n```\n\n**Headless / cron / fallback** — create `~/.config/imap-client/credentials`:\n\n```bash\nmkdir -p ~/.config/imap-client\ncat > ~/.config/imap-client/credentials <<'EOF'\nIMAP_USER='you@yandex.ru'\nIMAP_PASSWORD='app-specific-password-here'\nIMAP_PROVIDER='yandex'\nEOF\nchmod 600 ~/.config/imap-client/credentials\n```\n\nThe wrapper refuses to source this file if its permissions are not `600` or `400`.\n\n### 5. Verify\n\nAsk the agent something like *\"check the latest five emails\"* — or run the wrapper directly:\n\n```bash\nbash ~/.openclaw/skills/imap-client/scripts/imap.sh --count 5\n```\n\n## Repo layout\n\n```\nimap-client/\n├── SKILL.md                       # Frontmatter + workflow + principles\n├── README.md                      # This file\n├── LICENSE                        # MIT\n├── .gitignore\n├── references/\n│   ├── installation.md            # pipx / pip / nix / source install paths + sandbox\n│   ├── authentication.md          # OpenClaw env injection + fallbacks; provider table\n│   ├── operations.md              # Full myl flag reference + folder names per provider\n│   ├── recipes.md                 # 11 multi-step workflows, including Yandex/Mail.ru\n│   └── troubleshooting.md         # Symptom-first error guide\n└── scripts/\n    ├── imap.sh                    # Credential-aware wrapper around myl\n    └── check_myl.sh               # Fast install detection\n```\n\n## Security model\n\nThe skill is opinionated about credentials. The short version:\n\n- Passwords never appear as literals in commands the agent generates.\n- The runtime's environment-injection mechanism (OpenClaw `skills.entries.<key>.env`, or shell `export`, or the `chmod 600` creds file) is the source of truth.\n- The `imap.sh` wrapper reads env vars and constructs `myl` flags internally — the password is in the wrapper's process scope, never in the agent's command history.\n- App-specific passwords from each provider are the default recommendation; the skill explains where to generate them (Gmail, Yandex, Mail.ru, iCloud, Fastmail, Yahoo).\n- The agent is instructed not to echo, summarise, or persist the password anywhere.\n- For OpenClaw users, `apiKey` with a `SecretRef` (`{ source, provider, id }`) keeps the literal password out of `openclaw.json` entirely.\n\nSee [`references/authentication.md`](./references/authentication.md) for the full ruleset.\n\n## Limitations of `myl` itself\n\n`myl` is intentionally minimal. The skill will tell the user explicitly when their request is out of scope and suggest alternatives:\n\n| Want to… | Use instead |\n|---|---|\n| Send mail | `msmtp`, `mutt`, scripted SMTP |\n| Move / delete / label | `imap-tools`, the provider's web UI |\n| Sync to local maildir | `mbsync` (`isync`), `offlineimap`, `getmail` |\n| OAuth2 to Gmail / Outlook | Proton Bridge, `mbsync` + XOAUTH2, or app password fallback |\n\n## Contributing\n\nBug reports and PRs welcome. The skill itself is markdown plus two shell scripts — easy to read, easy to fork.\n\nWhen proposing changes, prefer:\n\n- additions to `references/` over additions to `SKILL.md` (keep the always-loaded part lean)\n- examples that don't paste credentials anywhere\n- behaviour changes that fail safely if the user's `myl` version is older than the skill assumes\n\n## Credits\n\n- [`myl`](https://github.com/pschmitt/myl) by Philipp Schmitt — the underlying CLI this skill wraps.\n- [OpenClaw](https://openclaw.ai) for the AgentSkills runtime, env injection mechanism, and skills format documented at https://docs.openclaw.ai/tools/skills.\n- Anthropic's [Skills documentation](https://docs.claude.com/en/docs/build-with-claude/skills) — structure and best-practice patterns.\n\n## About the maintainer\n\nBuilt and maintained by **[codd.tech](https://codd.tech)** — a boutique technical consultancy specialising in AI agent infrastructure, distributed systems, and platform engineering. We help product teams ship reliable agentic workflows in production: integration design, custom skill packs, OpenClaw / Claude / MCP deployments, and DevOps audits.\n\nHave a use case for agent-driven email automation, or want a custom skill built for your stack? **[Get in touch](https://codd.tech)**.\n\n## License\n\nMIT — see [`LICENSE`](./LICENSE).\n\nFile v0.1.2:_meta.json\n\n{\n  \"ownerId\": \"kn78q4f09z7as2hbshyxss9sk185ht5d\",\n  \"slug\": \"imap-client\",\n  \"version\": \"0.1.2\",\n  \"publishedAt\": 1777154306397\n}\n\nFile v0.1.2:references/authentication.md\n\n# Authentication & Connection\n\nThis is the most security-sensitive part of the skill. Read it before configuring credentials anywhere.\n\n## The model in one paragraph\n\nCredentials live as **environment variables** that the runtime injects per agent run. The wrapper at `scripts/imap.sh` reads those env vars, picks the right `myl` connection flags, and never echoes the password. **You configure once, you read mail forever.**\n\n## Setting up credentials — pick one method\n\n### Method A — OpenClaw (recommended for OpenClaw users)\n\nOpenClaw injects `skills.entries.<key>.env` into `process.env` for the duration of each agent turn, then restores the original environment. This is documented behaviour: see https://docs.openclaw.ai/tools/skills under \"Environment injection (per agent run)\".\n\nEdit `~/.openclaw/openclaw.json` and add an entry under `skills.entries`:\n\n```json\n{\n  \"skills\": {\n    \"entries\": {\n      \"imap-client\": {\n        \"enabled\": true,\n        \"env\": {\n          \"IMAP_USER\": \"you@example.com\",\n          \"IMAP_PASSWORD\": \"app-specific-password-here\",\n          \"IMAP_PROVIDER\": \"auto\"\n        }\n      }\n    }\n  }\n}\n```\n\nThen restart the agent session (or wait for the skills watcher to pick it up if `skills.load.watch` is enabled). The next time the agent runs the skill, `IMAP_USER` and `IMAP_PASSWORD` are already in the environment.\n\n**Permissions matter.** `~/.openclaw/openclaw.json` should not be world-readable:\n\n```bash\nchmod 600 ~/.openclaw/openclaw.json\n```\n\n**Use `apiKey` with a SecretRef for stronger isolation.** OpenClaw supports pulling the password from a separate source rather than inlining it as plaintext in the JSON:\n\n```json\n{\n  \"skills\": {\n    \"entries\": {\n      \"imap-client\": {\n        \"enabled\": true,\n        \"apiKey\": { \"source\": \"env\", \"provider\": \"default\", \"id\": \"MY_IMAP_PASSWORD\" },\n        \"env\": {\n          \"IMAP_USER\": \"you@example.com\",\n          \"IMAP_PROVIDER\": \"auto\"\n        }\n      }\n    }\n  }\n}\n```\n\nThe `apiKey` field maps to whatever env var name is declared in `metadata.openclaw.primaryEnv` of `SKILL.md` — for this skill that's `IMAP_PASSWORD`. So OpenClaw reads `MY_IMAP_PASSWORD` from your shell env (or another secret backend) and exposes it as `IMAP_PASSWORD` to the wrapper. The literal password never appears in `openclaw.json`.\n\n### Method B — Generic shell `export`\n\nFor Claude Code and other AgentSkills runtimes that don't have OpenClaw's injection mechanism, just export the variables in the shell that launches the agent:\n\n```bash\nexport IMAP_USER='you@example.com'\nexport IMAP_PASSWORD='app-specific-password-here'\nexport IMAP_PROVIDER='auto'\n```\n\nPut this in `~/.bashrc` / `~/.zshrc` if you want it to persist. The downside compared to Method A is that the variables are global to that shell, not scoped to the agent run. The upside is no extra config file.\n\n### Method C — Credentials file fallback\n\nWhen neither Method A nor B is convenient (e.g. cron jobs, headless workflows, CI), drop a credentials file at `~/.config/imap-client/credentials`:\n\n```bash\nmkdir -p ~/.config/imap-client\ncat > ~/.config/imap-client/credentials <<'EOF'\nIMAP_USER='you@example.com'\nIMAP_PASSWORD='app-specific-password-here'\nIMAP_PROVIDER='auto'\nEOF\nchmod 600 ~/.config/imap-client/credentials\n```\n\nThe wrapper sources this file when `IMAP_USER`/`IMAP_PASSWORD` are not in the env, **but only if permissions are 600 or 400**. World-readable creds files are ignored with a warning.\n\nTo use a different path, set `IMAP_CREDENTIALS_FILE` in env.\n\n## Per-account: switching mailboxes\n\nFor multiple accounts, declare each one as a separate OpenClaw skill entry under a different agent (per-agent skill allowlists make this clean), or scope the env per shell:\n\n```bash\n# Work\n( export IMAP_USER='kirill@codd.tech' \\\n         IMAP_PASSWORD=\"$WORK_APP_PASSWORD\" \\\n         IMAP_PROVIDER='auto' ; \\\n  bash scripts/imap.sh --count 5 )\n\n# Personal\n( export IMAP_USER='kirill@yandex.ru' \\\n         IMAP_PASSWORD=\"$YANDEX_APP_PASSWORD\" \\\n         IMAP_PROVIDER='yandex' ; \\\n  bash scripts/imap.sh --count 5 )\n```\n\nThe parentheses create a subshell so the exports don't pollute your main session.\n\n## `IMAP_PROVIDER` — what to set\n\n| Value | Effect | When to use |\n|---|---|---|\n| `auto` (default) | `myl --auto` — autodiscovery from username domain | Most modern providers (Fastmail, iCloud, ISPs) |\n| `gmail` | `myl --google` — hardcoded Gmail IMAP | `@gmail.com` / Google Workspace accounts |\n| `yandex` | `--server imap.yandex.com --port 993` | Yandex Mail (`@yandex.ru`, `@yandex.com`, custom domains) |\n| `mailru` | `--server imap.mail.ru --port 993` | Mail.ru (`@mail.ru`, `@bk.ru`, `@inbox.ru`, `@list.ru`) |\n| `manual` | `--server $IMAP_SERVER --port $IMAP_PORT [--starttls]` | Self-hosted, corporate, or anything autodiscovery doesn't recognise |\n\n## App passwords — the credential the user actually needs\n\nAlmost no major provider accepts the account password over IMAP anymore when 2FA is enabled. They require an **app-specific password** generated from the account settings.\n\n| Provider | Where to generate | Notes |\n|---|---|---|\n| **Gmail / Google Workspace** | https://myaccount.google.com/apppasswords | Requires 2-Step Verification on. If the link 404s, your account or organisation has app passwords disabled — switch provider or ask admin. |\n| **Yandex Mail** | https://id.yandex.ru/security/app-passwords | Pick \"Mail (IMAP/POP3, SMTP)\". Works for `@yandex.ru`, `@yandex.com`, and custom domains hosted on Yandex 360. |\n| **Mail.ru** | Account → \"Пароли для внешних приложений\" / \"Passwords for external applications\" | Same password works for `@mail.ru`, `@bk.ru`, `@inbox.ru`, `@list.ru`. |\n| **Fastmail** | Settings → Privacy & Security → App Passwords | Can scope to \"IMAP only\" for least privilege. |\n| **iCloud** | https://appleid.apple.com → Sign-In and Security → App-Specific Passwords | Username is your Apple ID email, even if you use an `@icloud.com` alias. |\n| **Yahoo** | Account Security → Generate app password | |\n| **Proton Mail** | Requires Proton Bridge running locally | Use `IMAP_PROVIDER=manual`, `IMAP_SERVER=127.0.0.1`, `IMAP_PORT=1143`. |\n| **Outlook.com** | Microsoft has been deprecating basic auth | If app passwords are disabled, use `mbsync` with XOAUTH2 instead. `myl` does not do OAuth2. |\n\nWhen the IMAP server returns `AUTHENTICATIONFAILED` and the username is one of the providers above, the cause is almost always that the user is trying their account password instead of an app password. Direct them to the relevant URL and explain why.\n\n## Yandex specifics\n\nYandex Mail is widely used in Russian-speaking contexts and has a few quirks worth knowing:\n\n- **Two server hostnames exist.** `imap.yandex.com` and `imap.yandex.ru` both work; `IMAP_PROVIDER=yandex` defaults to `.com` which serves both account types correctly. To force `.ru`, set `IMAP_SERVER=imap.yandex.ru`.\n- **Mailbox features must be enabled in Yandex web UI.** Settings → \"Почтовые программы\" → tick \"С сервера imap.yandex.ru по протоколу IMAP\". Without this, IMAP login fails with `AUTHENTICATIONFAILED` even with the right app password.\n- **Yandex 360 / business accounts (`@your-company.ru` hosted on Yandex)** use the same `imap.yandex.com:993` endpoint and the same app password mechanism.\n- **Folder names are localised.** See `references/operations.md` for the Russian folder name table.\n\n## Mail.ru specifics\n\n- **One app password covers the whole domain group** — the same credential works against `@mail.ru`, `@bk.ru`, `@inbox.ru`, `@list.ru` if you own multiple addresses on the platform.\n- **IMAP must be explicitly enabled in account settings.** Mail.ru settings → \"Все настройки\" → \"Почтовые программы\" → enable IMAP. Same gotcha as Yandex.\n\n## What to do if the user pastes a password into chat\n\nTreat it as compromised. The password may now sit in:\n\n- the chat transcript / conversation log\n- any analytics or telemetry the runtime captured\n- the user's clipboard history\n\n**Tell the user explicitly:** \"That password is now in the chat history. Rotate it (regenerate the app password from the provider) and put the new one into your `~/.openclaw/openclaw.json` config — not into chat.\" Then walk them through Method A above.\n\nDo not echo the password back, do not write it to any file, do not include it in a summary, and do not silently reuse it for the rest of the session.\n\n## Smoke test\n\nOnce credentials are configured, confirm the connection works with a minimal call:\n\n```bash\nbash scripts/imap.sh --count 1 >/dev/null && echo \"connection OK\"\n```\n\nIf this prints `connection OK`, every other operation in `references/operations.md` will work the same way.\n\nFile v0.1.2:references/installation.md\n\n# Installation\n\n`myl` is a Python package. There are several ways to install it; pick the first one that fits the user's environment.\n\n## How OpenClaw handles this\n\nThis skill declares `requires.bins: [\"myl\"]` in `metadata.openclaw`. OpenClaw checks for `myl` on `PATH` at skill load time and **silently filters this skill out** if it's missing, preventing the agent from invoking it without a working binary.\n\nIt also declares an `install` block:\n\n```json\n{ \"id\": \"pipx\", \"kind\": \"pipx\", \"package\": \"myl\", \"bins\": [\"myl\"] }\n```\n\nIn OpenClaw's macOS Skills UI this surfaces a one-click install button. From the CLI the user installs `myl` themselves with one of the methods below — the install block is hint metadata, not an automated runtime installer.\n\nFor non-OpenClaw runtimes (Claude Code, generic), there's no automatic gating. Run `bash scripts/check_myl.sh` first to confirm `myl` is present.\n\n## Detect what's already there\n\nAlways check before installing:\n\n```bash\nbash scripts/check_myl.sh\n```\n\nOr inline:\n\n```bash\nif command -v myl >/dev/null 2>&1; then\n  echo \"myl is installed: $(command -v myl) ($(myl --version 2>/dev/null || echo 'version unknown'))\"\nelse\n  echo \"myl is not on PATH\"\nfi\n```\n\nIf `myl` is present, skip the rest of this file and move on to `authentication.md`.\n\n## Install paths, in order of preference\n\n### `pipx` — recommended\n\nIsolates `myl` and its dependencies from system Python. This is what the upstream README recommends and what the skill's `install` metadata suggests.\n\n```bash\n# Install pipx itself if missing (Debian/Ubuntu)\nsudo apt update && sudo apt install -y pipx\npipx ensurepath\n\n# Install myl\npipx install myl\n```\n\nOn macOS:\n\n```bash\nbrew install pipx\npipx ensurepath\npipx install myl\n```\n\nAfter `pipx ensurepath`, the user may need to restart their shell or `source ~/.bashrc` / `source ~/.zshrc` for `myl` to appear on `PATH`.\n\n### `pip --user` — fallback when `pipx` isn't available\n\n```bash\npip install --user myl\n```\n\nThe binary lands in `~/.local/bin`, which must be on `PATH`. If not:\n\n```bash\necho 'export PATH=\"$HOME/.local/bin:$PATH\"' >> ~/.bashrc\n```\n\n### Nix flake — for Nix users\n\n```bash\n# One-shot run without installing\nnix run github:pschmitt/myl -- --help\n\n# Or add to a flake\n```\n\n### From source\n\n```bash\ngit clone https://github.com/pschmitt/myl.git\ncd myl\npipx install .\n```\n\n## Sandboxed agent runs\n\nIf the agent runs inside a Docker sandbox (OpenClaw `agents.defaults.sandbox.docker`), `myl` must be installed **inside the container** as well — the host bin doesn't satisfy the in-sandbox requirement. Add to `setupCommand`:\n\n```json\n{\n  \"agents\": {\n    \"defaults\": {\n      \"sandbox\": {\n        \"docker\": {\n          \"setupCommand\": \"pipx install myl || pip install --user --break-system-packages myl\"\n        }\n      }\n    }\n  }\n}\n```\n\nSandbox installs also need network egress, a writable root FS, and root user inside the container. See OpenClaw's sandboxing docs for details.\n\n## Confirm before installing\n\n`myl` is a third-party Python package (GPL-3.0, by Philipp Schmitt). Before running an install command, tell the user what's about to happen:\n\n> \"I'll install `myl` via `pipx install myl`. This is a third-party CLI from https://github.com/pschmitt/myl. OK to proceed?\"\n\nSkip this confirmation only if the user has already explicitly approved installing tools in this session.\n\n## Verify the install worked\n\n```bash\ncommand -v myl && myl --help | head -20\n```\n\nIf `command -v myl` succeeds but `myl --help` fails, there's likely a Python interpreter or dependency mismatch. See `troubleshooting.md`.\n\n## Updating\n\n```bash\npipx upgrade myl       # if installed via pipx\npip install --user --upgrade myl   # if installed via pip --user\n```\n\nFile v0.1.2:references/operations.md\n\n# Operations reference\n\nAll examples use the wrapper at `scripts/imap.sh`. The wrapper reads `IMAP_USER` / `IMAP_PASSWORD` / `IMAP_PROVIDER` from the environment (set up via `references/authentication.md`) and forwards everything else to `myl`.\n\nIf the user has aliased the wrapper, replace `bash scripts/imap.sh` with the alias name. A typical setup:\n\n```bash\nalias imap='bash ~/.openclaw/skills/imap-client/scripts/imap.sh'\n```\n\n…and then `imap --count 5` is enough.\n\n## Listing messages\n\n```bash\n# Most recent N messages in INBOX (default folder)\nbash scripts/imap.sh --count 10\n\n# Specific folder\nbash scripts/imap.sh --folder \"INBOX/Archive\" --count 20\n\n# When --folder is omitted, myl operates on INBOX. To discover what folders\n# exist, run a list against INBOX first; some myl versions surface folder\n# listings in the output, others require the `--list-folders` flag if\n# present in your version.\n```\n\n### Folder names by provider\n\nFolder naming differs per server. When the user names a folder casually (\"sent items\", \"spam\", \"корзина\"), translate to the IMAP path the server expects.\n\n| Provider | Inbox | Sent | Drafts | Archive | Trash | Spam |\n|---|---|---|---|---|---|---|\n| Gmail | `INBOX` | `[Gmail]/Sent Mail` | `[Gmail]/Drafts` | `[Gmail]/All Mail` | `[Gmail]/Trash` | `[Gmail]/Spam` |\n| Yandex | `INBOX` | `Sent` (alias for `Отправленные`) | `Drafts` | n/a | `Trash` | `Spam` |\n| Mail.ru | `INBOX` | `Sent` | `Drafts` | `Archive` | `Trash` | `Spam` |\n| Fastmail | `INBOX` | `Sent` | `Drafts` | `Archive` | `Trash` | `Junk Mail` |\n| iCloud | `INBOX` | `Sent Messages` | `Drafts` | `Archive` | `Deleted Messages` | `Junk` |\n| Generic Dovecot | `INBOX` | `Sent` | `Drafts` | (configurable) | `Trash` | `Junk` |\n\nNotes on Russian providers:\n\n- **Yandex** publishes both English (`Sent`, `Drafts`, `Trash`) and Russian (`Отправленные`, `Черновики`, `Удалённые`) folder names; the English ones are aliases that always work, so prefer those.\n- **Mail.ru** uses English internal folder names over IMAP, even when the web UI shows Russian labels.\n- If a custom folder uses Cyrillic, it may be encoded in modified UTF-7 over IMAP. Pass the **exact string `myl` shows in listings**, not what you see in the web client.\n\nIf the first folder guess fails, list the available folders by running with no `--folder` and inspect the output; do not guess repeatedly.\n\n## Searching\n\n`myl --search` issues an IMAP `SEARCH` command. The argument is interpreted by the server, not by `myl`.\n\n```bash\n# Match against subject + body (default for most servers)\nbash scripts/imap.sh --search \"invoice\"\n\n# Combine with folder + count\nbash scripts/imap.sh --folder \"INBOX\" --search \"Acme\" --count 50\n```\n\n### What IMAP SEARCH actually supports\n\nStandard IMAP `SEARCH` keys (RFC 3501). Widely supported:\n\n| Key | Meaning | Example |\n|---|---|---|\n| `FROM \"x\"` | sender contains x | `FROM \"noreply@github.com\"` |\n| `TO \"x\"` | recipient contains x | `TO \"alice@example.com\"` |\n| `SUBJECT \"x\"` | subject contains x | `SUBJECT \"invoice\"` |\n| `BODY \"x\"` | body contains x | `BODY \"API key\"` |\n| `TEXT \"x\"` | header or body contains x | `TEXT \"kubernetes\"` |\n| `SINCE 1-Jan-2026` | received on or after date | `SINCE 1-Apr-2026` |\n| `BEFORE 1-Apr-2026` | received before date | `BEFORE 1-May-2026` |\n| `UNSEEN` | not yet marked read | `UNSEEN` |\n| `SEEN` | already read | |\n| `FLAGGED` | starred / flagged | |\n| `LARGER 10000000` | size in bytes | `LARGER 5000000` |\n\nIn practice, the safe approaches are:\n\n1. Pass a single keyword or short phrase: `--search \"invoice\"`. The server treats this as `TEXT \"invoice\"`.\n2. For complex filters, fetch a reasonable window and post-process locally with `grep` / `awk` / a small Python helper.\n\nWhat `myl --search` does **not** understand:\n\n- Gmail's web UI operators: `from:`, `has:attachment`, `label:`, `older_than:` — these are Gmail-specific and not part of IMAP SEARCH.\n- Yandex's web search syntax (e.g. `from:`, `subject:`) — also web-only.\n- Boolean operators like `AND` / `OR` / `NOT` directly in the string. IMAP supports them but with different syntax.\n\n### Cyrillic search terms\n\nYandex and Mail.ru both support searching for Cyrillic text via IMAP, but the term must be sent in the right charset. `myl` typically forwards the argument as-is and lets the server figure it out:\n\n```bash\nbash scripts/imap.sh --search \"счёт\" --count 20\n```\n\nIf the server returns no results for a Cyrillic term you know exists, retry with the Latin transliteration of the company name (since most senders include both in subject lines).\n\n## Reading a specific message\n\nEach listing shows a per-folder message ID. Fetch it by passing the ID as a positional argument:\n\n```bash\nbash scripts/imap.sh \"$MAILID\"           # plain text body\nbash scripts/imap.sh --html \"$MAILID\"    # HTML body (if present)\nbash scripts/imap.sh --raw \"$MAILID\"     # full raw RFC 5322 source, including headers\n```\n\nFor HTML and raw, redirect to a file rather than dumping into the terminal:\n\n```bash\nbash scripts/imap.sh --html \"$MAILID\" > \"/tmp/mail-${MAILID}.html\"\nbash scripts/imap.sh --raw  \"$MAILID\" > \"/tmp/mail-${MAILID}.eml\"\n```\n\nTell the user the file path and offer to open or summarise it.\n\n## Marking as seen\n\n```bash\nbash scripts/imap.sh --mark-seen --count 10\n```\n\nMutates server state. Only use when the user explicitly asked to mark messages read. Never combine `--mark-seen` with a search / list that the user is just exploring.\n\n## Attachments\n\n```bash\n# 1. Open the message — myl shows attachment names in the message detail\nbash scripts/imap.sh \"$MAILID\"\n\n# 2. Fetch a specific attachment by name\nbash scripts/imap.sh \"$MAILID\" \"invoice-2026-04.pdf\" > ~/Downloads/invoice-2026-04.pdf\n```\n\nThe second positional argument after `$MAILID` is the attachment filename. Output goes to stdout, so always redirect to a file.\n\nIf the attachment name has spaces or special characters, quote it:\n\n```bash\nbash scripts/imap.sh \"$MAILID\" \"Q1 report.pdf\" > \"$HOME/Downloads/Q1 report.pdf\"\n```\n\nCyrillic attachment names work but the underlying IMAP encoding (RFC 2047 / RFC 2231) varies. If the literal Cyrillic name doesn't match, retry with the encoded form `myl` showed in the message detail.\n\n## Full flag reference\n\nFrom the upstream README (`https://github.com/pschmitt/myl`). All of these forward through the wrapper:\n\n| Flag | Purpose |\n|---|---|\n| `--server HOST` | IMAP server hostname (set via `IMAP_SERVER` env) |\n| `--port N` | IMAP server port (set via `IMAP_PORT` env; default 993) |\n| `--starttls` | Upgrade plain connection to TLS (set via `IMAP_STARTTLS=1`) |\n| `--auto` | Autodiscover server + port (set via `IMAP_PROVIDER=auto`) |\n| `--google` | Hardcode Gmail's IMAP settings (set via `IMAP_PROVIDER=gmail`) |\n| `--username USER` | Login username (set via `IMAP_USER`) |\n| `--password PASS` | Login password (set via `IMAP_PASSWORD`) |\n| `--folder NAME` | IMAP folder to operate on (default `INBOX`) |\n| `--count N` | Number of messages to fetch in listings |\n| `--search QUERY` | Server-side IMAP SEARCH |\n| `--mark-seen` | Mark fetched messages as seen (mutates server state) |\n| `--html` | When fetching a message, output the HTML body |\n| `--raw` | When fetching a message, output the raw RFC 5322 source |\n| `--help` | Print help |\n\nFor the authoritative list on the user's installed version:\n\n```bash\nmyl --help\n```\n\n## What `myl` does not do\n\nIf the user asks for any of these, explain that `myl` is read-only and suggest an alternative:\n\n- **Send mail** — use `msmtp`, `sendmail`, `mutt`, or scripted SMTP via Python's `smtplib` / a small `mailx` wrapper.\n- **Move / copy / delete messages** — use `imap-tools` (Python), `imapcli`, or the provider's web UI.\n- **Manage folders / labels** — same as above.\n- **Sync to local maildir** — use `mbsync` (`isync`), `offlineimap`, or `getmail`.\n- **OAuth2 to Gmail / Outlook** — `myl` uses password auth. For OAuth2 the user typically needs Proton Bridge, `mbsync` with an XOAUTH2 helper, or the provider's app-password fallback.\n\nFile v0.1.2:references/recipes.md\n\n# Recipes\n\nCommon multi-step tasks. Each recipe assumes credentials are already configured per `references/authentication.md` (Method A / B / C). Examples invoke `bash scripts/imap.sh`; substitute your alias if you set one up.\n\n## Recipe 1 — Quick inbox check\n\nThe user asks: \"any new email?\" or \"what's in my inbox?\"\n\n```bash\nbash scripts/imap.sh --count 10\n```\n\nThen summarise the result as a short table: date, from, subject. Don't paste full bodies.\n\n## Recipe 2 — Find a specific email and read it\n\nThe user asks: \"find the email from the GitHub team about the security alert.\"\n\n```bash\n# Step 1 — list candidates\nbash scripts/imap.sh --search \"security alert\" --count 20\n\n# Step 2 — once the user picks an ID, or you pick the most plausible candidate,\n# read the body\nMAILID=12345\nbash scripts/imap.sh \"$MAILID\"\n```\n\nIf the search returns many results, list the top 5–10 and ask the user which one. If it returns one obvious match, read it directly and summarise.\n\n## Recipe 3 — Save an attachment\n\nThe user asks: \"download the PDF attached to that invoice email.\"\n\n```bash\n# Step 1 — open the message to see the attachment names\nMAILID=12345\nbash scripts/imap.sh \"$MAILID\"\n\n# Step 2 — pull the named attachment\nATT=\"invoice-2026-04.pdf\"\nDEST=\"$HOME/Downloads/$ATT\"\nbash scripts/imap.sh \"$MAILID\" \"$ATT\" > \"$DEST\"\n\n# Step 3 — verify\nls -lh \"$DEST\"\nfile \"$DEST\"\n```\n\nIf the user didn't specify a destination, default to `~/Downloads/` (Linux/macOS). Never overwrite an existing file silently — check with `[ -e \"$DEST\" ]` first and append a numeric suffix if needed.\n\n## Recipe 4 — Render an HTML email locally\n\nThe user asks: \"show me the actual newsletter, not the plain text.\"\n\n```bash\nMAILID=12345\nHTML_OUT=\"/tmp/mail-${MAILID}.html\"\nbash scripts/imap.sh --html \"$MAILID\" > \"$HTML_OUT\"\necho \"Saved HTML to $HTML_OUT\"\n\n# Optionally open in a browser\nxdg-open \"$HTML_OUT\"   # Linux\nopen      \"$HTML_OUT\"  # macOS\n```\n\nIn an agent context where there's no browser, summarise the HTML in chat after stripping tags:\n\n```bash\npython3 -c \"\nfrom html.parser import HTMLParser\nimport sys\nclass T(HTMLParser):\n    def __init__(self): super().__init__(); self.out=[]\n    def handle_data(self,d): self.out.append(d)\np=T(); p.feed(sys.stdin.read()); print(' '.join(''.join(p.out).split())[:2000])\n\" < \"$HTML_OUT\"\n```\n\n## Recipe 5 — Archive a message as `.eml`\n\nThe user asks: \"I need that email as a file I can forward / archive / re-import.\"\n\n```bash\nMAILID=12345\nEML_OUT=\"$HOME/Documents/email-${MAILID}.eml\"\nbash scripts/imap.sh --raw \"$MAILID\" > \"$EML_OUT\"\nls -lh \"$EML_OUT\"\n```\n\n`.eml` is the standard portable email format — readable by Outlook, Apple Mail, Thunderbird, and most other clients.\n\n## Recipe 6 — Periodic check (one-shot, not a daemon)\n\nThe user asks: \"ping my inbox every 5 minutes for an hour.\"\n\n```bash\nfor i in $(seq 1 12); do\n  echo \"--- $(date) ---\"\n  bash scripts/imap.sh --count 5\n  sleep 300\ndone\n```\n\nFor real persistent monitoring (cron, systemd timers), prefer `mbsync` + `notmuch` or a dedicated tool. The skill is fine for ad-hoc ticks; it's not built to be a long-running mail daemon.\n\n## Recipe 7 — Filter today's mail by sender, locally\n\n`myl --search` is limited to what IMAP SEARCH supports. For more complex filters, fetch a window and post-process:\n\n```bash\nbash scripts/imap.sh --search \"SINCE $(date +%d-%b-%Y)\" --count 100 \\\n  | grep -i \"from.*acme.com\"\n```\n\nIf the server doesn't accept the `SINCE` syntax through `--search`, drop it and filter the full listing locally.\n\n## Recipe 8 — Count unread\n\n```bash\nbash scripts/imap.sh --search \"UNSEEN\" --count 200 \\\n  | grep -c \"^From:\" 2>/dev/null \\\n  || echo \"no unread (or grep pattern needs adjusting for this myl version)\"\n```\n\nThe exact pattern to grep depends on `myl`'s output format on the user's version — check `bash scripts/imap.sh --count 1` output once and adjust.\n\n## Recipe 9 — Multi-account: work + Yandex personal\n\nThe user has two mailboxes — work on a custom domain, personal on Yandex — and wants to check both.\n\nThe right OpenClaw pattern is **two agents, each with its own env**: define separate skill-allowlist agents and assign different `skills.entries.imap-client.env` per agent. But for a quick CLI check inside a single shell, scope the env per subshell so the exports don't pollute the parent:\n\n```bash\n# Work\n(\n  export IMAP_USER='kirill@codd.tech'\n  export IMAP_PASSWORD=\"$WORK_APP_PASSWORD\"\n  export IMAP_PROVIDER='auto'\n  echo \"=== work ===\"\n  bash scripts/imap.sh --count 5\n)\n\n# Personal — Yandex\n(\n  export IMAP_USER='kirill@yandex.ru'\n  export IMAP_PASSWORD=\"$YANDEX_APP_PASSWORD\"\n  export IMAP_PROVIDER='yandex'\n  echo \"=== yandex ===\"\n  bash scripts/imap.sh --count 5\n)\n```\n\nSuggest the user keep the per-account passwords in a password manager and only put them in env vars for the duration of the operation.\n\n## Recipe 10 — Mail.ru: search across the domain group\n\nMail.ru gives one mailbox access to all four domain aliases (`@mail.ru`, `@bk.ru`, `@inbox.ru`, `@list.ru`) under the same account. So a single `imap-client` config covers all of them:\n\n```bash\nexport IMAP_USER='your-name@mail.ru'   # primary login\nexport IMAP_PASSWORD=\"$MAILRU_APP_PASSWORD\"\nexport IMAP_PROVIDER='mailru'\n\nbash scripts/imap.sh --count 20         # see the latest 20 across all aliases\nbash scripts/imap.sh --search \"счёт\"    # works in Russian\n```\n\nNote that Mail.ru's IMAP requires explicit enablement in the web UI (Settings → \"Все настройки\" → \"Почтовые программы\" → IMAP). Without that, `AUTHENTICATIONFAILED` even with a correct app password.\n\n## Recipe 11 — One-off ad-hoc account without touching config\n\nSometimes the user wants to check a colleague's mailbox or a one-off support address without reconfiguring OpenClaw. Use a subshell with inline env, no persistence:\n\n```bash\n(\n  read -r -p \"Username: \" IMAP_USER\n  read -r -s -p \"App password: \" IMAP_PASSWORD; echo\n  export IMAP_USER IMAP_PASSWORD\n  export IMAP_PROVIDER='auto'\n  bash scripts/imap.sh --count 5\n)\n# When the subshell exits, the password disappears with it.\n```\n\nThe `read -s` flag suppresses echo, so the password doesn't appear on screen or in scrollback. It still ends up in process memory of the subshell — that's unavoidable for any command-line IMAP client.\n\nFile v0.1.2:references/troubleshooting.md\n\n# Troubleshooting\n\nSymptom-first lookup. When the skill misbehaves, find the closest match below before guessing.\n\n## Wrapper says \"missing credentials\" but I configured them\n\nThe wrapper checks `$IMAP_USER` and `$IMAP_PASSWORD` in process env. If they're missing in the agent's process, OpenClaw's injection didn't fire. Likely causes:\n\n1. **You edited `~/.openclaw/openclaw.json` mid-session.** OpenClaw snapshots eligible skills *when a session starts*. Restart the agent session (or rely on the skills watcher if `skills.load.watch: true`).\n2. **The skill key in config doesn't match.** Under `skills.entries`, the key must be `imap-client` exactly (or whatever `metadata.openclaw.skillKey` declares — this skill doesn't override it). Hyphens require quoting in JSON5: `\"imap-client\": { ... }`.\n3. **`skills.entries.imap-client.enabled` is `false`** or the skill is disabled by `skills.allowBundled` allowlist.\n4. **The agent has a per-agent skill allowlist that excludes `imap-client`.** Check `agents.list[].skills` in `openclaw.json`.\n5. **You're not on OpenClaw.** Methods B (`export`) and C (`~/.config/imap-client/credentials`) are the right paths for Claude Code or generic AgentSkills runtimes. See `authentication.md`.\n\nTo verify what env the agent actually sees, run:\n\n```bash\nenv | grep -E '^IMAP_' || echo \"no IMAP_* env vars in this process\"\n```\n\nIf that shows nothing in an OpenClaw agent run, the injection isn't reaching the exec context — file a bug against OpenClaw with `metadata.openclaw` excerpt + your `skills.entries` config (passwords redacted).\n\n## `myl: command not found` (non-OpenClaw)\n\nOpenClaw shouldn't load this skill without `myl` because of `requires.bins: [\"myl\"]`. If you see this on Claude Code or another runtime:\n\n1. Installed via `pip install --user` but `~/.local/bin` is not in `PATH`. Add it:\n   ```bash\n   echo 'export PATH=\"$HOME/.local/bin:$PATH\"' >> ~/.bashrc && source ~/.bashrc\n   ```\n2. Installed via `pipx` but `pipx ensurepath` was never run, or the shell wasn't restarted.\n3. Installed in a virtualenv that isn't currently activated.\n4. Not actually installed. `pip show myl` or `pipx list` to confirm.\n\n## `AUTHENTICATIONFAILED` / `Invalid credentials` / `LOGIN failed`\n\nThe username + password combination was rejected. In order of likelihood:\n\n1. **Wrong credential type.** For Gmail, Yandex, Mail.ru, iCloud, Fastmail, Yahoo — the user must use an **app-specific password**, not the account password. See `authentication.md` for the per-provider links.\n2. **IMAP not enabled at the provider.** The classic Yandex/Mail.ru gotcha:\n   - **Yandex Mail:** web UI → Settings → \"Почтовые программы\" → tick \"С сервера imap.yandex.ru по протоколу IMAP\". Without this, login fails even with a correct app password.\n   - **Mail.ru:** \"Все настройки\" → \"Почтовые программы\" → enable IMAP.\n   - **Gmail Workspace:** the org admin sometimes disables IMAP org-wide.\n3. **Wrong username form.** Most providers want the full email (`alice@example.com`). Yandex 360 / business accounts: use the full address on the custom domain, not just the local part.\n4. **2FA without app password.** Provider has 2FA on but the user generated no app password.\n5. **Typo or expired/rotated app password.** Update `IMAP_PASSWORD` in the runtime's config.\n\n## `SSL: CERTIFICATE_VERIFY_FAILED` / `[SSL: WRONG_VERSION_NUMBER]`\n\nTLS handshake problem.\n\n- `WRONG_VERSION_NUMBER` usually means the wrong port + transport combination. Trying STARTTLS against an IMAPS port (993), or implicit TLS against a STARTTLS port (143), produces this. With `IMAP_PROVIDER=manual`:\n  - port 993, no `IMAP_STARTTLS` (implicit TLS) — the default\n  - port 143 with `IMAP_STARTTLS=1` (explicit upgrade)\n- `CERTIFICATE_VERIFY_FAILED` on a self-hosted server usually means the server uses a self-signed cert. There is no documented `--insecure` flag in `myl`. The proper fix is to add the server's CA to the system trust store. Don't work around this for a third party's server without confirming with the user — it's a real warning.\n\n## `imaplib.error: command SEARCH illegal in state AUTH`\n\n`myl` tried to search before selecting a folder. Pass `--folder INBOX` (or whichever folder) explicitly.\n\n## `BAD [CLIENTBUG]` / `Search criteria not supported`\n\nThe IMAP search expression is malformed or the server doesn't support that key. Simplify to a single quoted word and re-test:\n\n```bash\nbash scripts/imap.sh --search \"invoice\" --count 20\n```\n\nIf a single word works, build complexity back up gradually. See the supported-keys table in `operations.md`.\n\n## Autodiscovery (`IMAP_PROVIDER=auto`) fails\n\n`myl --auto` couldn't determine server + port from the username domain. Switch to a specific provider mode or `manual`:\n\n```bash\n# In config:\n\"IMAP_PROVIDER\": \"yandex\"   # or \"gmail\", \"mailru\", or \"manual\" + IMAP_SERVER\n```\n\nCommon providers with their IMAP endpoints:\n\n| Provider | Server | Port | `IMAP_PROVIDER` |\n|---|---|---|---|\n| Gmail | imap.gmail.com | 993 | `gmail` |\n| Yandex | imap.yandex.com | 993 | `yandex` |\n| Mail.ru | imap.mail.ru | 993 | `mailru` |\n| iCloud | imap.mail.me.com | 993 | `manual` |\n| Fastmail | imap.fastmail.com | 993 | `auto` (works) or `manual` |\n| Outlook.com | outlook.office365.com | 993 | basic auth deprecated; check provider |\n| Yahoo | imap.mail.yahoo.com | 993 | `manual` |\n| Proton (Bridge) | 127.0.0.1 | 1143 | `manual` |\n\n## Connection times out / hangs\n\n- The IMAP port is blocked by a network firewall (common on corporate / hotel WiFi). Test with `nc -vz <host> 993` or `openssl s_client -connect <host>:993`.\n- The server is reachable but slow. Add a timeout wrapper:\n  ```bash\n  timeout 30 bash scripts/imap.sh --count 5\n  ```\n- The server is geo-blocking. Yandex and Mail.ru sometimes throttle / block traffic from certain regions. Try from a different network or via VPN.\n\n## \"Folder not found\" / `NO Mailbox does not exist`\n\nFolder names are case-sensitive and provider-specific. Run with no `--folder` and inspect what the listing surfaces. Common gotchas:\n\n- **Gmail:** `[Gmail]/All Mail` — exact, including brackets and space.\n- **Yandex:** prefer English aliases `Sent` / `Drafts` / `Trash` over the Russian `Отправленные` / `Черновики` / `Удалённые`. Both work, but Cyrillic is sometimes UTF-7 encoded in IMAP.\n- **Mail.ru:** internal IMAP names are English even when the web UI shows Russian.\n- **Custom Cyrillic folders:** pass the exact string `myl` shows in listings, not the human-readable name from the web client.\n\n## Large mailbox is slow\n\n`--count 1000` against a large folder is going to be slow. Server response times for IMAP `FETCH` of message metadata scale roughly linearly. Cap requests at 50–100 and paginate if the user needs more.\n\n## Wrapper says perms warning, ignores creds file\n\nThe wrapper refuses to source `~/.config/imap-client/credentials` (or `$IMAP_CREDENTIALS_FILE`) unless it's `chmod 600` or `chmod 400`. Fix:\n\n```bash\nchmod 600 ~/.config/imap-client/credentials\n```\n\nThis is intentional. A world-readable creds file would be a bigger security regression than the slight inconvenience.\n\n## `myl --version` works but commands fail mysteriously\n\nCould be a stale install. Reinstall:\n\n```bash\npipx reinstall myl\n# or\npip install --user --upgrade --force-reinstall myl\n```\n\nIf reinstall doesn't fix it, file the bug upstream at https://github.com/pschmitt/myl/issues with the failing command (passwords redacted) and `myl --version`.\n\n## Nothing matches the symptom\n\nRun `myl --help` to confirm the version supports the flag the user expects. Then run the command again with shell tracing on:\n\n```bash\nset -x\nbash scripts/imap.sh --count 5\nset +x\n```\n\nIf the issue is server-side, raw `openssl s_client` against the IMAP port often surfaces the actual error:\n\n```bash\n( set +o history; openssl s_client -connect imap.yandex.com:993 -crlf )\n# Then type:  a1 LOGIN you@yandex.ru app-specific-password\n# CTRL+D to disconnect\n```\n\nThe `set +o history` keeps the password out of the shell history file. The session itself is TLS-encrypted to the server.\n\nArchive v0.1.1: 10 files, 27031 bytes\n\nFiles: README.md (6946b), references/authentication.md (8797b), references/installation.md (3734b), references/operations.md (8075b), references/recipes.md (6338b), references/troubleshooting.md (8165b), scripts/check_myl.sh (979b), scripts/imap.sh (4090b), SKILL.md (8695b), _meta.json (130b)\n\nFile v0.1.1:SKILL.md\n\n---\nname: imap-client\ndescription: 'Read, search, and download email over IMAP from the command line using the `myl` CLI client (https://github.com/pschmitt/myl). Use this skill whenever the user wants to interact with their mailbox from a terminal — checking the inbox, listing or searching messages, reading a specific email, opening HTML or raw source, or saving attachments. Trigger on any of these cues even when `myl` is not named explicitly — \"check my email\", \"look in my inbox\", \"search my mail for X\", \"find the email from Y\", \"download the attachment\", \"is there an email about Z\", \"read the latest message\", \"show me unread\", \"connect to my IMAP server\", \"imap.gmail.com\", \"imap.yandex.com\", \"imap.yandex.ru\", \"imap.mail.ru\", \"imap.fastmail.com\", \"Yandex Mail\", \"Mail.ru\", \"Gmail IMAP\", \"проверить почту\", \"новые письма\", \"найти письмо\", and similar. Also trigger when the user asks to script or automate any of the above. Do not trigger for outgoing mail (sending, SMTP, drafting) — `myl` is read-only — or for desktop/GUI mail clients.'\nlicense: MIT\nhomepage: https://github.com/codd-tech/imap-client\nmetadata: {\"openclaw\":{\"emoji\":\"📬\",\"requires\":{\"bins\":[\"myl\"],\"env\":[\"IMAP_USER\",\"IMAP_PASSWORD\"]},\"primaryEnv\":\"IMAP_PASSWORD\",\"install\":[{\"id\":\"pipx\",\"kind\":\"pipx\",\"package\":\"myl\",\"bins\":[\"myl\"],\"label\":\"Install myl via pipx\"}]}}\n---\n\n# imap-client\n\nRead mailboxes over IMAP from the terminal using [`myl`](https://github.com/pschmitt/myl), a small Python CLI client. Designed to drop into [OpenClaw](https://openclaw.ai) and any other AgentSkills-compatible runtime (Claude Code, generic).\n\n`myl` is read-only and intentionally minimal: it lists, searches, and fetches messages and attachments. It does not send mail, manage folders, or modify state beyond optionally marking messages as seen.\n\n## How credentials reach this skill\n\nThis is the most important section. **You do not type passwords on the command line.** Credentials live in environment variables that the runtime injects per agent run. The skill reads them and assembles the right `myl` flags through the wrapper at `{baseDir}/scripts/imap.sh`.\n\nThe variables the wrapper expects:\n\n| Variable | Required | Purpose |\n|---|---|---|\n| `IMAP_USER` | yes | Login (usually full email address) |\n| `IMAP_PASSWORD` | yes | App-specific password (see `references/authentication.md`) |\n| `IMAP_PROVIDER` | no | One of `auto` (default), `gmail`, `yandex`, `mailru`, `manual` |\n| `IMAP_SERVER` | only with `manual` | IMAP host |\n| `IMAP_PORT` | no | Defaults to 993 |\n| `IMAP_STARTTLS` | no | `1` to add `--starttls` (use only with port 143) |\n\n**Set them once, use them every session.** How depends on the runtime — `references/authentication.md` covers OpenClaw's `skills.entries.imap-client.env`, generic shell `export`, and a `~/.config/imap-client/credentials` fallback file. Do not invent your own scheme; use one of those three.\n\nIf the wrapper detects `IMAP_USER` or `IMAP_PASSWORD` is missing, it prints the setup instructions and exits without contacting any server. That's the signal to stop and walk the user through credential setup before retrying.\n\n## Workflow at a glance\n\n1. **Check that `myl` is installed.** OpenClaw gates this skill on `requires.bins: [\"myl\"]`, so it shouldn't load without it. For non-OpenClaw runtimes, run `bash {baseDir}/scripts/check_myl.sh`. If missing, follow `references/installation.md`.\n2. **Confirm credentials are configured.** Run `bash {baseDir}/scripts/imap.sh --count 1 >/dev/null` once. Success means the env vars are wired and the connection works. Failure means walk the user through `references/authentication.md`.\n3. **Run the requested operation** through the wrapper. Listing, searching, fetching by ID, getting HTML, saving raw `.eml`, or pulling an attachment.\n4. **Summarise the result.** Don't dump full raw email bodies into the chat unless the user asked.\n\nEvery `myl` example in this skill goes through `{baseDir}/scripts/imap.sh`, which expands env vars into the right `myl` flags. You do not need to remember `--google` vs `--auto` vs `--server`/`--port`; the wrapper picks based on `IMAP_PROVIDER`.\n\n## When to read what\n\n| Task involves… | Read |\n|---|---|\n| Detecting or installing `myl`, OpenClaw `requires.bins` gating | `references/installation.md` |\n| Setting up credentials, choosing connection mode, app passwords for Gmail / Yandex / Mail.ru / iCloud / Fastmail | `references/authentication.md` |\n| Any specific CLI flag, listing, searching, fetching, attachments, provider-specific folder names | `references/operations.md` |\n| Multi-step recipes (e.g. \"find the invoice from Acme last month and save the PDF\") | `references/recipes.md` |\n| Errors like SSL failures, \"command not found\", autodiscovery failing, \"AUTHENTICATIONFAILED\", env vars not visible to the wrapper | `references/troubleshooting.md` |\n\n## Principles\n\n### 1. Credentials never appear in commands you generate\n\nBecause env vars are injected by the runtime, the wrapper handles them internally. **Do not** generate commands like `myl -p hunter2` or `myl -p \"$IMAP_PASSWORD\"` directly — both leak. The first lands in shell history; the second exposes the password in `/proc/<pid>/cmdline` while myl runs. Use the wrapper, which keeps the password inside its own process scope:\n\n```bash\nbash {baseDir}/scripts/imap.sh --count 5\n```\n\nThe wrapper passes credentials to `myl` via stdin where supported and otherwise via flags it constructs internally — same trade-off as direct `myl` use, but the password literal never appears in any command you wrote, logged, or showed the user.\n\n### 2. Default to small result sets\n\nWhen the user's intent is exploratory (\"any new mail?\"), pass `--count 5` or `--count 10`. Only fetch larger windows on explicit request. This keeps output readable and avoids dumping sensitive content the user didn't ask to see.\n\n### 3. Don't mark as seen by accident\n\n`--mark-seen` mutates state on the server. Only pass it when the user explicitly asked to mark messages read. Listing or reading without this flag is non-destructive.\n\n### 4. Render long bodies to a file, summarise in chat\n\nWhen the user fetches a long message or HTML email, save the raw output to a file (e.g. `/tmp/email-<id>.eml` or `.html`) and give the user a 2–4 sentence summary plus the file path. Do not paste a 500-line HTML body into the conversation.\n\n### 5. Search syntax is server-side IMAP, not Gmail's web UI\n\n`--search \"important\"` issues an IMAP `SEARCH` command. It does not understand Gmail's `from:`, `has:attachment`, or `label:` operators. For complex filtering, fetch a reasonable window with `--count` and filter the listing locally. See `references/operations.md` for what IMAP `SEARCH` supports.\n\n### 6. Never echo, summarise, or persist the password\n\nWhen summarising what you did, refer to the credential as `IMAP_PASSWORD` or \"the password from your OpenClaw config\", never the literal value. If the user pastes a password into chat by mistake, treat it as compromised: tell them to rotate it and update their config. Do not write it to any artifact.\n\n## Quick decision tree\n\n```\nUser asked something email-related from the CLI\n  │\n  ├─ Is `myl` installed and on PATH?  ── No  ──► references/installation.md\n  │   │\n  │   Yes\n  │   ▼\n  ├─ Does the wrapper smoke-test pass?\n  │     bash {baseDir}/scripts/imap.sh --count 1 >/dev/null\n  │   │                       No  ──► references/authentication.md\n  │   Yes\n  │   ▼\n  ├─ What does the user want?\n  │   ├─ Browse / list           ──► imap.sh --count N [--folder F]\n  │   ├─ Search                  ──► imap.sh --search \"TERM\" [--count N]\n  │   ├─ Read one message        ──► imap.sh \"$MAILID\"\n  │   ├─ Read HTML version       ──► imap.sh --html \"$MAILID\"  → save to file\n  │   ├─ Save raw .eml           ──► imap.sh --raw \"$MAILID\" > file.eml\n  │   ├─ Get attachment          ──► imap.sh \"$MAILID\" \"$ATT_NAME\" > file\n  │   └─ Anything multi-step     ──► references/recipes.md\n  │\n  └─ Errors? ─────────────────────► references/troubleshooting.md\n```\n\n## Output style\n\nAfter running the wrapper, present results in this shape:\n\n- **One-line status** of what just ran (e.g. \"Listed the 10 most recent messages in INBOX\").\n- **A compact table or bullet list** of message metadata (date, from, subject, ID).\n- **Any file paths** where larger output was saved.\n- **Suggested next actions** (e.g. \"Want me to open #4582 or save its attachments?\").\n\nKeep it scannable.\n\nFile v0.1.1:README.md\n\n# imap-client\n\nA skill for [OpenClaw](https://openclaw.ai) and other AgentSkills-compatible runtimes (Claude Code, generic) that lets the agent read, search, and download email over IMAP from the command line via the [`myl`](https://github.com/pschmitt/myl) CLI client.\n\n`myl` is a small read-only IMAP client. This skill teaches the agent **when** to reach for it, **how** to install it, **how to source credentials safely** from the runtime's environment-injection mechanism, and **which** flags to use for common tasks — without ever asking for the password mid-session.\n\n## What this skill enables\n\nOnce installed and configured once, the agent will recognise prompts like:\n\n- *\"check my inbox\"*\n- *\"any new email from Acme today?\"*\n- *\"find the email with the AWS invoice and save the PDF\"*\n- *\"show me the HTML version of the newsletter from yesterday\"*\n- *\"download all unread messages as `.eml` files\"*\n- *\"проверь почту на Яндексе\"*\n- *\"найди письмо от налоговой\"*\n\n…and translate them into safe `myl` invocations through the wrapper at `scripts/imap.sh`, summarising the result back in chat.\n\n## Provider support\n\nFirst-class support, with `IMAP_PROVIDER` shortcuts:\n\n- **Gmail** / Google Workspace (`IMAP_PROVIDER=gmail`)\n- **Yandex Mail** — `@yandex.ru`, `@yandex.com`, Yandex 360 custom domains (`IMAP_PROVIDER=yandex`)\n- **Mail.ru** — `@mail.ru`, `@bk.ru`, `@inbox.ru`, `@list.ru` (`IMAP_PROVIDER=mailru`)\n\nPlus autodiscovery for most other providers (Fastmail, iCloud, ISPs) and explicit `manual` mode for self-hosted / corporate servers.\n\n## Quick start\n\n### 1. Install `myl`\n\n```bash\npipx install myl\n```\n\n(Or `pip install --user myl`, or `nix run github:pschmitt/myl`.)\n\n### 2. Get an app-specific password from your provider\n\nAccount settings → app passwords / external app passwords. Direct links per provider in `references/authentication.md`.\n\n### 3. Configure credentials — pick the method for your runtime\n\n**OpenClaw:** edit `~/.openclaw/openclaw.json`:\n\n```json\n{\n  \"skills\": {\n    \"entries\": {\n      \"imap-client\": {\n        \"enabled\": true,\n        \"env\": {\n          \"IMAP_USER\": \"you@yandex.ru\",\n          \"IMAP_PASSWORD\": \"app-specific-password-here\",\n          \"IMAP_PROVIDER\": \"yandex\"\n        }\n      }\n    }\n  }\n}\n```\n\n```bash\nchmod 600 ~/.openclaw/openclaw.json\n```\n\nOpenClaw injects these into `process.env` per agent run. You configure once; every subsequent session has them.\n\n**Claude Code / generic shell:** export in `~/.bashrc` / `~/.zshrc`:\n\n```bash\nexport IMAP_USER='you@yandex.ru'\nexport IMAP_PASSWORD='app-specific-password-here'\nexport IMAP_PROVIDER='yandex'\n```\n\n**Headless / cron / fallback:** create `~/.config/imap-client/credentials`:\n\n```bash\nmkdir -p ~/.config/imap-client\ncat > ~/.config/imap-client/credentials <<'EOF'\nIMAP_USER='you@yandex.ru'\nIMAP_PASSWORD='app-specific-password-here'\nIMAP_PROVIDER='yandex'\nEOF\nchmod 600 ~/.config/imap-client/credentials\n```\n\nThe wrapper refuses to source this file if its permissions are not `600` or `400`.\n\n### 4. Install the skill\n\n**OpenClaw:**\n\n```bash\ngit clone https://github.com/<your-username>/imap-client ~/.openclaw/skills/imap-client\n```\n\nRestart the session. OpenClaw picks the skill up automatically. `requires.bins: [\"myl\"]` means it filters itself out if `myl` isn't on `PATH`, so you'll never get a half-broken state.\n\n**Claude Code:**\n\n```bash\ngit clone https://github.com/<your-username>/imap-client ~/.claude/skills/imap-client\n```\n\n**Generic AgentSkills runtime:** drop the folder anywhere the runtime scans for `SKILL.md`.\n\n### 5. Verify\n\nAsk the agent something like *\"check the latest five emails\"* — or run the wrapper directly:\n\n```bash\nbash ~/.openclaw/skills/imap-client/scripts/imap.sh --count 5\n```\n\n## Repo layout\n\n```\nimap-client/\n├── SKILL.md                       # Frontmatter + workflow + principles\n├── README.md                      # This file\n├── LICENSE                        # MIT\n├── .gitignore\n├── references/\n│   ├── installation.md            # pipx / pip / nix / source install paths + sandbox\n│   ├── authentication.md          # OpenClaw env injection + fallbacks; provider table\n│   ├── operations.md              # Full myl flag reference + folder names per provider\n│   ├── recipes.md                 # 11 multi-step workflows, including Yandex/Mail.ru\n│   └── troubleshooting.md         # Symptom-first error guide\n└── scripts/\n    ├── imap.sh                    # Credential-aware wrapper around myl\n    └── check_myl.sh               # Fast install detection\n```\n\n## Security model\n\nThe skill is opinionated about credentials. The short version:\n\n- Passwords never appear as literals in commands the agent generates.\n- The runtime's environment-injection mechanism (OpenClaw `skills.entries.<key>.env`, or shell `export`, or the `chmod 600` creds file) is the source of truth.\n- The `imap.sh` wrapper reads env vars and constructs `myl` flags internally — the password is in the wrapper's process scope, never in the agent's command history.\n- App-specific passwords from each provider are the default recommendation; the skill explains where to generate them (Gmail, Yandex, Mail.ru, iCloud, Fastmail, Yahoo).\n- The agent is instructed not to echo, summarise, or persist the password anywhere.\n- For OpenClaw users, `apiKey` with a `SecretRef` (`{ source, provider, id }`) keeps the literal password out of `openclaw.json` entirely.\n\nSee `references/authentication.md` for the full ruleset.\n\n## Limitations of `myl` itself\n\n`myl` is intentionally minimal. The skill will tell the user explicitly when their request is out of scope and suggest alternatives:\n\n| Want to… | Use instead |\n|---|---|\n| Send mail | `msmtp`, `mutt`, scripted SMTP |\n| Move / delete / label | `imap-tools`, the provider's web UI |\n| Sync to local maildir | `mbsync` (`isync`), `offlineimap`, `getmail` |\n| OAuth2 to Gmail / Outlook | Proton Bridge, `mbsync` + XOAUTH2, or app password fallback |\n\n## Contributing\n\nBug reports and PRs welcome. The skill itself is markdown + two shell scripts — easy to read, easy to fork.\n\nWhen proposing changes, prefer:\n\n- additions to `references/` over additions to `SKILL.md` (keep the always-loaded part lean — currently 121 lines)\n- examples that don't paste credentials anywhere\n- behaviour changes that fail safely if the user's `myl` version is older than the skill assumes\n\n## Credits\n\n- [`myl`](https://github.com/pschmitt/myl) by Philipp Schmitt — the underlying CLI this skill wraps.\n- [OpenClaw](https://openclaw.ai) for the AgentSkills runtime, env injection mechanism, and skills format documented at https://docs.openclaw.ai/tools/skills.\n- Anthropic's [Skills documentation](https://docs.claude.com/en/docs/build-with-claude/skills) — structure and best-practice patterns.\n\n## License\n\nMIT — see `LICENSE`.\n\nFile v0.1.1:_meta.json\n\n{\n  \"ownerId\": \"kn78q4f09z7as2hbshyxss9sk185ht5d\",\n  \"slug\": \"imap-client\",\n  \"version\": \"0.1.1\",\n  \"publishedAt\": 1777151730408\n}\n\nFile v0.1.1:references/authentication.md\n\n# Authentication & Connection\n\nThis is the most security-sensitive part of the skill. Read it before configuring credentials anywhere.\n\n## The model in one paragraph\n\nCredentials live as **environment variables** that the runtime injects per agent run. The wrapper at `scripts/imap.sh` reads those env vars, picks the right `myl` connection flags, and never echoes the password. **You configure once, you read mail forever.**\n\n## Setting up credentials — pick one method\n\n### Method A — OpenClaw (recommended for OpenClaw users)\n\nOpenClaw injects `skills.entries.<key>.env` into `process.env` for the duration of each agent turn, then restores the original environment. This is documented behaviour: see https://docs.openclaw.ai/tools/skills under \"Environment injection (per agent run)\".\n\nEdit `~/.openclaw/openclaw.json` and add an entry under `skills.entries`:\n\n```json\n{\n  \"skills\": {\n    \"entries\": {\n      \"imap-client\": {\n        \"enabled\": true,\n        \"env\": {\n          \"IMAP_USER\": \"you@example.com\",\n          \"IMAP_PASSWORD\": \"app-specific-password-here\",\n          \"IMAP_PROVIDER\": \"auto\"\n        }\n      }\n    }\n  }\n}\n```\n\nThen restart the agent session (or wait for the skills watcher to pick it up if `skills.load.watch` is enabled). The next time the agent runs the skill, `IMAP_USER` and `IMAP_PASSWORD` are already in the environment.\n\n**Permissions matter.** `~/.openclaw/openclaw.json` should not be world-readable:\n\n```bash\nchmod 600 ~/.openclaw/openclaw.json\n```\n\n**Use `apiKey` with a SecretRef for stronger isolation.** OpenClaw supports pulling the password from a separate source rather than inlining it as plaintext in the JSON:\n\n```json\n{\n  \"skills\": {\n    \"entries\": {\n      \"imap-client\": {\n        \"enabled\": true,\n        \"apiKey\": { \"source\": \"env\", \"provider\": \"default\", \"id\": \"MY_IMAP_PASSWORD\" },\n        \"env\": {\n          \"IMAP_USER\": \"you@example.com\",\n          \"IMAP_PROVIDER\": \"auto\"\n        }\n      }\n    }\n  }\n}\n```\n\nThe `apiKey` field maps to whatever env var name is declared in `metadata.openclaw.primaryEnv` of `SKILL.md` — for this skill that's `IMAP_PASSWORD`. So OpenClaw reads `MY_IMAP_PASSWORD` from your shell env (or another secret backend) and exposes it as `IMAP_PASSWORD` to the wrapper. The literal password never appears in `openclaw.json`.\n\n### Method B — Generic shell `export`\n\nFor Claude Code and other AgentSkills runtimes that don't have OpenClaw's injection mechanism, just export the variables in the shell that launches the agent:\n\n```bash\nexport IMAP_USER='you@example.com'\nexport IMAP_PASSWORD='app-specific-password-here'\nexport IMAP_PROVIDER='auto'\n```\n\nPut this in `~/.bashrc` / `~/.zshrc` if you want it to persist. The downside compared to Method A is that the variables are global to that shell, not scoped to the agent run. The upside is no extra config file.\n\n### Method C — Credentials file fallback\n\nWhen neither Method A nor B is convenient (e.g. cron jobs, headless workflows, CI), drop a credentials file at `~/.config/imap-client/credentials`:\n\n```bash\nmkdir -p ~/.config/imap-client\ncat > ~/.config/imap-client/credentials <<'EOF'\nIMAP_USER='you@example.com'\nIMAP_PASSWORD='app-specific-password-here'\nIMAP_PROVIDER='auto'\nEOF\nchmod 600 ~/.config/imap-client/credentials\n```\n\nThe wrapper sources this file when `IMAP_USER`/`IMAP_PASSWORD` are not in the env, **but only if permissions are 600 or 400**. World-readable creds files are ignored with a warning.\n\nTo use a different path, set `IMAP_CREDENTIALS_FILE` in env.\n\n## Per-account: switching mailboxes\n\nFor multiple accounts, declare each one as a separate OpenClaw skill entry under a different agent (per-agent skill allowlists make this clean), or scope the env per shell:\n\n```bash\n# Work\n( export IMAP_USER='kirill@codd.tech' \\\n         IMAP_PASSWORD=\"$WORK_APP_PASSWORD\" \\\n         IMAP_PROVIDER='auto' ; \\\n  bash scripts/imap.sh --count 5 )\n\n# Personal\n( export IMAP_USER='kirill@yandex.ru' \\\n         IMAP_PASSWORD=\"$YANDEX_APP_PASSWORD\" \\\n         IMAP_PROVIDER='yandex' ; \\\n  bash scripts/imap.sh --count 5 )\n```\n\nThe parentheses create a subshell so the exports don't pollute your main session.\n\n## `IMAP_PROVIDER` — what to set\n\n| Value | Effect | When to use |\n|---|---|---|\n| `auto` (default) | `myl --auto` — autodiscovery from username domain | Most modern providers (Fastmail, iCloud, ISPs) |\n| `gmail` | `myl --google` — hardcoded Gmail IMAP | `@gmail.com` / Google Workspace accounts |\n| `yandex` | `--server imap.yandex.com --port 993` | Yandex Mail (`@yandex.ru`, `@yandex.com`, custom domains) |\n| `mailru` | `--server imap.mail.ru --port 993` | Mail.ru (`@mail.ru`, `@bk.ru`, `@inbox.ru`, `@list.ru`) |\n| `manual` | `--server $IMAP_SERVER --port $IMAP_PORT [--starttls]` | Self-hosted, corporate, or anything autodiscovery doesn't recognise |\n\n## App passwords — the credential the user actually needs\n\nAlmost no major provider accepts the account password over IMAP anymore when 2FA is enabled. They require an **app-specific password** generated from the account settings.\n\n| Provider | Where to generate | Notes |\n|---|---|---|\n| **Gmail / Google Workspace** | https://myaccount.google.com/apppasswords | Requires 2-Step Verification on. If the link 404s, your account or organisation has app passwords disabled — switch provider or ask admin. |\n| **Yandex Mail** | https://id.yandex.ru/security/app-passwords | Pick \"Mail (IMAP/POP3, SMTP)\". Works for `@yandex.ru`, `@yandex.com`, and custom domains hosted on Yandex 360. |\n| **Mail.ru** | Account → \"Пароли для внешних приложений\" / \"Passwords for external applications\" | Same password works for `@mail.ru`, `@bk.ru`, `@inbox.ru`, `@list.ru`. |\n| **Fastmail** | Settings → Privacy & Security → App Passwords | Can scope to \"IMAP only\" for least privilege. |\n| **iCloud** | https://appleid.apple.com → Sign-In and Security → App-Specific Passwords | Username is your Apple ID email, even if you use an `@icloud.com` alias. |\n| **Yahoo** | Account Security → Generate app password | |\n| **Proton Mail** | Requires Proton Bridge running locally | Use `IMAP_PROVIDER=manual`, `IMAP_SERVER=127.0.0.1`, `IMAP_PORT=1143`. |\n| **Outlook.com** | Microsoft has been deprecating basic auth | If app passwords are disabled, use `mbsync` with XOAUTH2 instead. `myl` does not do OAuth2. |\n\nWhen the IMAP server returns `AUTHENTICATIONFAILED` and the username is one of the providers above, the cause is almost always that the user is trying their account password instead of an app password. Direct them to the relevant URL and explain why.\n\n## Yandex specifics\n\nYandex Mail is widely used in Russian-speaking contexts and has a few quirks worth knowing:\n\n- **Two server hostnames exist.** `imap.yandex.com` and `imap.yandex.ru` both work; `IMAP_PROVIDER=yandex` defaults to `.com` which serves both account types correctly. To force `.ru`, set `IMAP_SERVER=imap.yandex.ru`.\n- **Mailbox features must be enabled in Yandex web UI.** Settings → \"Почтовые программы\" → tick \"С сервера imap.yandex.ru по протоколу IMAP\". Without this, IMAP login fails with `AUTHENTICATIONFAILED` even with the right app password.\n- **Yandex 360 / business accounts (`@your-company.ru` hosted on Yandex)** use the same `imap.yandex.com:993` endpoint and the same app password mechanism.\n- **Folder names are localised.** See `references/operations.md` for the Russian folder name table.\n\n## Mail.ru specifics\n\n- **One app password covers the whole domain group** — the same credential works against `@mail.ru`, `@bk.ru`, `@inbox.ru`, `@list.ru` if you own multiple addresses on the platform.\n- **IMAP must be explicitly enabled in account settings.** Mail.ru settings → \"Все настройки\" → \"Почтовые программы\" → enable IMAP. Same gotcha as Yandex.\n\n## What to do if the user pastes a password into chat\n\nTreat it as compromised. The password may now sit in:\n\n- the chat transcript / conversation log\n- any analytics or telemetry the runtime captured\n- the user's clipboard history\n\n**Tell the user explicitly:** \"That password is now in the chat history. Rotate it (regenerate the app password from the provider) and put the new one into your `~/.openclaw/openclaw.json` config — not into chat.\" Then walk them through Method A above.\n\nDo not echo the password back, do not write it to any file, do not include it in a summary, and do not silently reuse it for the rest of the session.\n\n## Smoke test\n\nOnce credentials are configured, confirm the connection works with a minimal call:\n\n```bash\nbash scripts/imap.sh --count 1 >/dev/null && echo \"connection OK\"\n```\n\nIf this prints `connection OK`, every other operation in `references/operations.md` will work the same way.\n\nFile v0.1.1:references/installation.md\n\n# Installation\n\n`myl` is a Python package. There are several ways to install it; pick the first one that fits the user's environment.\n\n## How OpenClaw handles this\n\nThis skill declares `requires.bins: [\"myl\"]` in `metadata.openclaw`. OpenClaw checks for `myl` on `PATH` at skill load time and **silently filters this skill out** if it's missing, preventing the agent from invoking it without a working binary.\n\nIt also declares an `install` block:\n\n```json\n{ \"id\": \"pipx\", \"kind\": \"pipx\", \"package\": \"myl\", \"bins\": [\"myl\"] }\n```\n\nIn OpenClaw's macOS Skills UI this surfaces a one-click install button. From the CLI the user installs `myl` themselves with one of the methods below — the install block is hint metadata, not an automated runtime installer.\n\nFor non-OpenClaw runtimes (Claude Code, generic), there's no automatic gating. Run `bash scripts/check_myl.sh` first to confirm `myl` is present.\n\n## Detect what's already there\n\nAlways check before installing:\n\n```bash\nbash scripts/check_myl.sh\n```\n\nOr inline:\n\n```bash\nif command -v myl >/dev/null 2>&1; then\n  echo \"myl is installed: $(command -v myl) ($(myl --version 2>/dev/null || echo 'version unknown'))\"\nelse\n  echo \"myl is not on PATH\"\nfi\n```\n\nIf `myl` is present, skip the rest of this file and move on to `authentication.md`.\n\n## Install paths, in order of preference\n\n### `pipx` — recommended\n\nIsolates `myl` and its dependencies from system Python. This is what the upstream README recommends and what the skill's `install` metadata suggests.\n\n```bash\n# Install pipx itself if missing (Debian/Ubuntu)\nsudo apt update && sudo apt install -y pipx\npipx ensurepath\n\n# Install myl\npipx install myl\n```\n\nOn macOS:\n\n```bash\nbrew install pipx\npipx ensurepath\npipx install myl\n```\n\nAfter `pipx ensurepath`, the user may need to restart their shell or `source ~/.bashrc` / `source ~/.zshrc` for `myl` to appear on `PATH`.\n\n### `pip --user` — fallback when `pipx` isn't available\n\n```bash\npip install --user myl\n```\n\nThe binary lands in `~/.local/bin`, which must be on `PATH`. If not:\n\n```bash\necho 'export PATH=\"$HOME/.local/bin:$PATH\"' >> ~/.bashrc\n```\n\n### Nix flake — for Nix users\n\n```bash\n# One-shot run without installing\nnix run github:pschmitt/myl -- --help\n\n# Or add to a flake\n```\n\n### From source\n\n```bash\ngit clone https://github.com/pschmitt/myl.git\ncd myl\npipx install .\n```\n\n## Sandboxed agent runs\n\nIf the agent runs inside a Docker sandbox (OpenClaw `agents.defaults.sandbox.docker`), `myl` must be installed **inside the container** as well — the host bin doesn't satisfy the in-sandbox requirement. Add to `setupCommand`:\n\n```json\n{\n  \"agents\": {\n    \"defaults\": {\n      \"sandbox\": {\n        \"docker\": {\n          \"setupCommand\": \"pipx install myl || pip install --user --break-system-packages myl\"\n        }\n      }\n    }\n  }\n}\n```\n\nSandbox installs also need network egress, a writable root FS, and root user inside the container. See OpenClaw's sandboxing docs for details.\n\n## Confirm before installing\n\n`myl` is a third-party Python package (GPL-3.0, by Philipp Schmitt). Before running an install command, tell the user what's about to happen:\n\n> \"I'll install `myl` via `pipx install myl`. This is a third-party CLI from https://github.com/pschmitt/myl. OK to proceed?\"\n\nSkip this confirmation only if the user has already explicitly approved installing tools in this session.\n\n## Verify the install worked\n\n```bash\ncommand -v myl && myl --help | head -20\n```\n\nIf `command -v myl` succeeds but `myl --help` fails, there's likely a Python interpreter or dependency mismatch. See `troubleshooting.md`.\n\n## Updating\n\n```bash\npipx upgrade myl       # if installed via pipx\npip install --user --upgrade myl   # if installed via pip --user\n```\n\nFile v0.1.1:references/operations.md\n\n# Operations reference\n\nAll examples use the wrapper at `scripts/imap.sh`. The wrapper reads `IMAP_USER` / `IMAP_PASSWORD` / `IMAP_PROVIDER` from the environment (set up via `references/authentication.md`) and forwards everything else to `myl`.\n\nIf the user has aliased the wrapper, replace `bash scripts/imap.sh` with the alias name. A typical setup:\n\n```bash\nalias imap='bash ~/.openclaw/skills/imap-client/scripts/imap.sh'\n```\n\n…and then `imap --count 5` is enough.\n\n## Listing messages\n\n```bash\n# Most recent N messages in INBOX (default folder)\nbash scripts/imap.sh --count 10\n\n# Specific folder\nbash scripts/imap.sh --folder \"INBOX/Archive\" --count 20\n\n# When --folder is omitted, myl operates on INBOX. To discover what folders\n# exist, run a list against INBOX first; some myl versions surface folder\n# listings in the output, others require the `--list-folders` flag if\n# present in your version.\n```\n\n### Folder names by provider\n\nFolder naming differs per server. When the user names a folder casually (\"sent items\", \"spam\", \"корзина\"), translate to the IMAP path the server expects.\n\n| Provider | Inbox | Sent | Drafts | Archive | Trash | Spam |\n|---|---|---|---|---|---|---|\n| Gmail | `INBOX` | `[Gmail]/Sent Mail` | `[Gmail]/Drafts` | `[Gmail]/All Mail` | `[Gmail]/Trash` | `[Gmail]/Spam` |\n| Yandex | `INBOX` | `Sent` (alias for `Отправленные`) | `Drafts` | n/a | `Trash` | `Spam` |\n| Mail.ru | `INBOX` | `Sent` | `Drafts` | `Archive` | `Trash` | `Spam` |\n| Fastmail | `INBOX` | `Sent` | `Drafts` | `Archive` | `Trash` | `Junk Mail` |\n| iCloud | `INBOX` | `Sent Messages` | `Drafts` | `Archive` | `Deleted Messages` | `Junk` |\n| Generic Dovecot | `INBOX` | `Sent` | `Drafts` | (configurable) | `Trash` | `Junk` |\n\nNotes on Russian providers:\n\n- **Yandex** publishes both English (`Sent`, `Drafts`, `Trash`) and Russian (`Отправленные`, `Черновики`, `Удалённые`) folder names; the English ones are aliases that always work, so prefer those.\n- **Mail.ru** uses English internal folder names over IMAP, even when the web UI shows Russian labels.\n- If a custom folder uses Cyrillic, it may be encoded in modified UTF-7 over IMAP. Pass the **exact string `myl` shows in listings**, not what you see in the web client.\n\nIf the first folder guess fails, list the available folders by running with no `--folder` and inspect the output; do not guess repeatedly.\n\n## Searching\n\n`myl --search` issues an IMAP `SEARCH` command. The argument is interpreted by the server, not by `myl`.\n\n```bash\n# Match against subject + body (default for most servers)\nbash scripts/imap.sh --search \"invoice\"\n\n# Combine with folder + count\nbash scripts/imap.sh --folder \"INBOX\" --search \"Acme\" --count 50\n```\n\n### What IMAP SEARCH actually supports\n\nStandard IMAP `SEARCH` keys (RFC 3501). Widely supported:\n\n| Key | Meaning | Example |\n|---|---|---|\n| `FROM \"x\"` | sender contains x | `FROM \"noreply@github.com\"` |\n| `TO \"x\"` | recipient contains x | `TO \"alice@example.com\"` |\n| `SUBJECT \"x\"` | subject contains x | `SUBJECT \"invoice\"` |\n| `BODY \"x\"` | body contains x | `BODY \"API key\"` |\n| `TEXT \"x\"` | header or body contains x | `TEXT \"kubernetes\"` |\n| `SINCE 1-Jan-2026` | received on or after date | `SINCE 1-Apr-2026` |\n| `BEFORE 1-Apr-2026` | received before date | `BEFORE 1-May-2026` |\n| `UNSEEN` | not yet marked read | `UNSEEN` |\n| `SEEN` | already read | |\n| `FLAGGED` | starred / flagged | |\n| `LARGER 10000000` | size in bytes | `LARGER 5000000` |\n\nIn practice, the safe approaches are:\n\n1. Pass a single keyword or short phrase: `--search \"invoice\"`. The server treats this as `TEXT \"invoice\"`.\n2. For complex filters, fetch a reasonable window and post-process locally with `grep` / `awk` / a small Python helper.\n\nWhat `myl --search` does **not** understand:\n\n- Gmail's web UI operators: `from:`, `has:attachment`, `label:`, `older_than:` — these are Gmail-specific and not part of IMAP SEARCH.\n- Yandex's web search syntax (e.g. `from:`, `subject:`) — also web-only.\n- Boolean operators like `AND` / `OR` / `NOT` directly in the string. IMAP supports them but with different syntax.\n\n### Cyrillic search terms\n\nYandex and Mail.ru both support searching for Cyrillic text via IMAP, but the term must be sent in the right charset. `myl` typically forwards the argument as-is and lets the server figure it out:\n\n```bash\nbash scripts/imap.sh --search \"счёт\" --count 20\n```\n\nIf the server returns no results for a Cyrillic term you know exists, retry with the Latin transliteration of the company name (since most senders include both in subject lines).\n\n## Reading a specific message\n\nEach listing shows a per-folder message ID. Fetch it by passing the ID as a positional argument:\n\n```bash\nbash scripts/imap.sh \"$MAILID\"           # plain text body\nbash scripts/imap.sh --html \"$MAILID\"    # HTML body (if present)\nbash scripts/imap.sh --raw \"$MAILID\"     # full raw RFC 5322 source, including headers\n```\n\nFor HTML and raw, redirect to a file rather than dumping into the terminal:\n\n```bash\nbash scripts/imap.sh --html \"$MAILID\" > \"/tmp/mail-${MAILID}.html\"\nbash scripts/imap.sh --raw  \"$MAILID\" > \"/tmp/mail-${MAILID}.eml\"\n```\n\nTell the user the file path and offer to open or summarise it.\n\n## Marking as seen\n\n```bash\nbash scripts/imap.sh --mark-seen --count 10\n```\n\nMutates server state. Only use when the user explicitly asked to mark messages read. Never combine `--mark-seen` with a search / list that the user is just exploring.\n\n## Attachments\n\n```bash\n# 1. Open the message — myl shows attachment names in the message detail\nbash scripts/imap.sh \"$MAILID\"\n\n# 2. Fetch a specific attachment by name\nbash scripts/imap.sh \"$MAILID\" \"invoice-2026-04.pdf\" > ~/Downloads/invoice-2026-04.pdf\n```\n\nThe second positional argument after `$MAILID` is the attachment filename. Output goes to stdout, so always redirect to a file.\n\nIf the attachment name has spaces or special characters, quote it:\n\n```bash\nbash scripts/imap.sh \"$MAILID\" \"Q1 report.pdf\" > \"$HOME/Downloads/Q1 report.pdf\"\n```\n\nCyrillic attachment names work but the underlying IMAP encoding (RFC 2047 / RFC 2231) varies. If the literal Cyrillic name doesn't match, retry with the encoded form `myl` showed in the message detail.\n\n## Full flag reference\n\nFrom the upstream README (`https://github.com/pschmitt/myl`). All of these forward through the wrapper:\n\n| Flag | Purpose |\n|---|---|\n| `--server HOST` | IMAP server hostname (set via `IMAP_SERVER` env) |\n| `--port N` | IMAP server port (set via `IMAP_PORT` env; default 993) |\n| `--starttls` | Upgrade plain connection to TLS (set via `IMAP_STARTTLS=1`) |\n| `--auto` | Autodiscover server + port (set via `IMAP_PROVIDER=auto`) |\n| `--google` | Hardcode Gmail's IMAP settings (set via `IMAP_PROVIDER=gmail`) |\n| `--username USER` | Login username (set via `IMAP_USER`) |\n| `--password PASS` | Login password (set via `IMAP_PASSWORD`) |\n| `--folder NAME` | IMAP folder to operate on (default `INBOX`) |\n| `--count N` | Number of messages to fetch in listings |\n| `--search QUERY` | Server-side IMAP SEARCH |\n| `--mark-seen` | Mark fetched messages as seen (mutates server state) |\n| `--\n\nArchive v0.1.0: 10 files, 27021 bytes\n\nFiles: README.md (6946b), references/authentication.md (8797b), references/installation.md (3734b), references/operations.md (8075b), references/recipes.md (6338b), references/troubleshooting.md (8165b), scripts/check_myl.sh (979b), scripts/imap.sh (4090b), SKILL.md (8686b), _meta.json (130b)","readmeExcerpt":"Skill: IMAP Client Owner: aggrrrh Summary: Read, search, and download email over IMAP from the command line using the myl CLI client. Use this skill whenever the user wants to interact with their ma... Tags: latest:0.1.3 Version history: v0.1.3 | 2026-04-26T09:46:40.962Z | user Fix misleading security claim in Principle 1: accurately document that the password is passed via myl argv and is visible in /proc/<pid>/cmdl","codeSnippets":[],"executableExamples":[{"language":"bash","snippet":"bash {baseDir}/scripts/imap.sh --count 5"},{"language":"text","snippet":"User asked something email-related from the CLI\n  │\n  ├─ Is `myl` installed and on PATH?  ── No  ──► references/installation.md\n  │   │\n  │   Yes\n  │   ▼\n  ├─ Does the wrapper smoke-test pass?\n  │     bash {baseDir}/scripts/imap.sh --count 1 >/dev/null\n  │   │                       No  ──► references/authentication.md\n  │   Yes\n  │   ▼\n  ├─ What does the user want?\n  │   ├─ Browse / list           ──► imap.sh --count N [--folder F]\n  │   ├─ Search                  ──► imap.sh --search \"TERM\" [--count N]\n  │   ├─ Read one message        ──► imap.sh \"$MAILID\"\n  │   ├─ Read HTML version       ──► imap.sh --html \"$MAILID\"  → save to file\n  │   ├─ Save raw .eml           ──► imap.sh --raw \"$MAILID\" > file.eml\n  │   ├─ Get attachment          ──► imap.sh \"$MAILID\" \"$ATT_NAME\" > file\n  │   └─ Anything multi-step     ──► references/recipes.md\n  │\n  └─ Errors? ─────────────────────► references/troubleshooting.md"},{"language":"bash","snippet":"pipx install myl"},{"language":"bash","snippet":"clawhub install imap-client"},{"language":"bash","snippet":"# OpenClaw\ngit clone https://github.com/codd-tech/imap-client ~/.openclaw/skills/imap-client\n\n# Claude Code\ngit clone https://github.com/codd-tech/imap-client ~/.claude/skills/imap-client\n\n# Generic AgentSkills runtime — drop the folder anywhere the runtime scans for SKILL.md"},{"language":"json","snippet":"{\n  \"skills\": {\n    \"entries\": {\n      \"imap-client\": {\n        \"enabled\": true,\n        \"env\": {\n          \"IMAP_USER\": \"you@yandex.ru\",\n          \"IMAP_PASSWORD\": \"app-specific-password-here\",\n          \"IMAP_PROVIDER\": \"yandex\"\n        }\n      }\n    }\n  }\n}"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: imap-client\ndescription: 'Read, search, and download email over IMAP from the command line using the `myl` CLI client. Use this skill whenever the user wants to interact with their mailbox from a terminal — checking the inbox, listing or searching messages, reading a specific email, opening HTML or raw source, or saving attachments. Trigger on any of these cues even when `myl` is not named explicitly — \"check my email\", \"look in my inbox\", \"search my mail for X\", \"find the email from Y\", \"download the attachment\", \"is there an email about Z\", \"read the latest message\", \"show me unread\", \"connect to my IMAP server\", \"imap.gmail.com\", \"imap.yandex.com\", \"imap.yandex.ru\", \"imap.mail.ru\", \"imap.fastmail.com\", \"Yandex Mail\", \"Mail.ru\", \"Gmail IMAP\", \"проверить почту\", \"новые письма\", \"найти письмо\", and similar. Also trigger when the user asks to script or automate any of the above. Do not trigger for outgoing mail (sending, SMTP, drafting) — `myl` is read-only — or for desktop/GUI mail clients.'\nlicense: MIT\nhomepage: https://github.com/codd-tech/imap-client\nmetadata: {\"openclaw\":{\"emoji\":\"📬\",\"requires\":{\"bins\":[\"myl\"],\"env\":[\"IMAP_USER\",\"IMAP_PASSWORD\"]},\"primaryEnv\":\"IMAP_PASSWORD\",\"install\":[{\"id\":\"pipx\",\"kind\":\"pipx\",\"package\":\"myl\",\"bins\":[\"myl\"],\"label\":\"Install myl via pipx\"}]}}\n---\n\n# imap-client\n\nRead mailboxes over IMAP from the terminal using `myl`, a small Python CLI client. Maintained and distributed by [codd-tech](https://github.com/codd-tech/imap-client). Designed to drop into [OpenClaw](https://openclaw.ai) and any other AgentSkills-compatible runtime (Claude Code, generic).\n\n`myl` is read-only and intentionally minimal: it lists, searches, and fetches messages and attachments. It does not send mail, manage folders, or modify state beyond optionally marking messages as seen.\n\n## How credentials reach this skill\n\nThis is the most important section. **You do not type passwords on the command line.** Credentials live in environment variables that the runtime injects per agent run. The skill reads them and assembles the right `myl` flags through the wrapper at `{baseDir}/scripts/imap.sh`.\n\nThe variables the wrapper expects:\n\n| Variable | Required | Purpose |\n|---|---|---|\n| `IMAP_USER` | yes | Login (usually full email address) |\n| `IMAP_PASSWORD` | yes | App-specific password (see `references/authentication.md`) |\n| `IMAP_PROVIDER` | no | One of `auto` (default), `gmail`, `yandex`, `mailru`, `manual` |\n| `IMAP_SERVER` | only with `manual` | IMAP host |\n| `IMAP_PORT` | no | Defaults to 993 |\n| `IMAP_STARTTLS` | no | `1` to add `--starttls` (use only with port 143) |\n\n**Set them once, use them every session.** How depends on the runtime — `references/authentication.md` covers OpenClaw's `skills.entries.imap-client.env`, generic shell `export`, and a `~/.config/imap-client/credentials` fallback file. Do not invent your own scheme; use one of those three.\n\nIf the wrapper detects `IMAP_USER` or `IMAP_PASSWORD` is missing, it prints"},{"path":"README.md","content":"# imap-client\n\n[![Install via ClawHub](https://img.shields.io/badge/install-clawhub-2563eb?style=flat-square)](https://clawhub.ai/aggrrrh/imap-client)\n[![License: MIT](https://img.shields.io/github/license/codd-tech/imap-client?style=flat-square)](./LICENSE)\n[![Maintained by codd.tech](https://img.shields.io/badge/maintained%20by-codd.tech-f97316?style=flat-square)](https://codd.tech)\n[![Stars](https://img.shields.io/github/stars/codd-tech/imap-client?style=flat-square)](https://github.com/codd-tech/imap-client/stargazers)\n\nAn agent skill for [OpenClaw](https://openclaw.ai), Claude Code, and other AgentSkills-compatible runtimes. Lets the agent read, search, and download email over IMAP from the command line via the [`myl`](https://github.com/pschmitt/myl) CLI client.\n\n`myl` is a small read-only IMAP client. This skill teaches the agent **when** to reach for it, **how** to install it, **how to source credentials safely** from the runtime's environment-injection mechanism, and **which** flags to use for common tasks — without ever asking for the password mid-session.\n\n## What this skill enables\n\nOnce installed and configured once, the agent will recognise prompts like:\n\n- *\"check my inbox\"*\n- *\"any new email from Acme today?\"*\n- *\"find the email with the AWS invoice and save the PDF\"*\n- *\"show me the HTML version of the newsletter from yesterday\"*\n- *\"download all unread messages as `.eml` files\"*\n- *\"проверь почту на Яндексе\"*\n- *\"найди письмо от налоговой\"*\n\n…and translate them into safe `myl` invocations through the wrapper at `scripts/imap.sh`, summarising the result back in chat.\n\n## Provider support\n\nFirst-class support, with `IMAP_PROVIDER` shortcuts:\n\n- **Gmail** / Google Workspace (`IMAP_PROVIDER=gmail`)\n- **Yandex Mail** — `@yandex.ru`, `@yandex.com`, Yandex 360 custom domains (`IMAP_PROVIDER=yandex`)\n- **Mail.ru** — `@mail.ru`, `@bk.ru`, `@inbox.ru`, `@list.ru` (`IMAP_PROVIDER=mailru`)\n\nPlus autodiscovery for most other providers (Fastmail, iCloud, ISPs) and explicit `manual` mode for self-hosted / corporate servers.\n\n## Quick start\n\n### 1. Install `myl`\n\n```bash\npipx install myl\n```\n\n(Or `pip install --user myl`, or `nix run github:pschmitt/myl`.)\n\n### 2. Get an app-specific password from your provider\n\nAccount settings → app passwords / external app passwords. Direct links per provider in [`references/authentication.md`](./references/authentication.md).\n\n### 3. Install the skill\n\n**Recommended — via ClawHub:**\n\n```bash\nclawhub install imap-client\n```\n\n**Or clone directly:**\n\n```bash\n# OpenClaw\ngit clone https://github.com/codd-tech/imap-client ~/.openclaw/skills/imap-client\n\n# Claude Code\ngit clone https://github.com/codd-tech/imap-client ~/.claude/skills/imap-client\n\n# Generic AgentSkills runtime — drop the folder anywhere the runtime scans for SKILL.md\n```\n\nRestart the session. OpenClaw picks the skill up automatically. The skill declares `requires.bins: [\"myl\"]` so it filters itself out if `myl` isn't on `PATH` — you'll never get a"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn78q4f09z7as2hbshyxss9sk185ht5d\",\n  \"slug\": \"imap-client\",\n  \"version\": \"0.1.3\",\n  \"publishedAt\": 1777196800962\n}"},{"path":"references/authentication.md","content":"# Authentication & Connection\n\nThis is the most security-sensitive part of the skill. Read it before configuring credentials anywhere.\n\n## The model in one paragraph\n\nCredentials live as **environment variables** that the runtime injects per agent run. The wrapper at `scripts/imap.sh` reads those env vars, picks the right `myl` connection flags, and never echoes the password. **You configure once, you read mail forever.**\n\n## Setting up credentials — pick one method\n\n### Method A — OpenClaw (recommended for OpenClaw users)\n\nOpenClaw injects `skills.entries.<key>.env` into `process.env` for the duration of each agent turn, then restores the original environment. This is documented behaviour: see https://docs.openclaw.ai/tools/skills under \"Environment injection (per agent run)\".\n\nEdit `~/.openclaw/openclaw.json` and add an entry under `skills.entries`:\n\n```json\n{\n  \"skills\": {\n    \"entries\": {\n      \"imap-client\": {\n        \"enabled\": true,\n        \"env\": {\n          \"IMAP_USER\": \"you@example.com\",\n          \"IMAP_PASSWORD\": \"app-specific-password-here\",\n          \"IMAP_PROVIDER\": \"auto\"\n        }\n      }\n    }\n  }\n}\n```\n\nThen restart the agent session (or wait for the skills watcher to pick it up if `skills.load.watch` is enabled). The next time the agent runs the skill, `IMAP_USER` and `IMAP_PASSWORD` are already in the environment.\n\n**Permissions matter.** `~/.openclaw/openclaw.json` should not be world-readable:\n\n```bash\nchmod 600 ~/.openclaw/openclaw.json\n```\n\n**Use `apiKey` with a SecretRef for stronger isolation.** OpenClaw supports pulling the password from a separate source rather than inlining it as plaintext in the JSON:\n\n```json\n{\n  \"skills\": {\n    \"entries\": {\n      \"imap-client\": {\n        \"enabled\": true,\n        \"apiKey\": { \"source\": \"env\", \"provider\": \"default\", \"id\": \"MY_IMAP_PASSWORD\" },\n        \"env\": {\n          \"IMAP_USER\": \"you@example.com\",\n          \"IMAP_PROVIDER\": \"auto\"\n        }\n      }\n    }\n  }\n}\n```\n\nThe `apiKey` field maps to whatever env var name is declared in `metadata.openclaw.primaryEnv` of `SKILL.md` — for this skill that's `IMAP_PASSWORD`. So OpenClaw reads `MY_IMAP_PASSWORD` from your shell env (or another secret backend) and exposes it as `IMAP_PASSWORD` to the wrapper. The literal password never appears in `openclaw.json`.\n\n### Method B — Generic shell `export`\n\nFor Claude Code and other AgentSkills runtimes that don't have OpenClaw's injection mechanism, just export the variables in the shell that launches the agent:\n\n```bash\nexport IMAP_USER='you@example.com'\nexport IMAP_PASSWORD='app-specific-password-here'\nexport IMAP_PROVIDER='auto'\n```\n\nPut this in `~/.bashrc` / `~/.zshrc` if you want it to persist. The downside compared to Method A is that the variables are global to that shell, not scoped to the agent run. The upside is no extra config file.\n\n### Method C — Credentials file fallback\n\nWhen neither Method A nor B is convenient (e.g. cron jobs, headless workflows, CI), drop a credentials file at `~/."},{"path":"references/installation.md","content":"# Installation\n\n`myl` is a Python package. There are several ways to install it; pick the first one that fits the user's environment.\n\n## How OpenClaw handles this\n\nThis skill declares `requires.bins: [\"myl\"]` in `metadata.openclaw`. OpenClaw checks for `myl` on `PATH` at skill load time and **silently filters this skill out** if it's missing, preventing the agent from invoking it without a working binary.\n\nIt also declares an `install` block:\n\n```json\n{ \"id\": \"pipx\", \"kind\": \"pipx\", \"package\": \"myl\", \"bins\": [\"myl\"] }\n```\n\nIn OpenClaw's macOS Skills UI this surfaces a one-click install button. From the CLI the user installs `myl` themselves with one of the methods below — the install block is hint metadata, not an automated runtime installer.\n\nFor non-OpenClaw runtimes (Claude Code, generic), there's no automatic gating. Run `bash scripts/check_myl.sh` first to confirm `myl` is present.\n\n## Detect what's already there\n\nAlways check before installing:\n\n```bash\nbash scripts/check_myl.sh\n```\n\nOr inline:\n\n```bash\nif command -v myl >/dev/null 2>&1; then\n  echo \"myl is installed: $(command -v myl) ($(myl --version 2>/dev/null || echo 'version unknown'))\"\nelse\n  echo \"myl is not on PATH\"\nfi\n```\n\nIf `myl` is present, skip the rest of this file and move on to `authentication.md`.\n\n## Install paths, in order of preference\n\n### `pipx` — recommended\n\nIsolates `myl` and its dependencies from system Python. This is what the upstream README recommends and what the skill's `install` metadata suggests.\n\n```bash\n# Install pipx itself if missing (Debian/Ubuntu)\nsudo apt update && sudo apt install -y pipx\npipx ensurepath\n\n# Install myl\npipx install myl\n```\n\nOn macOS:\n\n```bash\nbrew install pipx\npipx ensurepath\npipx install myl\n```\n\nAfter `pipx ensurepath`, the user may need to restart their shell or `source ~/.bashrc` / `source ~/.zshrc` for `myl` to appear on `PATH`.\n\n### `pip --user` — fallback when `pipx` isn't available\n\n```bash\npip install --user myl\n```\n\nThe binary lands in `~/.local/bin`, which must be on `PATH`. If not:\n\n```bash\necho 'export PATH=\"$HOME/.local/bin:$PATH\"' >> ~/.bashrc\n```\n\n### Nix flake — for Nix users\n\n```bash\n# One-shot run without installing\nnix run github:pschmitt/myl -- --help\n\n# Or add to a flake\n```\n\n### From source\n\n```bash\ngit clone https://github.com/pschmitt/myl.git\ncd myl\npipx install .\n```\n\n## Sandboxed agent runs\n\nIf the agent runs inside a Docker sandbox (OpenClaw `agents.defaults.sandbox.docker`), `myl` must be installed **inside the container** as well — the host bin doesn't satisfy the in-sandbox requirement. Add to `setupCommand`:\n\n```json\n{\n  \"agents\": {\n    \"defaults\": {\n      \"sandbox\": {\n        \"docker\": {\n          \"setupCommand\": \"pipx install myl || pip install --user --break-system-packages myl\"\n        }\n      }\n    }\n  }\n}\n```\n\nSandbox installs also need network egress, a writable root FS, and root user inside the container. See OpenClaw's sandboxing docs for details.\n\n## Confirm before installing\n\n`myl` is a th"}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":null,"editorialQuality":{"score":100,"threshold":65,"status":"thin","wordCount":1819,"uniquenessScore":42,"reasons":["uniqueness-below-45"]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-11T13:01:16.763Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-11T13:01:16.763Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-11T16:01:20.117Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}