| name | add-email-account |
| description | Register an email mailbox for skills to operate on — reading, triage, drafting, bulk archive. NOT a channel; inbound emails will not wake the agent. For email-as-a-channel, use /add-gmail instead. Supports Google Workspace (Gmail), Microsoft 365 (Outlook/Exchange), and IMAP. |
Add Email Account
Register email accounts that other skills (/email-archive, /email-triage, etc.) can operate on. Each account has a provider type, credentials, and a verified connection.
This is for reading / triage / drafting — not a channel.
/add-email-account registers a mailbox that skills act on: batch-classifying old mail, summarizing the inbox, drafting replies you still send by hand. Incoming emails do not trigger the agent here.
If you want emails to wake the agent — route inbound mail into a chat thread, reply via the agent, etc. — that's a channel. Use /add-gmail instead. You can have both: a mailbox registered for triage here AND the same address wired as a channel via /add-gmail.
Detect Group
MAIN_FOLDER=$(sqlite3 store/nanoclaw.db "SELECT folder FROM registered_groups WHERE is_main = 1 LIMIT 1;" 2>/dev/null)
echo "MAIN_FOLDER=${MAIN_FOLDER:-unknown}"
If empty, ask:
Which group folder should I configure email accounts for?
Check Existing Accounts
test -f "groups/${MAIN_FOLDER}/email-accounts.yaml" && cat "groups/${MAIN_FOLDER}/email-accounts.yaml" || echo "NO_ACCOUNTS"
If accounts exist, show them:
Registered email accounts:
- gmail — Google Workspace (@.com) ✓
- outlook — Microsoft 365 (@.edu) ✓
What would you like to do?
- Add another account
- Remove an existing account
- Test an existing account
- Done
If no accounts exist, proceed to add one.
Add Account
Step 1: Choose provider
What type of email account?
- Google Workspace / Gmail (MCP) — uses
workspace-mcp, BYO OAuth client, structured MCP tools (recommended)
- Microsoft 365 / Outlook / Exchange — uses MS365 MCP, OAuth authentication
- IMAP — any standard mail server (iCloud, university, self-hosted)
- Google Workspace / Gmail (CLI, deprecated) — legacy
gws binary. Kept for backward compatibility with existing type: gws accounts. Don't pick this for new setups.
Use AskUserQuestion to get the choice.
Step 2: Authenticate (provider-specific)
Type: gws_mcp (Google Workspace via workspace-mcp — recommended)
First-time setup requires a Google Cloud OAuth Desktop Client. If the user hasn't created one, link them to:
https://console.cloud.google.com/apis/credentials → Create Credentials → OAuth client ID → Desktop app
Save the client ID and secret into .env:
GOOGLE_OAUTH_CLIENT_ID=...
GOOGLE_OAUTH_CLIENT_SECRET=...
Check if tokens already exist:
ls ~/.nanoclaw/.gws-mcp-tokens/*.json 2>/dev/null
If any *.json files exist, authentication is already set up. Extract the email from the filename (workspace-mcp names tokens {sanitized_email}.json) or parse one of the JSON files for the email field.
If no tokens exist:
Google Workspace (MCP) needs authentication. Please run:
! npm run provider-login gws_mcp
This runs scripts/gws-mcp-login.sh which launches workspace-mcp, triggers OAuth via a browser, and writes the token to ~/.nanoclaw/.gws-mcp-tokens/{your_email}.json. Once complete, tell me to continue.
After auth, verify tokens exist:
ls ~/.nanoclaw/.gws-mcp-tokens/*.json
Extract the email from the filename (strip .json, un-sanitize if needed) or from the JSON content.
Type: gws (Google Workspace CLI — deprecated)
Legacy path. Use only if the user explicitly wants to keep an existing type: gws account working. New setups should use gws_mcp above.
Check if already authenticated:
GWS_CREDENTIAL_STORE=plaintext gws gmail users getProfile --format json 2>&1
If authenticated, extract the email address. If not:
The legacy gws CLI needs auth. Run ! gws auth login, then tell me to continue.
Verify tokens are in place for container mounting:
test -d ~/.nanoclaw/.gws-tokens || mkdir -p ~/.nanoclaw/.gws-tokens
cp ~/.config/gws/credentials.json ~/.nanoclaw/.gws-tokens/ 2>/dev/null
cp ~/.config/gws/client_secret.json ~/.nanoclaw/.gws-tokens/ 2>/dev/null
Type: ms365 (Microsoft 365 / Outlook / Exchange)
Check if already authenticated:
test -f ~/.nanoclaw/.ms365-tokens/.token-cache.json && echo "MS365_OK" || echo "MS365_NOT_FOUND"
If not authenticated:
Microsoft 365 needs authentication. Please run:
! npm run ms365-login
This will open a browser for OAuth consent. Once complete, tell me to continue.
After auth, verify by checking the token file exists and ask the user for their email address:
What email address is this account for? (e.g., user@clemson.edu)
Type: imap (Standard IMAP)
Collect connection details via AskUserQuestion:
IMAP server details:
- Email address (e.g., user@icloud.com)
- IMAP server (e.g., imap.mail.me.com)
- Port (default: 993)
- Security (SSL/TLS — default, or STARTTLS)
- Username (usually the email address)
- App password (NOT your regular password — generate one in your email provider's security settings)
For common providers, auto-fill server details:
- iCloud:
imap.mail.me.com:993
- Yahoo:
imap.mail.yahoo.com:993
- Fastmail:
imap.fastmail.com:993
- ProtonMail: requires ProtonMail Bridge (
127.0.0.1:1143)
Store credentials securely:
mkdir -p ~/.nanoclaw/.imap-tokens
cat > ~/.nanoclaw/.imap-tokens/${ACCOUNT_ID}.json << 'EOF'
{
"host": "imap.mail.me.com",
"port": 993,
"security": "ssl",
"username": "user@icloud.com",
"password": "xxxx-xxxx-xxxx-xxxx"
}
EOF
chmod 600 ~/.nanoclaw/.imap-tokens/${ACCOUNT_ID}.json
Note: IMAP support requires an IMAP MCP server or CLI tool in the container. If one is not yet available, tell the user:
IMAP accounts are registered but not yet operational — an IMAP tool needs to be added to the container. The gws and ms365 providers are ready to use now.
Step 3: Choose an account ID
Suggest a short ID based on the provider and email:
I'll call this account gmail (or outlook, icloud, etc.). Want a different name?
The ID must be unique, lowercase, alphanumeric + hyphens.
Step 4: Verify connection
Test that the account can list inbox messages.
gws_mcp:
Call mcp__gws_mcp__search_gmail_messages with query "in:inbox" and max_results 3.
gws (deprecated):
GWS_CREDENTIAL_STORE=plaintext gws gmail +triage --max 3 --format json
ms365:
Call mcp__ms365__list-mail-messages to get 3 recent messages.
imap: Skip verification for now if no IMAP tool is available.
Report:
✓ Connected to @.com (Gmail)
Found 3 recent messages — account is working.
Step 5: Save account
Write or update groups/${MAIN_FOLDER}/email-accounts.yaml:
accounts:
- id: gmail
type: gws_mcp
address: <your-email>@<gws-domain>.com
enabled: true
added: "2026-04-18"
- id: outlook
type: ms365
address: <your-email>@<your-org>.edu
enabled: true
added: "2026-04-18"
If the file already exists, append the new account (don't overwrite existing entries).
Step 6: Done
Account ACCOUNT_ID registered (TYPE — ADDRESS).
This account is now available to email skills:
/add-email-archive — bulk sort old emails toward inbox zero
/email-triage — daily inbox management (coming soon)
Add another account? Or type done to finish.
If the user wants to add another, loop back to Step 1.
Remove Account
If the user chose "Remove":
Which account to remove?
List accounts with numbers. On selection, remove the entry from email-accounts.yaml. Don't delete credentials — just disable the account.
Test Account
If the user chose "Test":
Which account to test?
List accounts. Run the verification step (Step 4) for the selected account. Report success or failure.
Provider Operations Reference
This is the canonical reference for email operations by provider type. Other skills (/email-archive, /email-triage) should reference this.
Type: gws_mcp (Google Workspace via workspace-mcp)
All operations are MCP tool calls. Tool names follow the Gmail API verbs under the mcp__gws_mcp__ prefix. Exact signatures come from MCP discovery at runtime — the agent should list tools if uncertain.
| Operation | Tool (typical name) | Args |
|---|
| List inbox | mcp__gws_mcp__search_gmail_messages | query: "in:inbox", max_results: N |
| List with date filter | mcp__gws_mcp__search_gmail_messages | query: "in:inbox before:YYYY/MM/DD", max_results: N |
| Read message | mcp__gws_mcp__get_gmail_message | message_id: MSG_ID |
| List labels | mcp__gws_mcp__list_gmail_labels | — |
| Create label | mcp__gws_mcp__create_gmail_label | name: "NAME" |
| Move (label + archive) | mcp__gws_mcp__modify_gmail_message_labels | message_id: MSG_ID, add_labels: [LABEL_ID], remove_labels: ["INBOX"] |
| Batch move | mcp__gws_mcp__batch_modify_gmail_messages | message_ids: [...], add_labels: [LABEL_ID], remove_labels: ["INBOX"] |
Type: gws (Google Workspace CLI — deprecated, use gws_mcp for new setups)
| Operation | Command |
|---|
| List inbox | GWS_CREDENTIAL_STORE=plaintext gws gmail +triage --query "in:inbox" --max N --format json |
| List with date filter | GWS_CREDENTIAL_STORE=plaintext gws gmail +triage --query "in:inbox before:YYYY/MM/DD" --max N --format json |
| Read message | GWS_CREDENTIAL_STORE=plaintext gws gmail +read --id MSG_ID --headers --format json |
| List labels | GWS_CREDENTIAL_STORE=plaintext gws gmail users labels list --format json |
| Create label | GWS_CREDENTIAL_STORE=plaintext gws gmail users labels create --json '{"name":"NAME","labelListVisibility":"labelShow","messageListVisibility":"show"}' --format json |
| Move (label + archive) | GWS_CREDENTIAL_STORE=plaintext gws gmail users messages modify --params '{"id":"MSG_ID"}' --json '{"addLabelIds":["LABEL_ID"],"removeLabelIds":["INBOX"]}' |
| Batch move | GWS_CREDENTIAL_STORE=plaintext gws gmail users messages batchModify --json '{"ids":["ID1","ID2"],"addLabelIds":["LABEL_ID"],"removeLabelIds":["INBOX"]}' |
Type: ms365 (Microsoft 365)
| Operation | Tool |
|---|
| List inbox | mcp__ms365__list-mail-messages |
| Read message | mcp__ms365__get-mail-message with message ID |
| List folders | mcp__ms365__list-mail-folders |
| Create folder | mcp__ms365__create-mail-folder (parent before child for nested) |
| Move message | mcp__ms365__move-mail-message with message ID and destination folder ID |
Type: imap (Standard IMAP)
| Operation | Status |
|---|
| All operations | Pending — requires IMAP MCP server or CLI tool in container |
To add IMAP support: install an IMAP MCP server, register it in container/agent-runner/src/shared.ts, add tool names to allowedTools, and fill in this table.
Adding a new provider
- Add a type entry to this reference table
- Add detection + auth flow in Step 2 above
- Update the container skill's provider dispatch
- No changes needed to classification, rules, or state logic in consuming skills