Ashari Abidin's Developer Docs

Email Automation using OpenClaw

โœง Email Automation OpenClaw + Gmail + Gemini

Headless Ubuntu ยท SSH ready ยท Smart drafts, never auto-send ยท AI orchestrated by OpenClaw & Gemini

๐Ÿ“ฌ Gmail API ๐Ÿค– OpenClaw Core ๐Ÿง  Gemini AI ๐Ÿ“ Draft Factory
๐Ÿ”ป FINAL ARCHITECTURE โ€“ PRODUCTION GRADE
๐Ÿ“ฅ Gmail Inbox โ†’ ๐Ÿ Python Worker โ†’ โš™๏ธ OpenClaw Agent โ†’ โœจ Gemini LLM โ†’ โœ๏ธ Generate Reply โ†’ ๐Ÿ“‚ Gmail Draft
Ubuntu Server
โ”œโ”€โ”€ OpenClaw (headless)
โ”œโ”€โ”€ Python Worker + venv
โ”œโ”€โ”€ Gmail API (OAuth2)
โ”œโ”€โ”€ Gemini via OpenClaw
โ”œโ”€โ”€ OpenClaw Scheduler (cron native)
โ””โ”€โ”€ Draft automation (review before send)

๐Ÿ“Œ 1. System dependencies & project setup

# Update & install python3, venv, pip
sudo apt update
sudo apt install -y python3 python3-pip python3-venv

# Create OpenClaw workspace
mkdir -p ~/.openclaw/gmail-ai
cd ~/.openclaw/gmail-ai

# Virtual environment
python3 -m venv venv
source venv/bin/activate # (venv) should appear

# Install required libs
pip install google-genai google-api-python-client google-auth-httplib2 google-auth-oauthlib python-dotenv

๐Ÿ” 2. Gmail API & OAuth setup (RED ZONE)

  • Go to Google Cloud Console โ†’ Enable Gmail API
  • Configure OAuth consent screen: External โ†’ Testing mode โ†’ Add your Gmail as Test User
  • Create OAuth Client ID type โ†’ Desktop app โ†’ Download JSON โ†’ rename to credentials.json
  • Place credentials.json inside ~/.openclaw/gmail-ai/
# Also generate Gemini API Key from:
# https://aistudio.google.com/app/apikey
nano .env
# inside .env file:
GEMINI_API_KEY=YOUR_API_KEY_HERE

๐Ÿค– 3. OpenClaw runtime check

openclaw status # should be running
openclaw chat "hello world" # test Gemini integration
โš ๏ธ OpenClaw dashboard runs on http://192.168.0.7:18789 (example). Make sure OpenClaw is properly installed before proceeding.

๐Ÿ 4. Python Worker โ€“ main.py (full automation script)

Create main.py with the core logic: fetch unread email โ†’ filter (blocked senders/promo) โ†’ prompt OpenClaw โ†’ Gemini reply โ†’ create Gmail draft.

import os, time, base64, subprocess
from dotenv import load_dotenv
from email.mime.text import MIMEText
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build

load_dotenv()
SCOPES = ['https://www.googleapis.com/auth/gmail.modify']
BLOCKED_SENDERS = ["bibit.id","jenius.com","tokopedia.com","shopee","lazada"]
BLOCKED_WORDS = ["unsubscribe","promo","diskon","cashback","newsletter"]

creds = None
if os.path.exists('token.json'):
 creds = Credentials.from_authorized_user_file('token.json', SCOPES)
if not creds or not creds.valid:
 if creds and creds.expired and creds.refresh_token:
 creds.refresh(Request())
 else:
 flow = InstalledAppFlow.from_client_secrets_file('credentials.json', SCOPES)
 creds = flow.run_local_server(host='localhost', port=8080, open_browser=False)
 with open('token.json', 'w') as token:
 token.write(creds.to_json())

service = build('gmail', 'v1', credentials=creds)
results = service.users().messages().list(userId='me', q='is:unread category:primary', maxResults=1).execute()
messages = results.get('messages', [])
if not messages:
 print("No unread email")
 exit()

msg_id = messages[0]['id']
msg = service.users().messages().get(userId='me', id=msg_id, format='full').execute()
payload = msg['payload']
headers = payload['headers']
subject = sender = ""
for h in headers:
 if h['name'] == 'Subject': subject = h['value']
 if h['name'] == 'From': sender = h['value']

body = ""
parts = payload.get('parts')
if parts:
 for part in parts:
 if part.get("mimeType") == "text/plain":
 body = base64.urlsafe_b64decode(part['body']['data']).decode('utf-8')
 break

# Filtering
for blocked in BLOCKED_SENDERS:
 if blocked in sender.lower(): print("SKIPPED BLOCKED SENDER"); exit()
for blocked in BLOCKED_WORDS:
 if blocked in subject.lower() or blocked in body.lower(): print("SKIPPED PROMO"); exit()

