Gmail CDP Delivery
Use this workflow when a user asks to send email by Gmail from the local machine, with or without an attachment.
Current limitation: this skill supports plain-text Gmail body content plus attachments. It does not reliably support sending raw HTML as inline Gmail body content.
Required Inputs
- Recipient email
- Optional file path or paths
- Optional body text
Environment Assumptions
- Chrome with remote debugging support is already installed and expected to be available
- Chrome debug launcher exists in your repo/workspace when restart help is needed:
scripts/restart_debug_chrome.sh
- Chrome DevTools endpoint is
http://127.0.0.1:9222
- Node and npm are available
- This skill's runtime dependency is installed once with the bundled installer into
skills/cdp-gmail-delivery/.runtime/pupp-mail
Preflight Checklist
- If attaching a file, confirm target file exists and is readable
- If attaching files for a personal Gmail account, keep total size at or under 25 MB
- Reject obviously blocked Gmail attachment classes before send:
- executable/script-heavy file types like
.exe, .dll, .js, .jar, .bat, .cmd, .msi, .iso, and similar blocked extensions
- blocked files inside archives, including compressed forms or nested archives
- password-protected archives
- documents with malicious macros
- Confirm recipient email is explicit
- Confirm CDP endpoint responds (
http://127.0.0.1:9222/json/version)
- Confirm user login state in visible debug Chrome session
If a requested attachment appears blocked or too large for Gmail, stop and ask the human operator for another delivery path. Do not keep retrying the same blocked upload.
If the user wants an HTML newsletter or raw HTML email body, treat inline HTML body delivery as unsupported for this skill under the current Gmail compose + CDP model. Use plain-text summary/body plus an .html attachment instead, or use a future Gmail API / MIME-based workflow.
For detectable cases, scripts/send_via_cdp.js should fail before opening Gmail and print a limitation result instead of pretending the upload might work.
Workflow
- Assume Chrome CDP is already available and try the send flow first.
- If the CDP endpoint is unavailable, run
scripts/restart_debug_chrome.sh from repo/workspace root.
- If CDP is still unavailable after restart, ask the human operator to help restore the visible debug Chrome session.
- If Gmail is not already authenticated in that visible Chrome window, ask the operator to sign in manually.
- Send mail over CDP with
scripts/send_via_cdp.js.
- Verify send in Sent folder by a unique subject.
Non-negotiable Validation
Before clicking Send, validate all of the following in the live compose draft:
- To field contains intended recipient
- Subject is non-empty and unique
- If attaching files, the compose draft shows all requested filenames before send
If any check fails, stop and repair draft fields before send.
Gmail Attachment Constraints
- Personal Gmail sending limit: 25 MB total attachment size
- Google Workspace accounts may use admin-defined limits instead
- Gmail blocks many risky attachment types, including executable and script-like formats such as:
.ade, .adp, .apk, .appx, .appxbundle, .bat, .cab, .chm, .cmd, .com, .cpl, .diagcab, .diagcfg, .diagpkg, .dll, .dmg, .ex, .ex_, .exe, .hta, .img, .ins, .iso, .isp, .jar, .jnlp, .js, .jse, .lib, .lnk, .mde, .mjs, .msc, .msi, .msix, .msixbundle, .msp, .mst, .nsh, .pif, .ps1, .scr, .sct, .shb, .sys, .vb, .vbe, .vbs, .vhd, .vxd, .wsc, .wsf, .wsh, .xll
- Gmail can also block:
- compressed forms of blocked files
- blocked files found inside archives like
.zip or .tgz
- password-protected archives
- documents with malicious macros
Use these constraints as preflight filters. If the file is likely to be blocked, do not claim it can be mailed successfully.
HTML Email Limitation
- Do not promise raw HTML body delivery through Gmail compose DOM automation
- Gmail compose currently behaves like a plain-text/body-editor automation target for this skill, not a reliable raw HTML injection target
- Treat HTML email as a limitation of this skill, not a temporary success path
- Current supported workaround:
- put a plain-text summary or intro in the email body
- attach the full
.html file
- Future upgrade path for true inline HTML email:
- Gmail API
- raw MIME message assembly
Install (one-time)
From the workspace root, run:
bash skills/cdp-gmail-delivery/scripts/install_runtime.sh
What it does:
- Creates
skills/cdp-gmail-delivery/.runtime/pupp-mail
- Initializes a minimal npm runtime there
- Installs pinned
puppeteer-core@24
This keeps the runtime local to the skill instead of using an ad hoc /tmp path.
Send Command
node skills/cdp-gmail-delivery/scripts/send_via_cdp.js \
--to "recipient@example.com" \
--body "Optional message"
With attachment:
node skills/cdp-gmail-delivery/scripts/send_via_cdp.js \
--to "recipient@example.com" \
--file "/absolute/path/to/file.txt" \
--body "Optional message"
With multiple attachments:
node skills/cdp-gmail-delivery/scripts/send_via_cdp.js \
--to "recipient@example.com" \
--file "/absolute/path/to/file-a.txt" \
--file "/absolute/path/to/file-b.txt" \
--body "Optional message"
Success Output
The script prints:
EMAIL_SENT_OK
SUBJECT=<unique-subject>
TO=<recipient>
FILE_NAME=<basename-only> for each attached file
Report success only after these outputs and Sent verification succeed. Do not expose absolute local filesystem paths in success messages.
When local preflight detects a Gmail attachment limitation, the script should print:
LIMITATION_GMAIL_ATTACHMENT
REASON=<limitation-type>
DETAILS=<detected-context> when available
ACTION=... telling the human operator this is a limitation of Gmail attachment sending for this skill
When to read extra references
- If send flow fails or behaves unexpectedly: read
references/troubleshooting.md
- If you need incident evidence/context: read
references/receipts.md
References
- Runtime model:
- This workflow uses direct Chrome CDP automation (Puppeteer), not agent-browser.
- Browser runtime/bootstrap foundation:
https://github.com/joustonhuang/chrome_for_openclaw
- Script references:
chrome_for_openclaw.sh, scripts/restart_debug_chrome.sh
- Historical script context:
scripts/xrdp_chrome_debug_setup.sh
- Git repo context:
https://github.com/joustonhuang/unifai
- Incident receipts:
- Troubleshooting:
references/troubleshooting.md
1---2name: cdp-gmail-delivery3description: Send Gmail messages from an operator-controlled Chrome debug session using Gmail CDP automation. Use when the user asks to send email from the local machine, with or without an attachment. Default assumption: Chrome CDP is already installed and available. If the CDP endpoint is unavailable, ask the human operator to help restart the debug Chrome session, then send, and verify in Sent by unique subject.4---56# Gmail CDP Delivery78Use this workflow when a user asks to send email by Gmail from the local machine, with or without an attachment.910Current limitation: this skill supports plain-text Gmail body content plus attachments. It does not reliably support sending raw HTML as inline Gmail body content.1112## Required Inputs1314- Recipient email15- Optional file path or paths16- Optional body text1718## Environment Assumptions1920- Chrome with remote debugging support is already installed and expected to be available21- Chrome debug launcher exists in your repo/workspace when restart help is needed:22 - `scripts/restart_debug_chrome.sh`23- Chrome DevTools endpoint is `http://127.0.0.1:9222`24- Node and npm are available25- This skill's runtime dependency is installed once with the bundled installer into `skills/cdp-gmail-delivery/.runtime/pupp-mail`2627## Preflight Checklist2829- If attaching a file, confirm target file exists and is readable30- If attaching files for a personal Gmail account, keep total size at or under 25 MB31- Reject obviously blocked Gmail attachment classes before send:32 - executable/script-heavy file types like `.exe`, `.dll`, `.js`, `.jar`, `.bat`, `.cmd`, `.msi`, `.iso`, and similar blocked extensions33 - blocked files inside archives, including compressed forms or nested archives34 - password-protected archives35 - documents with malicious macros36- Confirm recipient email is explicit37- Confirm CDP endpoint responds (`http://127.0.0.1:9222/json/version`)38- Confirm user login state in visible debug Chrome session3940If a requested attachment appears blocked or too large for Gmail, stop and ask the human operator for another delivery path. Do not keep retrying the same blocked upload.4142If the user wants an HTML newsletter or raw HTML email body, treat inline HTML body delivery as unsupported for this skill under the current Gmail compose + CDP model. Use plain-text summary/body plus an `.html` attachment instead, or use a future Gmail API / MIME-based workflow.4344For detectable cases, `scripts/send_via_cdp.js` should fail before opening Gmail and print a limitation result instead of pretending the upload might work.4546## Workflow47481. Assume Chrome CDP is already available and try the send flow first.492. If the CDP endpoint is unavailable, run `scripts/restart_debug_chrome.sh` from repo/workspace root.503. If CDP is still unavailable after restart, ask the human operator to help restore the visible debug Chrome session.514. If Gmail is not already authenticated in that visible Chrome window, ask the operator to sign in manually.525. Send mail over CDP with `scripts/send_via_cdp.js`.536. Verify send in Sent folder by a unique subject.5455## Non-negotiable Validation5657Before clicking Send, validate all of the following in the live compose draft:5859- To field contains intended recipient60- Subject is non-empty and unique61- If attaching files, the compose draft shows all requested filenames before send6263If any check fails, stop and repair draft fields before send.6465## Gmail Attachment Constraints6667- Personal Gmail sending limit: 25 MB total attachment size68- Google Workspace accounts may use admin-defined limits instead69- Gmail blocks many risky attachment types, including executable and script-like formats such as:70 - `.ade`, `.adp`, `.apk`, `.appx`, `.appxbundle`, `.bat`, `.cab`, `.chm`, `.cmd`, `.com`, `.cpl`, `.diagcab`, `.diagcfg`, `.diagpkg`, `.dll`, `.dmg`, `.ex`, `.ex_`, `.exe`, `.hta`, `.img`, `.ins`, `.iso`, `.isp`, `.jar`, `.jnlp`, `.js`, `.jse`, `.lib`, `.lnk`, `.mde`, `.mjs`, `.msc`, `.msi`, `.msix`, `.msixbundle`, `.msp`, `.mst`, `.nsh`, `.pif`, `.ps1`, `.scr`, `.sct`, `.shb`, `.sys`, `.vb`, `.vbe`, `.vbs`, `.vhd`, `.vxd`, `.wsc`, `.wsf`, `.wsh`, `.xll`71- Gmail can also block:72 - compressed forms of blocked files73 - blocked files found inside archives like `.zip` or `.tgz`74 - password-protected archives75 - documents with malicious macros7677Use these constraints as preflight filters. If the file is likely to be blocked, do not claim it can be mailed successfully.7879## HTML Email Limitation8081- Do not promise raw HTML body delivery through Gmail compose DOM automation82- Gmail compose currently behaves like a plain-text/body-editor automation target for this skill, not a reliable raw HTML injection target83- Treat HTML email as a limitation of this skill, not a temporary success path84- Current supported workaround:85 - put a plain-text summary or intro in the email body86 - attach the full `.html` file87- Future upgrade path for true inline HTML email:88 - Gmail API89 - raw MIME message assembly9091## Install (one-time)9293From the workspace root, run:9495```bash96bash skills/cdp-gmail-delivery/scripts/install_runtime.sh97```9899What it does:100- Creates `skills/cdp-gmail-delivery/.runtime/pupp-mail`101- Initializes a minimal npm runtime there102- Installs pinned `puppeteer-core@24`103104This keeps the runtime local to the skill instead of using an ad hoc `/tmp` path.105106## Send Command107108```bash109node skills/cdp-gmail-delivery/scripts/send_via_cdp.js \110 --to "recipient@example.com" \111 --body "Optional message"112```113114With attachment:115116```bash117node skills/cdp-gmail-delivery/scripts/send_via_cdp.js \118 --to "recipient@example.com" \119 --file "/absolute/path/to/file.txt" \120 --body "Optional message"121```122123With multiple attachments:124125```bash126node skills/cdp-gmail-delivery/scripts/send_via_cdp.js \127 --to "recipient@example.com" \128 --file "/absolute/path/to/file-a.txt" \129 --file "/absolute/path/to/file-b.txt" \130 --body "Optional message"131```132133## Success Output134135The script prints:136137- `EMAIL_SENT_OK`138- `SUBJECT=<unique-subject>`139- `TO=<recipient>`140- `FILE_NAME=<basename-only>` for each attached file141142Report success only after these outputs and Sent verification succeed. Do not expose absolute local filesystem paths in success messages.143144When local preflight detects a Gmail attachment limitation, the script should print:145146- `LIMITATION_GMAIL_ATTACHMENT`147- `REASON=<limitation-type>`148- `DETAILS=<detected-context>` when available149- `ACTION=...` telling the human operator this is a limitation of Gmail attachment sending for this skill150151## When to read extra references152153- If send flow fails or behaves unexpectedly: read `references/troubleshooting.md`154- If you need incident evidence/context: read `references/receipts.md`155156## References157158- Runtime model:159 - This workflow uses direct Chrome CDP automation (Puppeteer), not agent-browser.160- Browser runtime/bootstrap foundation:161 - `https://github.com/joustonhuang/chrome_for_openclaw`162 - Script references: `chrome_for_openclaw.sh`, `scripts/restart_debug_chrome.sh`163- Historical script context:164 - `scripts/xrdp_chrome_debug_setup.sh`165- Git repo context: `https://github.com/joustonhuang/unifai`166- Incident receipts:167 - `references/receipts.md`168- Troubleshooting:169 - `references/troubleshooting.md`