๐ŸŽ Get the FREE AI Skills Starter Guide โ€” Subscribe โ†’
BytesAgainBytesAgain
๐Ÿฆ€ ClawHub

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...

Versionv1.0.4
Downloads1,178
Starsโญ 1
TERMINAL
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

  • Draft professional emails with AI assistance
  • Reply to emails with context
  • Support Gmail, Outlook, QQ Mail, 163 Mail
  • Multi-language support (Chinese and English)
  • Trigger Conditions

  • "Help me write an email"
  • "Reply to this email"
  • "Send email to someone"
  • "Write a thank you email"
  • Privacy Warning

    This skill accesses your email account through browser session.

  • Reads and sends emails on your behalf
  • Uses your browser email login session
  • Only use on trusted email accounts
  • Step 1: Understand Email Request

    Ask user for email details:

  • Recipient email address
  • Subject line
  • Content/key points
  • Formal or informal tone
  • Language preference
  • 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:

  • Gmail: mail.google.com
  • Outlook: outlook.live.com
  • QQ Mail: mail.qq.com
  • 163 Mail: mail.163.com
  • 126 Mail: mail.126.com
  • 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]

    Error Handling

  • Email not logged in: Prompt user to log in
  • Send failed: Prompt user to send manually
  • Attachment failed: Suggest manual attachment
  • Unknown provider: Ask user which email service
  • Limitations

  • Cannot handle email verification codes
  • Cannot send encrypted emails
  • No batch sending support
  • QQ/163 may need iframe handling
  • Privacy and Security

  • No email content uploaded externally
  • All processing done locally
  • Browser email session accessed
  • Review before sending sensitive information
  • Notes

  • Requires OpenClaw v2026.3.22+
  • Gmail has most reliable selectors
  • QQ/163 use iframe for email body
  • Test with non-sensitive account first
  • ๐Ÿ“‹ Tips & Best Practices

  • Requires OpenClaw v2026.3.22+
  • Gmail has most reliable selectors
  • QQ/163 use iframe for email body
  • Test with non-sensitive account first