You can send and receive email as REPLACE_WITH_IDENTITY@agentmail.to using two Python scripts.
The scripts live in this skill folder and are deployed to ~/.openclaw/workspace/agentmail/.
The scripts contain placeholders which need to be replaced with real-life value:
Copy the scripts and create the venv in the workspace:
DEST=~/.openclaw/workspace/agentmail
SKILL_DIR="$(dirname "$(readlink -f "$0")")" # if running from a script
# or just point SKILL_DIR to this skill folder
mkdir -p "$DEST"
cp "$SKILL_DIR/check_mail.py" "$SKILL_DIR/send_email.py" "$DEST/"
cd "$DEST"
# Create venv (prefer uv, fall back to python)
if command -v uv &>/dev/null; then
uv venv venv
uv pip install --python venv/bin/python agentmail python-dotenv
else
python3 -m venv venv
venv/bin/pip install agentmail python-dotenv
fi
.env filecat > ~/.openclaw/workspace/agentmail/.env << 'EOF'
AGENTMAIL_API_KEY=am_us_.....
EOF
This is only necessary if you don't have the environment variable in your running environment or if you can't read it from your openclaw.json config file.
cd ~/.openclaw/workspace/agentmail
source venv/bin/activate
python check_mail.py # should print "No new mail." on a fresh inbox
cd ~/.openclaw/workspace/agentmail
source venv/bin/activate
python check_mail.py
This downloads all unread messages as JSON files into the workspace directory and marks them as read. Running it again only fetches new mail.
Each message is saved as MAIL. — timestamp from the message, 3-digit sequence number within the batch.
Example: MAIL.20260226T134244.001
The JSON inside contains:
{
"message_id": "<...>",
"thread_id": "...",
"timestamp": "2026-02-26 13:42:44+00:00",
"from": "Sender Name <sender@example.com>",
"to": ["REPLACE_WITH_IDENTITY@agentmail.to"],
"cc": null,
"subject": "Re: Hello",
"text": "Plain-text body...",
"html": "<p>HTML body...</p>",
"labels": ["received", "unread"],
"in_reply_to": "<original-message-id>",
"attachments": []
}
# List all mail files (oldest first)
ls -1 MAIL.* 2>/dev/null | sort
# Read one
cat MAIL.20260226T134244.001
# Extract just the text body
python -c "import json,sys; print(json.load(open(sys.argv[1]))['text'])" MAIL.20260226T134244.001
| Code | Meaning |
|---|---|
| ------ | --------- |
| 0 | Success (mail downloaded or inbox empty) |
| 1 | Missing API key |
| 2 | API error on initial listing |
| 3 | Total failure (all messages errored) |
cd ~/.openclaw/workspace/agentmail
source venv/bin/activate
python send_email.py
send_email.py is a template with hardcoded recipient/subject/body. For real use, modify its parameters or write a one-off script using the same pattern:
import os
from dotenv import load_dotenv
from agentmail import AgentMail
load_dotenv()
client = AgentMail(api_key=os.getenv("AGENTMAIL_API_KEY"))
client.inboxes.messages.send(
inbox_id="REPLACE_WITH_IDENTITY@agentmail.to",
to="recipient@example.com",
subject="Subject line",
text="Plain-text body.",
)
| Parameter | Required | Description |
|---|---|---|
| ----------- | ---------- | ------------- |
inbox_id | yes | Always "REPLACE_WITH_IDENTITY@agentmail.to" |
to | yes | Recipient email address |
subject | no | Subject line |
text | no | Plain-text body |
html | no | HTML body |
cc | no | CC addresses |
bcc | no | BCC addresses |
To reply in the same thread, use reply() with the message_id from a downloaded MAIL.* file:
import json, os
from dotenv import load_dotenv
from agentmail import AgentMail
load_dotenv()
client = AgentMail(api_key=os.getenv("AGENTMAIL_API_KEY"))
# Load the message you want to reply to
with open("MAIL.20260226T134244.001") as f:
msg = json.load(f)
client.inboxes.messages.reply(
inbox_id="REPLACE_WITH_IDENTITY@agentmail.to",
message_id=msg["message_id"],
text="This is my reply.",
)
This preserves threading — the reply appears in the same conversation as the original.
python check_mail.pyMAIL.* files that were createdreply() pattern from section 4rm MAIL.* when done processingcheck_mail.py again later for new messages共 1 个版本