Submail client
Read emails from a Submail virtual inbox using the submail CLI. Use when an agent needs to check, list, or retrieve emails delivered to its inbox address.From its SKILL.md
npx -y skills add chickenzord/submail --skill submail-clientAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
7.1 KB, ~1.7k tokens by cl100k_base, as published. Nobody here has run it
Submail Client Skill
Submail is a virtual inbox router. Each agent has a dedicated email address and
API token. This skill covers everything needed to configure and use the
submail CLI to access that inbox.
Prerequisites
submailbinary is on$PATH- You know your server URL, agent token, and (optionally) your profile name
Step 1 — Configure a profile (one-time setup)
Profiles store the server URL and token so you never pass them as flags.
Profile files live at ~/.config/submail/profiles/<name>.yaml.
submail profile set <profile-name> \
--url <server-url> \
--token <your-agent-token>
Example:
submail profile set hawkeye \
--url http://localhost:8080 \
--token hawkeye-secret-token
Validate the profile was saved correctly
submail profile show <profile-name> --json
Expected output (token is always masked):
{"name":"hawkeye","token_set":true,"url":"http://localhost:8080"}
Check: token_set must be true and url must be non-empty. If either is
wrong, re-run profile set with the correct values.
Set the active profile for this agent session
export SUBMAIL_PROFILE=<profile-name>
After this, all submail inbox commands use the profile automatically — no
--url or --token flags needed.
Step 2 — Verify connectivity
Run a quick sanity check before doing real work:
submail inbox list --json --limit 1
| Exit code | Meaning | Fix |
|---|---|---|
0 | Connected and authenticated | — |
4 | Token rejected | Re-run profile set with the correct token |
1 | Server unreachable | Check url in the profile; confirm server is running |
A successful response looks like:
{"mails":[...],"total":5,"limit":1,"offset":0}
If total is 0 the inbox is empty — that is not an error.
Available tasks
List messages
submail inbox list --json
Response schema:
{
"mails": [
{
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"message_id": "<[email protected]>",
"subject": "Subject line",
"from": "[email protected]",
"to": "[email protected]",
"received_at": "2026-01-01T00:00:00Z"
}
],
"total": 42,
"limit": 50,
"offset": 0
}
Key fields:
id— UUID used to fetch the full message; use this ininbox getreceived_at— ISO 8601 UTC timestamptotal— total matching messages (ignoreslimit/offset)mailsmay be an empty array[]— that is not an error
Pagination
# First page
submail inbox list --json --limit 20 --offset 0
# Second page
submail inbox list --json --limit 20 --offset 20
Iterate until offset + len(mails) >= total.
Get only IDs (pipe-friendly)
submail inbox list --quiet
Outputs one UUID per line. Useful for looping or piping.
Get a single message
submail inbox get --json <id>
<id> must be a lowercase UUID (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).
Obtain it from the id field in inbox list.
Response schema (same as list items, plus body fields):
{
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"message_id": "<[email protected]>",
"subject": "Subject line",
"from": "[email protected]",
"to": "[email protected]",
"received_at": "2026-01-01T00:00:00Z",
"text_body": "Plain-text content of the email.",
"html_body": "<html>...</html>"
}
text_body— prefer this for content parsing; may be empty for HTML-only emailshtml_body— raw HTML; present when the sender included an HTML part- Both fields are omitted (not
null) when absent
Exit codes
| Code | Meaning | Retryable |
|---|---|---|
0 | Success | — |
2 | Bad input (e.g. malformed UUID) | No — fix the input |
3 | Message not found | No |
4 | Unauthorized — wrong token | No — fix the profile |
1 | Server / network error | Yes |
Always check $? after each command. On non-zero exit (JSON mode), stdout
contains a structured error:
{
"error": "not_found",
"message": "mail not found",
"input": {"id": "00000000-0000-0000-0000-000000000000"},
"retryable": false
}
Use retryable to decide whether to retry or abort.
Common workflows
Read the most recent message
ID=$(submail inbox list --quiet --limit 1)
submail inbox get --json "$ID"
Process all messages newest-first
LIMIT=20
OFFSET=0
while true; do
PAGE=$(submail inbox list --json --limit $LIMIT --offset $OFFSET)
TOTAL=$(echo "$PAGE" | jq '.total')
IDS=$(echo "$PAGE" | jq -r '.mails[].id')
for ID in $IDS; do
submail inbox get --json "$ID" | jq '.text_body'
done
OFFSET=$((OFFSET + LIMIT))
[ $OFFSET -ge $TOTAL ] && break
done
Check for new mail since a known timestamp
inbox list does not have a since filter — fetch the list and filter
client-side by received_at:
submail inbox list --json --limit 50 | \
jq '[.mails[] | select(.received_at > "2026-01-01T00:00:00Z")]'
Profile reference
| Command | Purpose |
|---|---|
submail profile set <name> --url URL --token TOKEN | Create or update a profile |
submail profile show <name> --json | Verify a profile (token masked) |
submail profile list --json | List all configured profiles |
submail profile delete <name> | Remove a profile |
Profile files are stored at ~/.config/submail/profiles/<name>.yaml with
mode 0600 (readable only by the current OS user).
Credential precedence (most specific wins)
--url/--tokenflagsSUBMAIL_URL/SUBMAIL_TOKENenvironment variables--profileflag orSUBMAIL_PROFILEenvironment variable~/.config/submail/profiles/default.yaml(silent fallback)
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.