prompt = f"""Balas email berikut secara profesional dan singkat. Gunakan bahasa yang sama dengan email pengirim.
Jangan menulis: SUBJECT, EMAIL, markdown, template tambahan.
Hanya tulis isi balasan email final saja.

Email asli: {body}"""

reply_text = ""
for attempt in range(3):
 try:
 result = subprocess.run(["openclaw", "chat", prompt], capture_output=True, text=True)
 reply_text = result.stdout.strip()
 break
 except Exception as e:
 print(e)
 time.sleep(5)

reply_msg = MIMEText(reply_text)
reply_msg['to'] = sender
reply_msg['subject'] = "Re: " + subject
raw = base64.urlsafe_b64encode(reply_msg.as_bytes()).decode()
draft_body = {'message': {'raw': raw}}
draft = service.users().drafts().create(userId='me', body=draft_body).execute()
print("\nโœ… DRAFT CREATED in Gmail โ†’ Drafts folder")
print(draft)

๐Ÿ“ฌ 5. OAuth First Run & token generation

# Activate venv & run
source venv/bin/activate
python main.py

Terminal will output a Google authorization URL โ†’ open browser, login, allow access. token.json will be saved automatically.

โฑ๏ธ 6. DNS Fix (Ubuntu critical)

If you see Temporary failure in name resolution:
sudo nano /etc/resolv.conf โ†’ add
nameserver 8.8.8.8
nameserver 1.1.1.1
ping google.com # should resolve

๐Ÿš€ 7. run.sh wrapper & OpenClaw Cron scheduler

nano ~/.openclaw/gmail-ai/run.sh
#!/bin/bash
cd ~/.openclaw/gmail-ai
source venv/bin/activate
python main.py

chmod +x run.sh
./run.sh # test

โฒ๏ธ Native OpenClaw Cron (1 minute interval)

openclaw cron add --name "gmail-ai-worker" --every 60000 --session isolated --message "Execute ~/.openclaw/gmail-ai/run.sh"
openclaw cron list # verify
โšก 60000 ms = 1 minute. Worker will pull latest unread email, generate AI draft via Gemini, safe draft mode.

๐Ÿงช 8. Testing & verification

  • Send a test email to your automation Gmail account (non-promotional, clear content).
  • Run python main.py or wait for cron job.
  • Open Gmail โ†’ Drafts folder โ†’ AI generated reply appears, ready for human review.
  • No auto-send โ†’ prevents spam & hallucination risks.

๐Ÿญ Production & ideal architecture

๐Ÿ“ˆ Final Production Flow (OpenClaw Scheduler)
OpenClaw Cron โžก run.sh โžก main.py โžก Gmail API (fetch) โžก OpenClaw Agent โžก Gemini โžก Gmail Draft

โœ”๏ธ Draft-first strategy: AI never sends automatically. You review, edit, and send manually โ€” compliant and safe.

๐Ÿ“ˆ Next Recommended Upgrades (Tier roadmap)

1. Processed label
Move processed emails to "AI_processed" label.
2. Logging & retry handling
Structured logs, exponential backoff.
3. Classification layer
Route emails to specific agents.
4. Approval workflow
Slack/Telegram approval before draft.
5. Vector memory (RAG)
Recall past conversations for context.
6. PostgreSQL logging
Analytics and audit trail.
7. Dashboard monitoring
Real-time metrics + alerts.
8. WhatsApp integration
Multi-channel AI drafts.

๐Ÿง  Best Practices for Production

  • Draft mode only (no auto-send) โ€“ prevents AI mistakes and reputation risk.
  • Set up email filters for spam & automated out-of-office replies.
  • Regularly audit token.json permissions; refresh token stored securely.
  • Use dedicated Gmail account for automation (not personal primary).
  • Add human review stage (check drafts, then send).
๐Ÿ›ก๏ธ Security note: credentials.json and .env must never be public. Set file permissions: chmod 600 credentials.json .env

๐Ÿ› ๏ธ Troubleshooting & quick reference

# Re-authenticate Gmail if token expired
rm token.json && python main.py # fresh OAuth flow

# Check OpenClaw logs
openclaw logs --tail 30

# Manually test Gemini through OpenClaw
openclaw chat "Generate a professional email reply" 

# Cron Debug (if worker not running)
openclaw cron list
openclaw cron remove --name "gmail-ai-worker" # then recreate
โœ… SUCCESS CRITERIA

โœ”๏ธ Ubuntu headless + OpenClaw + Gmail API connected.
โœ”๏ธ Gemini generates contextual reply.
โœ”๏ธ Draft automatically created in Gmail (never auto-sent).
โœ”๏ธ Cron worker runs every minute, fully autonomous.
๐Ÿ”ด Red alert performance โ€“ fully modular & extensible.

Back