Email Writer
by @tobewin
Email writer and sender for OpenClaw. Use when user needs to draft, reply, or send emails via browser. Supports Gmail, Outlook, QQ Mail, 163 Mail. Requires O...
clawhub install email-composer๐ About This Skill
name: email-writer description: Email writer and sender for OpenClaw. Use when user needs to draft, reply, or send emails via browser. Supports Gmail, Outlook, QQ Mail, 163 Mail. Requires OpenClaw v2026.3.22+ with browser access. version: 1.0.4 license: MIT-0 metadata: {"openclaw": {"emoji": "๐ง", "requires": {"bins": [], "env": []}, "minVersion": "2026.3.22", "needsBrowser": true}}
Email Writer
Email composition and sending tool using OpenClaw browser automation.
Features
Trigger Conditions
Privacy Warning
This skill accesses your email account through browser session.
Step 1: Understand Email Request
Ask user for email details:
Step 2: Detect Email Provider
// Detect which email provider based on URL
function detectProvider(url) {
if (url.includes('mail.google.com') || url.includes('gmail.com')) return 'gmail';
if (url.includes('outlook.live.com') || url.includes('outlook.com')) return 'outlook';
if (url.includes('mail.qq.com')) return 'qq';
if (url.includes('mail.163.com')) return '163';
if (url.includes('mail.126.com')) return '126';
return 'unknown';
}
Step 3: Open Email Client
// Open email client based on user preference
await browser.open({ url: "https://mail.google.com" })
await browser.wait({ timeout: 5000 })
Supported platforms:
Step 4: Compose New Email
Gmail Compose
// Click compose button (Gmail)
await browser.click({ selector: '[gh="cm"]' })
await browser.wait({ timeout: 2000 })// Fill recipient
await browser.evaluate((email) => {
const toField = document.querySelector('[name="to"]');
if (toField) {
toField.focus();
toField.value = email;
toField.dispatchEvent(new Event('input', { bubbles: true }));
}
}, recipientEmail)
// Fill subject
await browser.evaluate((subject) => {
const subjectField = document.querySelector('[name="subjectbox"]');
if (subjectField) {
subjectField.focus();
subjectField.value = subject;
}
}, emailSubject)
// Fill body
await browser.evaluate((body) => {
const bodyField = document.querySelector('[role="textbox"][contenteditable="true"]');
if (bodyField) {
bodyField.focus();
bodyField.innerHTML = body.replace(/\n/g, '
');
}
}, emailBody)
// Send (Gmail)
await browser.click({ selector: '[gh="s"]' })
Outlook Compose
// Click new message button (Outlook)
await browser.click({ selector: '[aria-label="New message"], .ms-Button--primary' })
await browser.wait({ timeout: 2000 })// Fill recipient (Outlook)
await browser.evaluate((email) => {
const toField = document.querySelector('[aria-label="To"], input[placeholder*="To"]');
if (toField) {
toField.focus();
toField.value = email;
toField.dispatchEvent(new Event('input', { bubbles: true }));
}
}, recipientEmail)
// Fill subject (Outlook)
await browser.evaluate((subject) => {
const subjectField = document.querySelector('[aria-label="Subject"], input[placeholder*="Subject"]');
if (subjectField) {
subjectField.focus();
subjectField.value = subject;
}
}, emailSubject)
// Fill body (Outlook)
await browser.evaluate((body) => {
const bodyField = document.querySelector('[aria-label="Message body"], [role="textbox"]');
if (bodyField) {
bodyField.focus();
bodyField.innerHTML = body.replace(/\n/g, '
');
}
}, emailBody)
// Send (Outlook)
await browser.click({ selector: '[aria-label="Send"], button[title="Send"]' })
QQ Mail Compose
// Click compose button (QQ Mail)
await browser.click({ selector: '.compose-button, .btn-compose, [title="ๅไฟก"]' })
await browser.wait({ timeout: 2000 })// Fill recipient (QQ Mail)
await browser.evaluate((email) => {
const toField = document.querySelector('#to_input, input[name="to"]') ||
document.querySelector('[aria-label="ๆถไปถไบบ"]');
if (toField) {
toField.focus();
toField.value = email;
toField.dispatchEvent(new Event('input', { bubbles: true }));
}
}, recipientEmail)
// Fill subject (QQ Mail)
await browser.evaluate((subject) => {
const subjectField = document.querySelector('#subject, input[name="subject"]');
if (subjectField) {
subjectField.focus();
subjectField.value = subject;
}
}, emailSubject)
// Fill body (QQ Mail)
await browser.evaluate((body) => {
const bodyField = document.querySelector('#QMEditorArea iframe') ||
document.querySelector('.qmEditorArea');
if (bodyField) {
if (bodyField.tagName === 'IFRAME') {
bodyField.contentDocument.body.innerHTML = body.replace(/\n/g, '
');
} else {
bodyField.innerHTML = body.replace(/\n/g, '
');
}
}
}, emailBody)
// Send (QQ Mail)
await browser.click({ selector: '.btn-send, [title="ๅ้"], .qmBtn' })
163 Mail Compose
// Click compose button (163 Mail)
await browser.click({ selector: '.nui-mainToolbar-btn, .js-component-composebtn' })
await browser.wait({ timeout: 2000 })// Fill recipient (163 Mail)
await browser.evaluate((email) => {
const toField = document.querySelector('#draft_to_input, input[name="to"]') ||
document.querySelector('.nui-editableAddr-input');
if (toField) {
toField.focus();
toField.value = email;
toField.dispatchEvent(new Event('input', { bubbles: true }));
}
}, recipientEmail)
// Fill subject (163 Mail)
await browser.evaluate((subject) => {
const subjectField = document.querySelector('#draft_subject, input[name="subject"]');
if (subjectField) {
subjectField.focus();
subjectField.value = subject;
}
}, emailSubject)
// Fill body (163 Mail)
await browser.evaluate((body) => {
const bodyField = document.querySelector('.APP-editor-iframe iframe') ||
document.querySelector('.nuiEditor');
if (bodyField) {
if (bodyField.tagName === 'IFRAME') {
bodyField.contentDocument.body.innerHTML = body.replace(/\n/g, '
');
} else {
bodyField.innerHTML = body.replace(/\n/g, '
');
}
}
}, emailBody)
// Send (163 Mail)
await browser.click({ selector: '.nui-mainToolbar-sendBtn, .js-component-sendbtn' })
Step 5: Reply to Email
Gmail Reply
await browser.click({ selector: '.zA' })
await browser.click({ selector: '[aria-label="Reply"]' })
await browser.wait({ timeout: 2000 })
await browser.evaluate((body) => {
const bodyField = document.querySelector('[role="textbox"][contenteditable="true"]');
if (bodyField) bodyField.innerHTML = body.replace(/\n/g, '
');
}, replyBody)
await browser.click({ selector: '[gh="s"]' })
Outlook Reply
await browser.click({ selector: '[aria-label="Reply"]' })
await browser.wait({ timeout: 2000 })
await browser.evaluate((body) => {
const bodyField = document.querySelector('[aria-label="Message body"]');
if (bodyField) bodyField.innerHTML = body.replace(/\n/g, '
');
}, replyBody)
await browser.click({ selector: '[aria-label="Send"]' })
QQ Mail Reply
await browser.click({ selector: '.btn-reply, [title="ๅๅค"]' })
await browser.wait({ timeout: 2000 })
await browser.evaluate((body) => {
const iframe = document.querySelector('#QMEditorArea iframe');
if (iframe) iframe.contentDocument.body.innerHTML = body.replace(/\n/g, '
');
}, replyBody)
await browser.click({ selector: '.btn-send, [title="ๅ้"]' })
163 Mail Reply
await browser.click({ selector: '.js-component-replybtn, [title="ๅๅค"]' })
await browser.wait({ timeout: 2000 })
await browser.evaluate((body) => {
const iframe = document.querySelector('.APP-editor-iframe iframe');
if (iframe) iframe.contentDocument.body.innerHTML = body.replace(/\n/g, '
');
}, replyBody)
await browser.click({ selector: '.js-component-sendbtn' })
Step 6: Send Confirmation
// Wait for send
await browser.wait({ timeout: 3000 })// Check for success message
const sent = await browser.evaluate(() => {
const text = document.body.innerText;
return text.includes('Message sent') ||
text.includes('Sent') ||
text.includes('ๅทฒๅ้') ||
text.includes('ๅ้ๆๅ') ||
text.includes('้ฎไปถๅทฒๅ้');
})
if (sent) {
console.log("Email sent successfully!")
}
Email Templates
Thank You Email
Subject: Thank you for your support
Dear [Name],
Thank you for [specific reason].
[Details]
Best regards, [Your name]
Work Report
Subject: Work Report - [Date]
Hi Manager,
Weekly report:
1. Completed tasks 2. In progress 3. Next week plan
Best, [Your name]
Meeting Invitation
Subject: Meeting: [Topic]
Hi [Name],
Please join our meeting:
Time: [Time] Location: [Location/Link] Agenda: 1. Topic 1 2. Topic 2
Please confirm your attendance.
Thanks, [Your name]