Refactor high-complexity React components in Dify frontend. Use when `pnpm analyze-component...
npx skills add cshen/SKILLS --skill "mail139"
Install specific skill from multi-skill repository
# Description
Read, send, delete, reply, and forward email via IMAP/SMTP. Check for new/unread messages, fetch content, search mailboxes, mark as read/unread, and send emails with attachments. Works with any IMAP/SMTP server including Gmail, Outlook, 163.com, vip.163.com, etc.
# SKILL.md
name: mail139
slug: mail139
version: 1.0.0
description: Read, send, delete, reply, and forward email via IMAP/SMTP. Check for new/unread messages, fetch content, search mailboxes, mark as read/unread, and send emails with attachments. Works with any IMAP/SMTP server including Gmail, Outlook, 163.com, vip.163.com, etc.
metadata: {"clawdbot":{"emoji":"๐ฌ","requires":{"bins":["python3"]},"os":["linux","darwin","win32"]}}
mail139 โ 139.com Email Downloader ๐ฌ
Download and search emails from 139.com via IMAP using pure Python stdlib. No pip installs needed.
Prerequisites
MAIL139_IDโ 139.com email address (e.g.[email protected])MAIL139_TOKENโ account password/token (fallbacks: prompt orMAIL139_PASSWORD)- If either is missing, stop and tell the user to set them:
bash export MAIL139_ID="[email protected]" export MAIL139_TOKEN="your-password" - IMAP access must be enabled in the 139.com account settings (่ฎพ็ฝฎ โ POP3/SMTP/IMAP)
Tool Location
The CLI script is bundled with this skill:
{baseDir}/mail139.py
All commands follow the pattern:
python3 {baseDir}/mail139.py -u "$MAIL139_ID" -p "$MAIL139_TOKEN" <command> [options]
# or simply rely on env defaults:
[email protected] MAIL139_TOKEN=secret python3 {baseDir}/mail139.py <command> [options]
When to Use This Skill
Activate when the user wants to:
- Read, check, or view emails from their 139.com inbox
- Download or save emails to disk
- Search emails by keyword or date
- List mailbox folders on 139.com
- Export emails as JSON or .eml files
- Save email attachments from 139.com
- Delete an email from their 139.com account
- Reply to an email on 139.com
- Forward an email to another address from 139.com
Trigger phrases: "check my 139 email", "read my 139.com inbox", "download emails from 139", "search my 139 mail", "list my 139 folders", "save emails from 139.com", "delete email", "reply to email", "forward email", "139้ฎ็ฎฑ", "ไธญๅฝ็งปๅจ้ฎ็ฎฑ", "check inbox"
Commands Reference
List Folders
python3 {baseDir}/mail139.py -u "$MAIL139_ID" -p "$MAIL139_TOKEN" list-folders
Lists all IMAP mailboxes/folders on the account. Run this first if the user wants to fetch from a non-INBOX folder and you don't know the exact folder name.
Folder names are decoded from IMAP modified UTF-7 (handles Chinese names); copy the exact output when passing --folder.
Fetch Emails
python3 {baseDir}/mail139.py -u "$MAIL139_ID" -p "$MAIL139_TOKEN" fetch [options]
| Option | Default | Description |
|---|---|---|
--folder <name> |
INBOX |
IMAP folder to fetch from |
--limit <N> |
10 |
Max emails to fetch (newest first) |
--since <DD-Mon-YYYY> |
โ | Only emails on or after this date |
--search <text> |
โ | Filter by text in headers or body |
--format <fmt> |
text |
Output format: text, json, or eml |
--output <dir> / -o <dir> |
โ | Directory to save output files |
--save-attachments |
off | Save attachments (defaults to ~/Downloads if --output is omitted) |
--mark-read |
off | Mark fetched emails as read on the server |
For
--format eml, files are written to--output. If--outputis omitted, the existing~/Downloadsdirectory is used. If~/Downloadsdoes not exist, the command exits with an error.HTML bodies are converted to plain text via
html2text(if installed), elselynx --dump, else an internal stripper. No HTML tags appear in printed/JSON bodies.
Examples:
# Print latest 10 emails to console
python3 {baseDir}/mail139.py -u "$MAIL139_ID" -p "$MAIL139_TOKEN" fetch
# Fetch last 20 emails as JSON
python3 {baseDir}/mail139.py -u "$MAIL139_ID" -p "$MAIL139_TOKEN" fetch \
--limit 20 --format json
# Save as JSON to a directory
python3 {baseDir}/mail139.py -u "$MAIL139_ID" -p "$MAIL139_TOKEN" fetch \
--format json -o ./emails
# Save raw .eml files and extract attachments
python3 {baseDir}/mail139.py -u "$MAIL139_ID" -p "$MAIL139_TOKEN" fetch \
--format eml --save-attachments -o ./emails
# Fetch from Sent folder since a date
python3 {baseDir}/mail139.py -u "$MAIL139_ID" -p "$MAIL139_TOKEN" fetch \
--folder "Sent Messages" --since "01-Jan-2025" --limit 50
# Search for emails containing a keyword
python3 {baseDir}/mail139.py -u "$MAIL139_ID" -p "$MAIL139_TOKEN" fetch \
--search "invoice" --format json
Delete an Email
python3 {baseDir}/mail139.py -u "$MAIL139_ID" -p "$MAIL139_TOKEN" delete --uid <uid> [--folder INBOX] [--expunge]
| Option | Default | Description |
|---|---|---|
--uid <uid> |
required | UID of the email to delete |
--folder <name> |
INBOX |
IMAP folder containing the email |
--expunge |
off | Permanently remove immediately; without this, only sets \Deleted flag |
Without
--expunge, the message is flagged for deletion but not yet removed. Pass--expungeonly if the user explicitly asks to permanently delete.
# Flag for deletion (soft delete)
python3 {baseDir}/mail139.py -u "$MAIL139_ID" -p "$MAIL139_TOKEN" delete --uid 42
# Permanently delete
python3 {baseDir}/mail139.py -u "$MAIL139_ID" -p "$MAIL139_TOKEN" delete --uid 42 --expunge
# Delete from a specific folder
python3 {baseDir}/mail139.py -u "$MAIL139_ID" -p "$MAIL139_TOKEN" delete --uid 17 --folder "Sent Messages" --expunge
Reply to an Email
python3 {baseDir}/mail139.py -u "$MAIL139_ID" -p "$MAIL139_TOKEN" reply --uid <uid> --body "text" [--folder INBOX] [--reply-all]
| Option | Default | Description |
|---|---|---|
--uid <uid> |
required | UID of the email to reply to |
--body <text> |
required | Reply body. Use "-" to read from stdin |
--folder <name> |
INBOX |
IMAP folder containing the original email |
--reply-all |
off | Reply to all recipients (To + Cc), not just the sender |
# Simple reply
python3 {baseDir}/mail139.py -u "$MAIL139_ID" -p "$MAIL139_TOKEN" reply --uid 42 --body "Thanks, got it!"
# Reply-all
python3 {baseDir}/mail139.py -u "$MAIL139_ID" -p "$MAIL139_TOKEN" reply --uid 42 --body "See below." --reply-all
# Multi-line body from stdin
echo -e "Hi,\n\nPlease see my response." | python3 {baseDir}/mail139.py -u "$MAIL139_ID" -p "$MAIL139_TOKEN" reply --uid 42 --body -
Forward an Email
python3 {baseDir}/mail139.py -u "$MAIL139_ID" -p "$MAIL139_TOKEN" forward --uid <uid> --to [email protected] [--folder INBOX] [--body "note"]
| Option | Default | Description |
|---|---|---|
--uid <uid> |
required | UID of the email to forward |
--to <email> |
required | Recipient email address |
--folder <name> |
INBOX |
IMAP folder containing the original email |
--body <text> |
โ | Optional message prepended before the forwarded content |
# Forward with no preamble
python3 {baseDir}/mail139.py -u "$MAIL139_ID" -p "$MAIL139_TOKEN" forward --uid 42 --to [email protected]
# Forward with a note
python3 {baseDir}/mail139.py -u "$MAIL139_ID" -p "$MAIL139_TOKEN" forward --uid 42 --to [email protected] --body "FYI โ see below."
Output Format Details
text
Prints each email to stdout with a header block (UID, Date, From, To, Subject, Attachments) and up to 2 000 characters of body text. Ideal for quick reading.
json
Produces an array of objects. Each object has:
{
"uid": "1234",
"date": "Mon, 10 Mar 2025 09:00:00 +0800",
"from": "[email protected]",
"to": "[email protected]",
"subject": "Hello",
"content_type": "text/plain",
"body": "Email body textโฆ",
"attachments": ["report.pdf"]
}
Written to emails.json inside --output, or printed to stdout if no --output is given.
eml
Saves each email as <uid>.eml โ a raw RFC 822 file openable in any email client. Requires --output.
Important Details
Date Format for --since
Use IMAP date format: DD-Mon-YYYY โ e.g. 01-Jan-2025, 15-Mar-2026.
Folder Names
139.com folder names may be in Chinese. Always run list-folders first if unsure. Common folders:
- INBOX โ inbox (always English)
- Sent Messages โ sent mail
- Drafts โ drafts
- Deleted Messages โ trash
Attachment Saving
Attachments are saved to <output>/<uid>_attachments/<filename>. If --output is not set, attachments default to ~/Downloads/<uid>_attachments/. The --save-attachments flag works independently of --output. By default attachments are saved to ~/Downloads if --output is not specified.
Read-Only by Default
Without --mark-read, the script opens the mailbox read-only and leaves no server-side trace. Pass --mark-read only if the user explicitly asks to mark emails as read.
Behavioral Rules
- Always use
python3to invoke the script. - Prefer env vars for credentials (
$MAIL139_ID,$MAIL139_TOKENfallback$MAIL139_PASSWORD) โ never echo passwords in plain text in explanations. - If
MAIL139_IDorMAIL139_TOKENare not set, stop and ask the user to export them before proceeding (or be ready to prompt for password). - Default to
--format textfor casual "check my email" requests; usejsonwhen the user wants to process or save data; useemlwhen they want to archive or open in an email client. - When the user asks to search, use
--searchfor keyword filters and--sincefor date filters; combine both when appropriate. - When the user asks for a specific folder, run
list-foldersfirst if you are unsure of the exact folder name. - Do not use
--mark-readunless the user explicitly asks to mark emails as read. - After fetching JSON, parse and summarise the results for the user โ don't just dump the raw JSON unless asked.
- If a command fails, read stderr and explain the issue in plain language (e.g. wrong password, IMAP not enabled, network error).
- For attachment tasks,
--save-attachmentsworks without--outputโ attachments will be saved to~/Downloads/<uid>_attachments/by default. Only set--outputif the user wants a specific location. - For
delete, default to soft-delete (flag only, no--expunge). Only pass--expungewhen the user explicitly says "permanently delete" or "remove completely". - For
reply, use--reply-allonly when the user explicitly asks to reply to everyone. Default to replying only to the sender. - For
replyandforward, both IMAP (to fetch the original) and SMTP (to send) connections are established. The same credentials are used for both. - For multi-line reply bodies, suggest using stdin (
--body -) with a heredoc or echo pipe rather than embedding newlines in a shell argument.
# Supported AI Coding Agents
This skill is compatible with the SKILL.md standard and works with all major AI coding agents:
Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.