hermes-skills/communication/email-send-from-arif-fazil/SKILL.md
Send email from [email protected] using secrets from /root/AAA/secrets/email.env. Handles the execute_code sandbox env-var visibility issue.
npx skillsauth add ariffazil/openclaw-workspace email-send-from-arif-fazilInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
execute_code (hermes_tools sandbox) CANNOT see env vars set by email.env via source /root/AAA/secrets/email.env. The sandbox has its own environment — os.environ.get('GMAIL_APP_PASSWORD', '') returns empty string inside execute_code, even though terminal() can see it fine.
Always use terminal() Python for email send, not execute_code().
File: /root/AAA/secrets/email.env
[email protected]
GMAIL_APP_PASSWORD=<16-char app password>
Use terminal() with inline Python that reads the password file directly:
python3 << 'EOF'
import smtplib, os
from email.message import EmailMessage
# Read password directly from file (bypasses sandbox env-var issue)
password = None
with open('/root/AAA/secrets/email.env') as f:
for line in f:
if 'GMAIL_APP_PASSWORD' in line and '=' in line:
password = line.strip().split('=', 1)[1].strip()
break
user = "[email protected]"
msg = EmailMessage()
msg["From"] = user
msg["To"] = "[email protected]"
msg["Subject"] = "Subject here"
msg.set_content("Body text here")
with smtplib.SMTP("smtp.gmail.com", 587) as server:
server.starttls()
server.login(user, password)
server.send_message(msg)
print("SENT OK")
EOF
starttls() — works from af-forge VPSSMTP_SSLzclv — if wrong, Gmail returns 535 Username and Password not acceptedSending FROM [email protected] requires separate SMTP config — currently not set up. All outgoing email via this method only sends FROM [email protected].
The Problem:
Gmail SMTP can silently REJECT your email at the auth layer. If your code saves to the Sent folder before calling server.send_message(), a Sent folder entry exists even when the SMTP call throws SMTPAuthenticationError. This creates a false "success" state — you see the email in Sent, but it was NEVER delivered to any recipient.
Error signature:
SMTPAuthenticationError: (535, b'5.7.8 Username and Password not accepted.')
Why it happens:
Correct verification pattern — do BOTH:
all_recipients = to_list + cc_list # flatten first!
try:
with smtplib.SMTP("smtp.gmail.com", 587) as server:
server.starttls()
server.login(GMAIL_USER, GMAIL_APP_PASSWORD)
# send_message returns {} on success, dict of failures on partial/total failure
result = server.send_message(msg, to_addrs=all_recipients)
if result:
print(f"⚠️ PARTIAL FAILURES: {result}")
else:
print(f"✅ DELIVERED to all {len(all_recipients)} recipients")
except smtplib.SMTPAuthenticationError as e:
print(f"❌ AUTH FAILED — email NOT sent. Fix app password at: https://myaccount.google.com/apppasswords")
raise # re-raise so you see the error
except Exception as e:
print(f"❌ SMTP ERROR: {e}")
raise
Key rules:
to_addrs — send_message(to_addrs=to_list + cc_list), not nested listsSMTPAuthenticationError specifically — it's the most common Gmail failure modesend_message() return value — empty dict {} = all delivered; non-empty = failures per recipientIf auth keeps failing, check:
/root/AAA/secrets/email.env with the new passwordBatch send (TO + CC + BCC):
TO = ["[email protected]", "[email protected]"]
CC = ["[email protected]", "[email protected]"]
BCC = ["[email protected]"]
msg["To"] = ", ".join(TO)
msg["Cc"] = ", ".join(CC)
# BCC goes only to send_message, not in headers
all_recipients = TO + CC + BCC
server.send_message(msg, to_addrs=all_recipients)
testing
OpenClaw edge agent bridge — operational triage, doctor, restart, and A2A bridge routing for the federation edge (Telegram surface). USE WHEN: "openclaw unhealthy", "gateway down", "edge bot not responding", "a2a bridge disconnected", "watchdog tripped", "openclaw doctor", "openclaw restart". NOT for token/security audit — use FORGE-telegram-audit.
tools
Generate images, videos, TTS, voice clone, and music via MiniMax MCP server. Use when user asks to "draw", "generate image", "create picture", "make a photo", "text to image", "image generation".
testing
Single load-bearing constitutional-judgment skill. Routes all F1–F13, verdict, hold, seal, scope, authority and floor-check calls through the live arif_judge surface. Replaces 7 overlapping predecessors (arifos-constitutional-judge, arifos-constitutional-judge, arifos-constitutional-judge, arifos-constitutional-judge, arifos-constitutional-judge, arifos-constitutional-judge, arifos-constitutional-judge).
development
MANDATORY LSP grounding gate BEFORE any code mutation on .ts, .py, .js, .tsx, .jsx files. Forces the agent to read real-time compiler diagnostics and structural project context before editing — eliminating blind guesses and anchoring every mutation in F2 (TRUTH). Routes through arifOS kernel (:8088) for centralized gate logic.