emailr-cli 1.12.0 → 1.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +140 -456
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {Command}from'commander';import {Emailr}from'emailr';import
|
|
2
|
+
import {Command}from'commander';import {Emailr}from'emailr';import T,{readFileSync}from'fs';import V from'os';import E from'path';import de from'cli-table3';import x from'chalk';import at from'http';import {URL}from'url';import vt from'crypto';import {spawn,execSync,exec}from'child_process';var We=[E.join(V.homedir(),".emailrrc"),E.join(V.homedir(),".config","emailr","config.json")];function d(){if(process.env.EMAILR_API_KEY)return {apiKey:process.env.EMAILR_API_KEY,baseUrl:process.env.EMAILR_BASE_URL,format:process.env.EMAILR_FORMAT||"table"};for(let r of We)if(T.existsSync(r))try{let t=T.readFileSync(r,"utf-8"),e=JSON.parse(t);if(e.apiKey)return {apiKey:e.apiKey,baseUrl:e.baseUrl,format:e.format||"table"}}catch{}throw new Error(`No API key configured.
|
|
3
3
|
|
|
4
4
|
Set the EMAILR_API_KEY environment variable:
|
|
5
5
|
export EMAILR_API_KEY=your-api-key
|
|
@@ -7,8 +7,8 @@ Set the EMAILR_API_KEY environment variable:
|
|
|
7
7
|
Or create a config file at ~/.emailrrc:
|
|
8
8
|
{ "apiKey": "your-api-key" }
|
|
9
9
|
|
|
10
|
-
Or run: emailr config set api-key <your-api-key>`)}function I(){let
|
|
11
|
-
`);}function ce(
|
|
10
|
+
Or run: emailr config set api-key <your-api-key>`)}function I(){let r=E.join(V.homedir(),".config","emailr");return E.join(r,"config.json")}function G(r){let t=I(),e=E.dirname(t);T.existsSync(e)||T.mkdirSync(e,{recursive:true});let i={};if(T.existsSync(t))try{i=JSON.parse(T.readFileSync(t,"utf-8"));}catch{}let n={...i,...r};T.writeFileSync(t,JSON.stringify(n,null,2)+`
|
|
11
|
+
`);}function ce(r){try{return d()[r]?.toString()}catch{return}}function m(r,t="table"){t==="json"?console.log(JSON.stringify(r,null,2)):Xe(r);}function Xe(r){Array.isArray(r)?Ve(r):typeof r=="object"&&r!==null?ze(r):console.log(r);}function Ve(r){if(r.length===0){console.log(x.gray("No results"));return}let t=r[0];if(typeof t!="object"||t===null){r.forEach(n=>console.log(n));return}let e=Object.keys(t),i=new de({head:e.map(n=>x.cyan(n)),style:{head:[],border:[]}});for(let n of r){let a=e.map(o=>{let s=n[o];return pe(s)});i.push(a);}console.log(i.toString());}function ze(r){let t=new de({style:{head:[],border:[]}});for(let[e,i]of Object.entries(r))t.push([x.cyan(e),pe(i)]);console.log(t.toString());}function pe(r){return r==null?x.gray("-"):typeof r=="boolean"?r?x.green("\u2713"):x.red("\u2717"):typeof r=="object"?JSON.stringify(r):String(r)}function p(r){console.log(x.green("\u2713"),r);}function l(r){console.error(x.red("\u2717"),r);}function C(r){console.warn(x.yellow("\u26A0"),r);}function u(r){console.log(x.blue("\u2139"),r);}function fe(){return new Command("send").description(`Send an email
|
|
12
12
|
|
|
13
13
|
USAGE
|
|
14
14
|
emailr send --to <email_address> [options]
|
|
@@ -156,7 +156,7 @@ EXAMPLES
|
|
|
156
156
|
SEE ALSO
|
|
157
157
|
emailr templates Manage email templates
|
|
158
158
|
emailr contacts Manage contacts
|
|
159
|
-
emailr broadcasts Send bulk emails to segments`).requiredOption("--to <email>","Recipient email address (comma-separated for multiple)").option("--from <email>","Sender email address").option("--subject <subject>","Email subject").option("--html <html>","HTML content (inline)").option("--text <text>","Plain text content (inline)").option("--html-file <path>","Read HTML content from file").option("--text-file <path>","Read plain text content from file").option("--template <id>","Template ID to use").option("--template-data <json>","Template data as JSON").option("--cc <emails>","CC recipients (comma-separated)").option("--bcc <emails>","BCC recipients (comma-separated)").option("--reply-to <email>","Reply-to email address").option("--schedule <datetime>","Schedule send time (ISO 8601)").option("--format <format>","Output format (json|table)","table").action(async
|
|
159
|
+
emailr broadcasts Send bulk emails to segments`).requiredOption("--to <email>","Recipient email address (comma-separated for multiple)").option("--from <email>","Sender email address").option("--subject <subject>","Email subject").option("--html <html>","HTML content (inline)").option("--text <text>","Plain text content (inline)").option("--html-file <path>","Read HTML content from file").option("--text-file <path>","Read plain text content from file").option("--template <id>","Template ID to use").option("--template-data <json>","Template data as JSON").option("--cc <emails>","CC recipients (comma-separated)").option("--bcc <emails>","BCC recipients (comma-separated)").option("--reply-to <email>","Reply-to email address").option("--schedule <datetime>","Schedule send time (ISO 8601)").option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=d(),i=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),n=t.to.split(",").map(s=>s.trim()),a={to:n.length===1?n[0]:n};if(t.from&&(a.from=t.from),t.subject&&(a.subject=t.subject),t.htmlFile)try{a.html=readFileSync(t.htmlFile,"utf-8");}catch{l(`Failed to read HTML file: ${t.htmlFile}`),process.exit(1);}else t.html&&(a.html=t.html);if(t.textFile)try{a.text=readFileSync(t.textFile,"utf-8");}catch{l(`Failed to read text file: ${t.textFile}`),process.exit(1);}else t.text&&(a.text=t.text);if(t.template&&(a.template_id=t.template),t.templateData)try{a.template_data=JSON.parse(t.templateData);}catch{l("Invalid JSON for --template-data"),process.exit(1);}if(t.cc){let s=t.cc.split(",").map(c=>c.trim());a.cc=s.length===1?s[0]:s;}if(t.bcc){let s=t.bcc.split(",").map(c=>c.trim());a.bcc=s.length===1?s[0]:s;}t.replyTo&&(a.reply_to_email=t.replyTo),t.schedule&&(a.scheduled_at=t.schedule);let o=await i.emails.send(a);t.format==="json"?m(o,"json"):(p("Email sent successfully!"),m({"Message ID":o.message_id,Recipients:o.recipients,Status:o.status,...o.scheduled_at&&{"Scheduled At":o.scheduled_at}},"table"));}catch(e){l(e instanceof Error?e.message:"Failed to send email"),process.exit(1);}})}function be(){let r=new Command("contacts").description(`Manage contacts
|
|
160
160
|
|
|
161
161
|
USAGE
|
|
162
162
|
emailr contacts <subcommand> [options]
|
|
@@ -238,7 +238,7 @@ EXAMPLES
|
|
|
238
238
|
|
|
239
239
|
SEE ALSO
|
|
240
240
|
emailr segments Manage contact segments
|
|
241
|
-
emailr broadcasts Send emails to contacts`);return
|
|
241
|
+
emailr broadcasts Send emails to contacts`);return r.command("list").description(`List all contacts
|
|
242
242
|
|
|
243
243
|
USAGE
|
|
244
244
|
emailr contacts list [options]
|
|
@@ -286,8 +286,8 @@ EXAMPLES
|
|
|
286
286
|
emailr contacts list --format json
|
|
287
287
|
|
|
288
288
|
# Combine filters with pagination
|
|
289
|
-
emailr contacts list --subscribed --limit 100 --offset 0`).option("--limit <number>","Number of contacts to return","20").option("--offset <number>","Offset for pagination","0").option("--subscribed","Only show subscribed contacts").option("--unsubscribed","Only show unsubscribed contacts").option("--search <query>","Search by email, first name, or last name").option("--tags <tags>","Filter by tags (comma-separated)").option("--format <format>","Output format (json|table)","table").action(async
|
|
290
|
-
Total: ${
|
|
289
|
+
emailr contacts list --subscribed --limit 100 --offset 0`).option("--limit <number>","Number of contacts to return","20").option("--offset <number>","Offset for pagination","0").option("--subscribed","Only show subscribed contacts").option("--unsubscribed","Only show unsubscribed contacts").option("--search <query>","Search by email, first name, or last name").option("--tags <tags>","Filter by tags (comma-separated)").option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=d(),i=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),n={limit:parseInt(t.limit,10),offset:parseInt(t.offset,10)};if(t.subscribed&&(n.subscribed=!0),t.unsubscribed&&(n.subscribed=!1),t.search&&(n.search=t.search),t.tags){let o=t.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean);o.length>0&&(n.tags=o.join(","));}let a=await i.contacts.list(n);if(t.format==="json")m(a,"json");else {let o=a.contacts.map(s=>({ID:s.id,Email:s.email,Name:[s.first_name,s.last_name].filter(Boolean).join(" ")||"-",Subscribed:s.subscribed,Tags:s.tags?.join(", ")||"-",Created:s.created_at}));m(o,"table"),console.log(`
|
|
290
|
+
Total: ${a.total}`);}}catch(e){l(e instanceof Error?e.message:"Failed to list contacts"),process.exit(1);}}),r.command("get <contact_id>").description(`Get a contact by ID
|
|
291
291
|
|
|
292
292
|
USAGE
|
|
293
293
|
emailr contacts get <contact_id> [options]
|
|
@@ -314,7 +314,7 @@ EXAMPLES
|
|
|
314
314
|
emailr contacts get con_abc123 --format json
|
|
315
315
|
|
|
316
316
|
# Pipe JSON to jq for processing
|
|
317
|
-
emailr contacts get con_abc123 --format json | jq '.metadata'`).option("--format <format>","Output format (json|table)","table").action(async(
|
|
317
|
+
emailr contacts get con_abc123 --format json | jq '.metadata'`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let i=d(),a=await new Emailr({apiKey:i.apiKey,baseUrl:i.baseUrl}).contacts.get(t);m(a,e.format);}catch(i){l(i instanceof Error?i.message:"Failed to get contact"),process.exit(1);}}),r.command("create").description(`Create a new contact
|
|
318
318
|
|
|
319
319
|
USAGE
|
|
320
320
|
emailr contacts create --email <email_address> [options]
|
|
@@ -357,7 +357,7 @@ EXAMPLES
|
|
|
357
357
|
emailr contacts create --email "user@example.com" --subscribed false
|
|
358
358
|
|
|
359
359
|
# Get JSON output for scripting
|
|
360
|
-
emailr contacts create --email "user@example.com" --format json`).requiredOption("--email <email>","Contact email address").option("--first-name <name>","First name").option("--last-name <name>","Last name").option("--subscribed","Mark as subscribed (default: true)").option("--metadata <json>","Metadata as JSON").option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format (json|table)","table").action(async
|
|
360
|
+
emailr contacts create --email "user@example.com" --format json`).requiredOption("--email <email>","Contact email address").option("--first-name <name>","First name").option("--last-name <name>","Last name").option("--subscribed","Mark as subscribed (default: true)").option("--metadata <json>","Metadata as JSON").option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=d(),i=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),n={email:t.email};if(t.firstName&&(n.first_name=t.firstName),t.lastName&&(n.last_name=t.lastName),t.subscribed!==void 0&&(n.subscribed=t.subscribed),t.metadata)try{n.metadata=JSON.parse(t.metadata);}catch{l("Invalid JSON for --metadata"),process.exit(1);}t.tags&&(n.tags=t.tags.split(",").map(o=>o.trim().toLowerCase()).filter(Boolean));let a=await i.contacts.create(n);t.format==="json"?m(a,"json"):(p(`Contact created: ${a.id}`),m(a,"table"));}catch(e){l(e instanceof Error?e.message:"Failed to create contact"),process.exit(1);}}),r.command("update <contact_id>").description(`Update a contact
|
|
361
361
|
|
|
362
362
|
USAGE
|
|
363
363
|
emailr contacts update <contact_id> [options]
|
|
@@ -406,7 +406,7 @@ EXAMPLES
|
|
|
406
406
|
emailr contacts update con_abc123 --metadata '{"plan": "enterprise", "upgraded": true}'
|
|
407
407
|
|
|
408
408
|
# Get JSON output
|
|
409
|
-
emailr contacts update con_abc123 --first-name "Jane" --format json`).option("--email <email>","New email address").option("--first-name <name>","First name").option("--last-name <name>","Last name").option("--subscribed","Mark as subscribed").option("--unsubscribed","Mark as unsubscribed").option("--metadata <json>","Metadata as JSON").option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format (json|table)","table").action(async(
|
|
409
|
+
emailr contacts update con_abc123 --first-name "Jane" --format json`).option("--email <email>","New email address").option("--first-name <name>","First name").option("--last-name <name>","Last name").option("--subscribed","Mark as subscribed").option("--unsubscribed","Mark as unsubscribed").option("--metadata <json>","Metadata as JSON").option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let i=d(),n=new Emailr({apiKey:i.apiKey,baseUrl:i.baseUrl}),a={};if(e.email&&(a.email=e.email),e.firstName&&(a.first_name=e.firstName),e.lastName&&(a.last_name=e.lastName),e.subscribed&&(a.subscribed=!0),e.unsubscribed&&(a.subscribed=!1),e.metadata)try{a.metadata=JSON.parse(e.metadata);}catch{l("Invalid JSON for --metadata"),process.exit(1);}e.tags&&(a.tags=e.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean));let o=await n.contacts.update(t,a);e.format==="json"?m(o,"json"):(p(`Contact updated: ${o.id}`),m(o,"table"));}catch(i){l(i instanceof Error?i.message:"Failed to update contact"),process.exit(1);}}),r.command("delete <contact_id>").description(`Delete a contact
|
|
410
410
|
|
|
411
411
|
USAGE
|
|
412
412
|
emailr contacts delete <contact_id>
|
|
@@ -423,7 +423,7 @@ EXAMPLES
|
|
|
423
423
|
emailr contacts delete con_abc123
|
|
424
424
|
|
|
425
425
|
WARNING
|
|
426
|
-
This action is permanent and cannot be undone.`).action(async
|
|
426
|
+
This action is permanent and cannot be undone.`).action(async t=>{try{let e=d();await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).contacts.delete(t),p(`Contact deleted: ${t}`);}catch(e){l(e instanceof Error?e.message:"Failed to delete contact"),process.exit(1);}}),r}function ge(){return E.join(V.homedir(),".config","emailr","templates")}function tt(){let r=ge();T.existsSync(r)||T.mkdirSync(r,{recursive:true});}function z(r){return E.join(ge(),`${r}.html`)}function Y(r,t){tt();let e=z(r);T.writeFileSync(e,t,"utf-8");}function ye(r){let t=z(r);return T.existsSync(t)?T.readFileSync(t,"utf-8"):null}function we(r){let t=z(r);return T.existsSync(t)}var v=null,P=null,H=false;function ve(r){return r.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function it(r){return r===null||r.trim()===""}function ot(r){return `<!DOCTYPE html>
|
|
427
427
|
<html lang="en">
|
|
428
428
|
<head>
|
|
429
429
|
<meta charset="UTF-8">
|
|
@@ -489,14 +489,14 @@ WARNING
|
|
|
489
489
|
<div class="icon">\u{1F4ED}</div>
|
|
490
490
|
<h1>No Content Available</h1>
|
|
491
491
|
<p>This template exists but has no HTML content to display.</p>
|
|
492
|
-
<div class="template-id">${ve(
|
|
492
|
+
<div class="template-id">${ve(r)}</div>
|
|
493
493
|
<div class="hint">
|
|
494
494
|
<p><strong>To add content:</strong></p>
|
|
495
495
|
<p>Update the template using the CLI with the <code>--html</code> option or provide HTML content when creating the template.</p>
|
|
496
496
|
</div>
|
|
497
497
|
</div>
|
|
498
498
|
</body>
|
|
499
|
-
</html>`}function Se(
|
|
499
|
+
</html>`}function Se(r){return `<!DOCTYPE html>
|
|
500
500
|
<html lang="en">
|
|
501
501
|
<head>
|
|
502
502
|
<meta charset="UTF-8">
|
|
@@ -548,11 +548,11 @@ WARNING
|
|
|
548
548
|
<div class="icon">404</div>
|
|
549
549
|
<h1>Template Not Found</h1>
|
|
550
550
|
<p>The requested template could not be found in local storage.</p>
|
|
551
|
-
<div class="template-id">${ve(
|
|
551
|
+
<div class="template-id">${ve(r)}</div>
|
|
552
552
|
<p style="margin-top: 1rem;">Try creating or retrieving the template first using the CLI.</p>
|
|
553
553
|
</div>
|
|
554
554
|
</body>
|
|
555
|
-
</html>`}function rt(
|
|
555
|
+
</html>`}function rt(r){let t=r.match(/^\/preview\/([^/]+)$/);return t?t[1]:null}function nt(){return (r,t)=>{if(r.method!=="GET"){t.writeHead(405,{"Content-Type":"text/plain"}),t.end("Method Not Allowed");return}let e=r.url||"/",i=rt(e);if(!i){t.writeHead(404,{"Content-Type":"text/plain"}),t.end("Not Found");return}if(!we(i)){t.writeHead(404,{"Content-Type":"text/html; charset=utf-8"}),t.end(Se(i));return}let n=ye(i);if(n===null){t.writeHead(404,{"Content-Type":"text/html; charset=utf-8"}),t.end(Se(i));return}if(it(n)){t.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),t.end(ot(i));return}t.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),t.end(n);}}var xe={async start(){return H&&P!==null?P:new Promise((r,t)=>{v=at.createServer(nt()),v.listen(0,"127.0.0.1",()=>{let e=v.address();e&&typeof e=="object"?(P=e.port,H=true,v.unref(),r(P)):t(new Error("Failed to get server address"));}),v.on("error",e=>{H=false,P=null,v=null,t(new Error(`Failed to start preview server: ${e.message}`));});})},getPort(){return P},isRunning(){return H},async stop(){if(v)return new Promise(r=>{v.close(()=>{v=null,P=null,H=false,r();});})}};function Te(){return xe}async function Z(r){try{return `http://127.0.0.1:${await xe.start()}/preview/${r}`}catch{return null}}function Oe(){v&&v.ref();}var A=null,Q=null,W=null,k=[],_e=`
|
|
556
556
|
<script>
|
|
557
557
|
(function() {
|
|
558
558
|
const evtSource = new EventSource('/__live-reload');
|
|
@@ -566,11 +566,11 @@ WARNING
|
|
|
566
566
|
};
|
|
567
567
|
})();
|
|
568
568
|
</script>
|
|
569
|
-
`;function mt(
|
|
569
|
+
`;function mt(r){return r.includes("</body>")?r.replace("</body>",`${_e}</body>`):r+_e}function ct(){k.forEach(r=>{try{r.write(`data: reload
|
|
570
570
|
|
|
571
|
-
`);}catch{}});}async function ee(
|
|
571
|
+
`);}catch{}});}async function ee(r,t){let e=E.resolve(r);return new Promise((i,n)=>{A=at.createServer((a,o)=>{if(a.url==="/__live-reload"){o.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive","Access-Control-Allow-Origin":"*"}),o.write(`data: connected
|
|
572
572
|
|
|
573
|
-
`),
|
|
573
|
+
`),k.push(o),a.on("close",()=>{k=k.filter(s=>s!==o);});return}if(a.method==="GET"){try{let s=T.readFileSync(e,"utf-8"),c=mt(s);o.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),o.end(c);}catch(s){o.writeHead(500,{"Content-Type":"text/plain"}),o.end(`Error reading file: ${s instanceof Error?s.message:String(s)}`);}return}o.writeHead(405,{"Content-Type":"text/plain"}),o.end("Method Not Allowed");}),A.listen(0,"127.0.0.1",()=>{let a=A.address();if(a&&typeof a=="object"){Q=a.port;let o=null;W=T.watch(e,s=>{s==="change"&&(o&&clearTimeout(o),o=setTimeout(()=>{ct(),t?.();},100));}),i(Q);}else n(new Error("Failed to get server address"));}),A.on("error",a=>{n(new Error(`Failed to start server: ${a.message}`));});})}async function te(){if(W&&(W.close(),W=null),k.forEach(r=>{try{r.end();}catch{}}),k=[],A)return new Promise(r=>{A.close(()=>{A=null,Q=null,r();});})}async function je(r){try{let t=r.html_content??"";Y(r.id,t);}catch(t){return C(`Could not save template for preview: ${t instanceof Error?t.message:String(t)}`),null}try{let t=await Z(r.id);return t===null?(C("Could not start preview server"),null):t}catch(t){return C(`Could not generate preview URL: ${t instanceof Error?t.message:String(t)}`),null}}function Ie(){let r=new Command("templates").description(`Manage email templates
|
|
574
574
|
|
|
575
575
|
USAGE
|
|
576
576
|
emailr templates <subcommand> [options]
|
|
@@ -641,7 +641,7 @@ AGENTIC WORKFLOW
|
|
|
641
641
|
|
|
642
642
|
SEE ALSO
|
|
643
643
|
emailr send Send emails using templates
|
|
644
|
-
emailr broadcasts Send bulk emails to segments`);return
|
|
644
|
+
emailr broadcasts Send bulk emails to segments`);return r.command("list").description(`List all templates
|
|
645
645
|
|
|
646
646
|
USAGE
|
|
647
647
|
emailr templates list [options]
|
|
@@ -671,8 +671,8 @@ EXAMPLES
|
|
|
671
671
|
emailr templates list --page 2 --limit 10
|
|
672
672
|
|
|
673
673
|
# Get JSON output for scripting
|
|
674
|
-
emailr templates list --format json`).option("--limit <count>","Number of templates to return","20").option("--page <page_number>","Page number for pagination","1").option("--tags <tags>","Filter by tags (comma-separated)").option("--format <format>","Output format: json | table","table").action(async
|
|
675
|
-
Total: ${
|
|
674
|
+
emailr templates list --format json`).option("--limit <count>","Number of templates to return","20").option("--page <page_number>","Page number for pagination","1").option("--tags <tags>","Filter by tags (comma-separated)").option("--format <format>","Output format: json | table","table").action(async t=>{try{let e=d(),i=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),n={limit:parseInt(t.limit,10),page:parseInt(t.page,10)};if(t.tags){let o=t.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean);o.length>0&&(n.tags=o.join(","));}let a=await i.templates.list(n);if(t.format==="json")m(a,"json");else {let o=a.map(s=>({ID:s.id,Name:s.name,Subject:s.subject,Variables:s.variables?.join(", ")||"-",Tags:s.tags?.join(", ")||"-",Created:s.created_at}));m(o,"table"),console.log(`
|
|
675
|
+
Total: ${a.length}`);}}catch(e){l(e instanceof Error?e.message:"Failed to list templates"),process.exit(1);}}),r.command("get <template_id>").description(`Get a template by ID
|
|
676
676
|
|
|
677
677
|
USAGE
|
|
678
678
|
emailr templates get <template_id> [options]
|
|
@@ -700,7 +700,7 @@ EXAMPLES
|
|
|
700
700
|
emailr templates get tpl_abc123 --format json
|
|
701
701
|
|
|
702
702
|
# Pipe JSON to jq for processing
|
|
703
|
-
emailr templates get tpl_abc123 --format json | jq '.html_content'`).option("--format <format>","Output format: json | table","table").action(async(
|
|
703
|
+
emailr templates get tpl_abc123 --format json | jq '.html_content'`).option("--format <format>","Output format: json | table","table").action(async(t,e)=>{try{let i=d(),a=await new Emailr({apiKey:i.apiKey,baseUrl:i.baseUrl}).templates.get(t),o=await je({id:a.id,html_content:a.html_content??void 0}),s=a.preview_html?`${i.baseUrl}/preview/${a.id}`:null;if(e.format==="json")m({...a,preview_url:s??o},"json");else {let c={ID:a.id,Name:a.name,Subject:a.subject,Variables:a.variables?.join(", ")||"-",Created:a.created_at};s?c["Preview URL"]=s:o&&(c["Local Preview"]=o),m(c,"table");}}catch(i){l(i instanceof Error?i.message:"Failed to get template"),process.exit(1);}}),r.command("fetch <template_id>").description(`Download template HTML to file or stdout
|
|
704
704
|
|
|
705
705
|
USAGE
|
|
706
706
|
emailr templates fetch <template_id> [options]
|
|
@@ -734,8 +734,8 @@ AGENTIC WORKFLOW
|
|
|
734
734
|
This is step 1 of the agentic workflow:
|
|
735
735
|
1. Fetch: emailr templates fetch <id> --output template.html
|
|
736
736
|
2. Edit locally or with AI assistance
|
|
737
|
-
3. Push preview: emailr templates push-preview <id> --html-file template.html`).option("--output <file_path>","Write HTML to file (default: stdout)").option("--preview","Fetch preview HTML instead of published HTML").action(async(
|
|
738
|
-
Run 'emailr templates push-preview <id> --html-file <path>' to create a preview.`)):l("Template has no HTML content"),process.exit(1)),e.output){let
|
|
737
|
+
3. Push preview: emailr templates push-preview <id> --html-file template.html`).option("--output <file_path>","Write HTML to file (default: stdout)").option("--preview","Fetch preview HTML instead of published HTML").action(async(t,e)=>{try{let i=d(),a=await new Emailr({apiKey:i.apiKey,baseUrl:i.baseUrl}).templates.fetch(t,{preview:e.preview??!1});if(a||(e.preview?(l("No preview HTML exists for this template"),console.log(`
|
|
738
|
+
Run 'emailr templates push-preview <id> --html-file <path>' to create a preview.`)):l("Template has no HTML content"),process.exit(1)),e.output){let o=E.resolve(e.output);T.writeFileSync(o,a,"utf-8"),p(`HTML saved to: ${o}`);}else console.log(a);}catch(i){l(i instanceof Error?i.message:"Failed to fetch template"),process.exit(1);}}),r.command("push-preview <template_id>").description(`Upload HTML to template's preview for sharing with AI agents
|
|
739
739
|
|
|
740
740
|
USAGE
|
|
741
741
|
emailr templates push-preview <template_id> --html-file <file_path>
|
|
@@ -778,9 +778,9 @@ AGENTIC WORKFLOW
|
|
|
778
778
|
2. Edit locally or with AI assistance
|
|
779
779
|
3. Push preview: emailr templates push-preview <id> --html-file template.html
|
|
780
780
|
4. Share the preview URL with your AI agent for feedback
|
|
781
|
-
5. Repeat steps 2-4 until satisfied`).option("--html-file <file_path>","Read HTML content from file").option("--html <html_content>","Inline HTML content").option("--format <format>","Output format: json | table","table").action(async(
|
|
782
|
-
Usage:`),console.log(" emailr templates push-preview <id> --html-file <path>"),console.log(" emailr templates push-preview <id> --html <content>"),process.exit(1)),e.htmlFile&&e.html&&(l("Cannot use both --html-file and --html. Choose one."),process.exit(1));let
|
|
783
|
-
Share this URL with your AI agent for feedback.`));}catch(
|
|
781
|
+
5. Repeat steps 2-4 until satisfied`).option("--html-file <file_path>","Read HTML content from file").option("--html <html_content>","Inline HTML content").option("--format <format>","Output format: json | table","table").action(async(t,e)=>{try{!e.htmlFile&&!e.html&&(l("Either --html-file or --html is required"),console.log(`
|
|
782
|
+
Usage:`),console.log(" emailr templates push-preview <id> --html-file <path>"),console.log(" emailr templates push-preview <id> --html <content>"),process.exit(1)),e.htmlFile&&e.html&&(l("Cannot use both --html-file and --html. Choose one."),process.exit(1));let i=d(),n=new Emailr({apiKey:i.apiKey,baseUrl:i.baseUrl}),a;if(e.htmlFile){let c=E.resolve(e.htmlFile);try{a=T.readFileSync(c,"utf-8");}catch{l(`Failed to read file: ${c}`),process.exit(1);}}else a=e.html;let o=await n.templates.pushPreview(t,a),s="updated";e.format==="json"?m({template_id:t,preview_url:o.preview_url,status:s},"json"):(p("Preview uploaded successfully"),m({"Template ID":t,"Preview URL":o.preview_url,Status:s},"table"),console.log(`
|
|
783
|
+
Share this URL with your AI agent for feedback.`));}catch(i){l(i instanceof Error?i.message:"Failed to push preview"),process.exit(1);}}),r.command("create").description(`Create a new email template
|
|
784
784
|
|
|
785
785
|
USAGE
|
|
786
786
|
emailr templates create --name <template_name> --subject <subject_line> [options]
|
|
@@ -828,8 +828,8 @@ EXAMPLES
|
|
|
828
828
|
|
|
829
829
|
TIP
|
|
830
830
|
For live preview while building, use "emailr templates draft" first.
|
|
831
|
-
It creates a local file with hot-reload preview, then use this command to save.`).requiredOption("--name <template_name>","Template name").requiredOption("--subject <subject_line>","Email subject line").option("--html <html_content>","Inline HTML content").option("--text <text_content>","Plain text content").option("--html-file <file_path>","Read HTML content from file").option("--text-file <file_path>","Read text content from file").option("--from <email_address>","Default from email address").option("--from-name <name>","Sender display name").option("--reply-to <email_address>","Default reply-to email address").option("--preview-text <text>","Preview text shown in email clients").option("--inbox-id <inbox_id>","Inbox ID for sender identity defaults").option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format: json | table","table").action(async
|
|
832
|
-
Open the Preview URL in your browser to view the rendered template.`);}}catch(e){l(e instanceof Error?e.message:"Failed to create template"),process.exit(1);}}),
|
|
831
|
+
It creates a local file with hot-reload preview, then use this command to save.`).requiredOption("--name <template_name>","Template name").requiredOption("--subject <subject_line>","Email subject line").option("--html <html_content>","Inline HTML content").option("--text <text_content>","Plain text content").option("--html-file <file_path>","Read HTML content from file").option("--text-file <file_path>","Read text content from file").option("--from <email_address>","Default from email address").option("--from-name <name>","Sender display name").option("--reply-to <email_address>","Default reply-to email address").option("--preview-text <text>","Preview text shown in email clients").option("--inbox-id <inbox_id>","Inbox ID for sender identity defaults").option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format: json | table","table").action(async t=>{try{let e=d(),i=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),n={name:t.name,subject:t.subject};if(t.htmlFile){let s=await import('fs');n.html_content=s.readFileSync(t.htmlFile,"utf-8");}else t.html&&(n.html_content=t.html);if(t.textFile){let s=await import('fs');n.text_content=s.readFileSync(t.textFile,"utf-8");}else t.text&&(n.text_content=t.text);t.from&&(n.from_email=t.from),t.fromName&&(n.from_name=t.fromName),t.replyTo&&(n.reply_to=t.replyTo),t.previewText&&(n.preview_text=t.previewText),t.inboxId&&(n.inbox_id=t.inboxId),t.tags&&(n.tags=t.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean));let a=await i.templates.create(n),o=await je({id:a.id,html_content:a.html_content??void 0});if(t.format==="json")m({...a,preview_url:o},"json");else {p(`Template created: ${a.id}`);let s={ID:a.id,Name:a.name,Subject:a.subject,Variables:a.variables?.join(", ")||"-",Tags:a.tags?.join(", ")||"-"};o&&(s["Preview URL"]=o),m(s,"table"),o&&console.log(`
|
|
832
|
+
Open the Preview URL in your browser to view the rendered template.`);}}catch(e){l(e instanceof Error?e.message:"Failed to create template"),process.exit(1);}}),r.command("update <template_id>").description(`Update an existing email template
|
|
833
833
|
|
|
834
834
|
USAGE
|
|
835
835
|
emailr templates update <template_id> [options]
|
|
@@ -884,7 +884,7 @@ AGENTIC WORKFLOW
|
|
|
884
884
|
2. Edit locally or with AI assistance
|
|
885
885
|
3. Push preview: emailr templates push-preview <id> --html-file template.html
|
|
886
886
|
4. Share URL with AI agent, iterate on feedback
|
|
887
|
-
5. Publish: emailr templates update <id> --html-file template.html`).option("--name <template_name>","New template name").option("--subject <subject_line>","New email subject line").option("--html <html_content>","New inline HTML content").option("--text <text_content>","New plain text content").option("--html-file <file_path>","Read new HTML content from file").option("--text-file <file_path>","Read new text content from file").option("--from <email_address>","New default from email address").option("--from-name <name>","New sender display name").option("--reply-to <email_address>","New default reply-to email address").option("--preview-text <text>","New preview text").option("--inbox-id <inbox_id>",'Inbox ID for sender identity (use "none" to clear)').option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format: json | table","table").action(async(
|
|
887
|
+
5. Publish: emailr templates update <id> --html-file template.html`).option("--name <template_name>","New template name").option("--subject <subject_line>","New email subject line").option("--html <html_content>","New inline HTML content").option("--text <text_content>","New plain text content").option("--html-file <file_path>","Read new HTML content from file").option("--text-file <file_path>","Read new text content from file").option("--from <email_address>","New default from email address").option("--from-name <name>","New sender display name").option("--reply-to <email_address>","New default reply-to email address").option("--preview-text <text>","New preview text").option("--inbox-id <inbox_id>",'Inbox ID for sender identity (use "none" to clear)').option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format: json | table","table").action(async(t,e)=>{try{let i=d(),n=new Emailr({apiKey:i.apiKey,baseUrl:i.baseUrl}),a={};if(e.name&&(a.name=e.name),e.subject&&(a.subject=e.subject),e.htmlFile){let s=await import('fs');a.html_content=s.readFileSync(e.htmlFile,"utf-8");}else e.html&&(a.html_content=e.html);if(e.textFile){let s=await import('fs');a.text_content=s.readFileSync(e.textFile,"utf-8");}else e.text&&(a.text_content=e.text);e.from&&(a.from_email=e.from),e.fromName&&(a.from_name=e.fromName),e.replyTo&&(a.reply_to=e.replyTo),e.previewText&&(a.preview_text=e.previewText),e.inboxId&&(a.inbox_id=e.inboxId==="none"?null:e.inboxId),e.tags&&(a.tags=e.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean));let o=await n.templates.update(t,a);if(e.format==="json")m(o,"json");else {p(`Template updated: ${o.id}`);let s={ID:o.id,Name:o.name,Subject:o.subject,Variables:o.variables?.join(", ")||"-",Tags:o.tags?.join(", ")||"-",Updated:o.updated_at};m(s,"table");}}catch(i){l(i instanceof Error?i.message:"Failed to update template"),process.exit(1);}}),r.command("delete <template_id>").description(`Delete a template
|
|
888
888
|
|
|
889
889
|
USAGE
|
|
890
890
|
emailr templates delete <template_id>
|
|
@@ -901,7 +901,7 @@ EXAMPLES
|
|
|
901
901
|
emailr templates delete tpl_abc123
|
|
902
902
|
|
|
903
903
|
WARNING
|
|
904
|
-
This action is permanent and cannot be undone.`).action(async
|
|
904
|
+
This action is permanent and cannot be undone.`).action(async t=>{try{let e=d();await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).templates.delete(t),p(`Template deleted: ${t}`);}catch(e){l(e instanceof Error?e.message:"Failed to delete template"),process.exit(1);}}),r.command("preview <template_id>").description(`Preview a template in the browser
|
|
905
905
|
|
|
906
906
|
USAGE
|
|
907
907
|
emailr templates preview <template_id> [options]
|
|
@@ -930,12 +930,12 @@ EXAMPLES
|
|
|
930
930
|
|
|
931
931
|
SEE ALSO
|
|
932
932
|
emailr templates edit Live editing with hot-reload
|
|
933
|
-
emailr templates stop-preview Stop background preview server`).option("--no-open","Do not automatically open browser").option("--foreground","Keep process running in foreground (blocks terminal)").action(async(
|
|
934
|
-
Template: ${
|
|
933
|
+
emailr templates stop-preview Stop background preview server`).option("--no-open","Do not automatically open browser").option("--foreground","Keep process running in foreground (blocks terminal)").action(async(t,e)=>{try{let i=d(),n=new Emailr({apiKey:i.apiKey,baseUrl:i.baseUrl});console.log(`Fetching template ${t}...`);let a=await n.templates.get(t),o=a.html_content??"";if(Y(a.id,o),e.foreground){let y=await Z(a.id);if(y||(l("Failed to start preview server"),process.exit(1)),Oe(),console.log(`
|
|
934
|
+
Template: ${a.name}`),console.log(`Preview URL: ${y}`),e.open!==!1)try{await(await import('open')).default(y),console.log(`
|
|
935
935
|
Browser opened.`);}catch{console.log(`
|
|
936
936
|
Could not open browser automatically. Open the URL above manually.`);}process.on("SIGINT",async()=>{console.log(`
|
|
937
937
|
|
|
938
|
-
Stopping preview server...`),await
|
|
938
|
+
Stopping preview server...`),await Te().stop(),console.log("Done."),process.exit(0);});return}let s=E.join(process.cwd(),`.template-preview-${a.id}.html`);T.writeFileSync(s,o,"utf-8");let{spawn:c}=await import('child_process'),b=await import('os'),g=E.join(b.tmpdir(),"emailr-preview.pid");try{let y=T.readFileSync(g,"utf-8").trim();process.kill(parseInt(y,10),"SIGTERM");}catch{}let f=`
|
|
939
939
|
const http = require('http');
|
|
940
940
|
const fs = require('fs');
|
|
941
941
|
const path = require('path');
|
|
@@ -960,9 +960,9 @@ Stopping preview server...`),await xe().stop(),console.log("Done."),process.exit
|
|
|
960
960
|
console.log('PORT:' + port);
|
|
961
961
|
});
|
|
962
962
|
process.on('SIGTERM', () => { try { fs.unlinkSync(pidFile); fs.unlinkSync(portFile); fs.unlinkSync(filePath); } catch {} process.exit(0); });
|
|
963
|
-
`,h=c("node",["-e",f],{detached:!0,stdio:["ignore","pipe","ignore"]}),S="";await new Promise(
|
|
964
|
-
Template: ${
|
|
965
|
-
To stop: emailr templates stop-preview`),e.open!==!1)try{await(await import('open')).default(_);}catch{}process.exit(0);}catch(
|
|
963
|
+
`,h=c("node",["-e",f],{detached:!0,stdio:["ignore","pipe","ignore"]}),S="";await new Promise(y=>{h.stdout?.on("data",j=>{let B=j.toString().match(/PORT:(\d+)/);B&&(S=B[1],y());}),setTimeout(y,3e3);}),h.unref();let _=`http://127.0.0.1:${S}/`;if(console.log(`
|
|
964
|
+
Template: ${a.name}`),console.log(`Preview URL: ${_}`),console.log(`
|
|
965
|
+
To stop: emailr templates stop-preview`),e.open!==!1)try{await(await import('open')).default(_);}catch{}process.exit(0);}catch(i){l(i instanceof Error?i.message:"Failed to preview template"),process.exit(1);}}),r.command("edit <template_id>").description(`Start a live editing session for a template with hot-reload
|
|
966
966
|
|
|
967
967
|
USAGE
|
|
968
968
|
emailr templates edit <template_id> [options]
|
|
@@ -1002,17 +1002,17 @@ EXAMPLES
|
|
|
1002
1002
|
SEE ALSO
|
|
1003
1003
|
emailr templates draft Draft a new template with live preview
|
|
1004
1004
|
emailr templates update Save changes to the template
|
|
1005
|
-
emailr templates stop-preview Stop the background preview server`).option("--file <file_path>","Path to save the HTML file for editing","./template.html").option("--no-open","Do not automatically open browser").option("--foreground","Keep process running in foreground (blocks terminal)").action(async(
|
|
1006
|
-
Template: ${
|
|
1007
|
-
Watching for changes... Edit the file and see live updates.`),console.log(`When done, run: emailr templates update ${
|
|
1005
|
+
emailr templates stop-preview Stop the background preview server`).option("--file <file_path>","Path to save the HTML file for editing","./template.html").option("--no-open","Do not automatically open browser").option("--foreground","Keep process running in foreground (blocks terminal)").action(async(t,e)=>{try{let i=d(),n=new Emailr({apiKey:i.apiKey,baseUrl:i.baseUrl}),a=E.resolve(e.file);console.log(`Fetching template ${t}...`);let o=await n.templates.get(t),s=o.html_content??"";if(T.writeFileSync(a,s,"utf-8"),console.log(`Template saved to: ${a}`),e.foreground){let j=`http://127.0.0.1:${await ee(a,()=>{console.log("File changed - browser refreshed");})}/`;if(console.log(`
|
|
1006
|
+
Template: ${o.name}`),console.log(`Template ID: ${o.id}`),console.log(`Live Preview: ${j}`),console.log(`File: ${a}`),console.log(`
|
|
1007
|
+
Watching for changes... Edit the file and see live updates.`),console.log(`When done, run: emailr templates update ${t} --html-file ${e.file}`),e.open!==!1)try{await(await import('open')).default(j);}catch{}process.on("SIGINT",async()=>{console.log(`
|
|
1008
1008
|
|
|
1009
1009
|
Stopping live preview server...`),await te(),console.log("Done."),console.log(`
|
|
1010
|
-
To save changes: emailr templates update ${
|
|
1010
|
+
To save changes: emailr templates update ${t} --html-file ${e.file}`),process.exit(0);});return}let{spawn:c}=await import('child_process'),b=await import('os'),g=E.join(b.tmpdir(),"emailr-preview.pid");try{let y=T.readFileSync(g,"utf-8").trim();process.kill(parseInt(y,10),"SIGTERM");}catch{}let f=`
|
|
1011
1011
|
const http = require('http');
|
|
1012
1012
|
const fs = require('fs');
|
|
1013
1013
|
const path = require('path');
|
|
1014
1014
|
const os = require('os');
|
|
1015
|
-
const filePath = ${JSON.stringify(
|
|
1015
|
+
const filePath = ${JSON.stringify(a)};
|
|
1016
1016
|
const pidFile = path.join(os.tmpdir(), 'emailr-preview.pid');
|
|
1017
1017
|
const portFile = path.join(os.tmpdir(), 'emailr-preview.port');
|
|
1018
1018
|
let clients = [];
|
|
@@ -1047,10 +1047,10 @@ To save changes: emailr templates update ${a} --html-file ${e.file}`),process.ex
|
|
|
1047
1047
|
});
|
|
1048
1048
|
});
|
|
1049
1049
|
process.on('SIGTERM', () => { try { fs.unlinkSync(pidFile); fs.unlinkSync(portFile); } catch {} process.exit(0); });
|
|
1050
|
-
`,h=c("node",["-e",f],{detached:!0,stdio:["ignore","pipe","ignore"]}),S="";await new Promise(
|
|
1051
|
-
Template: ${
|
|
1050
|
+
`,h=c("node",["-e",f],{detached:!0,stdio:["ignore","pipe","ignore"]}),S="";await new Promise(y=>{h.stdout?.on("data",j=>{let me=j.toString().match(/PORT:(\d+)/);me&&(S=me[1],y());}),setTimeout(y,3e3);}),h.unref();let _=`http://127.0.0.1:${S}/`;if(console.log(`
|
|
1051
|
+
Template: ${o.name}`),console.log(`Template ID: ${o.id}`),console.log(`Live Preview: ${_}`),console.log(`File: ${a}`),console.log(`
|
|
1052
1052
|
Edit the file and see live updates in the browser.`),console.log(`
|
|
1053
|
-
When done:`),console.log(` emailr templates update ${
|
|
1053
|
+
When done:`),console.log(` emailr templates update ${t} --html-file ${e.file}`),console.log(" emailr templates stop-preview"),e.open!==!1)try{await(await import('open')).default(_);}catch{}process.exit(0);}catch(i){l(i instanceof Error?i.message:"Failed to edit template"),process.exit(1);}}),r.command("draft").description(`Start a live drafting session for a new template with hot-reload
|
|
1054
1054
|
|
|
1055
1055
|
USAGE
|
|
1056
1056
|
emailr templates draft [options]
|
|
@@ -1092,7 +1092,7 @@ EXAMPLES
|
|
|
1092
1092
|
SEE ALSO
|
|
1093
1093
|
emailr templates edit Edit an existing template with live preview
|
|
1094
1094
|
emailr templates create Create the template from your draft
|
|
1095
|
-
emailr templates stop-preview Stop the background preview server`).option("--file <file_path>","Path to save the HTML file for drafting","./new-template.html").option("--no-open","Do not automatically open browser").option("--blank","Start with a blank file instead of starter template").option("--foreground","Keep process running in foreground (blocks terminal)").action(async
|
|
1095
|
+
emailr templates stop-preview Stop the background preview server`).option("--file <file_path>","Path to save the HTML file for drafting","./new-template.html").option("--no-open","Do not automatically open browser").option("--blank","Start with a blank file instead of starter template").option("--foreground","Keep process running in foreground (blocks terminal)").action(async t=>{try{let e=E.resolve(t.file),i;if(t.blank?i="":i=`<!DOCTYPE html>
|
|
1096
1096
|
<html>
|
|
1097
1097
|
<head>
|
|
1098
1098
|
<meta charset="UTF-8">
|
|
@@ -1127,13 +1127,13 @@ SEE ALSO
|
|
|
1127
1127
|
<p><a href="{{unsubscribe_link}}">Unsubscribe</a></p>
|
|
1128
1128
|
</div>
|
|
1129
1129
|
</body>
|
|
1130
|
-
</html>`,
|
|
1130
|
+
</html>`,T.writeFileSync(e,i,"utf-8"),console.log(`Template draft created: ${e}`),t.foreground){let h=`http://127.0.0.1:${await ee(e,()=>{console.log("File changed - browser refreshed");})}/`;if(console.log(`
|
|
1131
1131
|
Live Preview: ${h}`),console.log(`File: ${e}`),console.log(`
|
|
1132
1132
|
Watching for changes... Edit the file and see live updates.`),console.log(`
|
|
1133
|
-
When done, create the template:`),console.log(` emailr templates create --name "Template Name" --subject "Email Subject" --html-file ${
|
|
1133
|
+
When done, create the template:`),console.log(` emailr templates create --name "Template Name" --subject "Email Subject" --html-file ${t.file}`),t.open!==!1)try{await(await import('open')).default(h);}catch{}process.on("SIGINT",async()=>{console.log(`
|
|
1134
1134
|
|
|
1135
1135
|
Stopping live preview server...`),await te(),console.log("Done."),console.log(`
|
|
1136
|
-
To create template: emailr templates create --name "Template Name" --subject "Email Subject" --html-file ${
|
|
1136
|
+
To create template: emailr templates create --name "Template Name" --subject "Email Subject" --html-file ${t.file}`),process.exit(0);});return}let{spawn:n}=await import('child_process'),a=await import('os'),o=E.join(a.tmpdir(),"emailr-preview.pid");try{let f=T.readFileSync(o,"utf-8").trim();process.kill(parseInt(f,10),"SIGTERM");}catch{}let s=`
|
|
1137
1137
|
const http = require('http');
|
|
1138
1138
|
const fs = require('fs');
|
|
1139
1139
|
const path = require('path');
|
|
@@ -1176,7 +1176,7 @@ To create template: emailr templates create --name "Template Name" --subject "Em
|
|
|
1176
1176
|
`,c=n("node",["-e",s],{detached:!0,stdio:["ignore","pipe","ignore"]}),b="";await new Promise(f=>{c.stdout?.on("data",h=>{let S=h.toString().match(/PORT:(\d+)/);S&&(b=S[1],f());}),setTimeout(f,3e3);}),c.unref();let g=`http://127.0.0.1:${b}/`;if(console.log(`
|
|
1177
1177
|
Live Preview: ${g}`),console.log(`File: ${e}`),console.log(`
|
|
1178
1178
|
Edit the file and see live updates in the browser.`),console.log(`
|
|
1179
|
-
When done:`),console.log(` emailr templates create --name "Template Name" --subject "Email Subject" --html-file ${
|
|
1179
|
+
When done:`),console.log(` emailr templates create --name "Template Name" --subject "Email Subject" --html-file ${t.file}`),console.log(" emailr templates stop-preview"),t.open!==!1)try{await(await import('open')).default(g);}catch{}process.exit(0);}catch(e){l(e instanceof Error?e.message:"Failed to start draft session"),process.exit(1);}}),r.command("stop-preview").description(`Stop any running background preview server
|
|
1180
1180
|
|
|
1181
1181
|
USAGE
|
|
1182
1182
|
emailr templates stop-preview
|
|
@@ -1193,7 +1193,7 @@ EXAMPLES
|
|
|
1193
1193
|
SEE ALSO
|
|
1194
1194
|
emailr templates edit Start live editing session
|
|
1195
1195
|
emailr templates draft Start live drafting session
|
|
1196
|
-
emailr templates preview Preview a template in browser`).action(async()=>{let
|
|
1196
|
+
emailr templates preview Preview a template in browser`).action(async()=>{let t=await import('os'),e=E.join(t.tmpdir(),"emailr-preview.pid");try{let i=T.readFileSync(e,"utf-8").trim();process.kill(parseInt(i,10),"SIGTERM"),T.unlinkSync(e),p("Preview server stopped");}catch{p("No preview server running");}}),r}function Ce(){let r=new Command("domains").description(`Manage sending domains
|
|
1197
1197
|
|
|
1198
1198
|
USAGE
|
|
1199
1199
|
emailr domains <subcommand> [options]
|
|
@@ -1274,7 +1274,7 @@ VERIFICATION STATUS
|
|
|
1274
1274
|
|
|
1275
1275
|
SEE ALSO
|
|
1276
1276
|
emailr send Send emails using verified domains
|
|
1277
|
-
emailr webhooks Receive domain verification events`);return
|
|
1277
|
+
emailr webhooks Receive domain verification events`);return r.command("list").description(`List all domains
|
|
1278
1278
|
|
|
1279
1279
|
USAGE
|
|
1280
1280
|
emailr domains list [options]
|
|
@@ -1301,7 +1301,7 @@ EXAMPLES
|
|
|
1301
1301
|
emailr domains list --format json | jq '.[] | select(.status == "verified")'
|
|
1302
1302
|
|
|
1303
1303
|
# Count domains
|
|
1304
|
-
emailr domains list --format json | jq 'length'`).option("--format <format>","Output format (json|table)","table").action(async
|
|
1304
|
+
emailr domains list --format json | jq 'length'`).option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=d(),n=await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).domains.list();if(t.format==="json")m(n,"json");else {let a=n.map(o=>({ID:o.id,Domain:o.domain,Status:o.status,DKIM:o.dkim_verified,SPF:o.spf_verified,DMARC:o.dmarc_verified,Created:o.created_at}));m(a,"table");}}catch(e){l(e instanceof Error?e.message:"Failed to list domains"),process.exit(1);}}),r.command("get <domain_id>").description(`Get domain details
|
|
1305
1305
|
|
|
1306
1306
|
USAGE
|
|
1307
1307
|
emailr domains get <domain_id> [options]
|
|
@@ -1328,7 +1328,7 @@ EXAMPLES
|
|
|
1328
1328
|
emailr domains get dom_abc123 --format json
|
|
1329
1329
|
|
|
1330
1330
|
# Extract DNS records
|
|
1331
|
-
emailr domains get dom_abc123 --format json | jq '.dns_records'`).option("--format <format>","Output format (json|table)","table").action(async(
|
|
1331
|
+
emailr domains get dom_abc123 --format json | jq '.dns_records'`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let i=d(),a=await new Emailr({apiKey:i.apiKey,baseUrl:i.baseUrl}).domains.get(t);m(a,e.format);}catch(i){l(i instanceof Error?i.message:"Failed to get domain"),process.exit(1);}}),r.command("add <domain_name>").description(`Add a new domain
|
|
1332
1332
|
|
|
1333
1333
|
USAGE
|
|
1334
1334
|
emailr domains add <domain_name> [options]
|
|
@@ -1381,7 +1381,7 @@ NEXT STEPS
|
|
|
1381
1381
|
1. Copy the DNS records shown in the output
|
|
1382
1382
|
2. Add them to your DNS provider (Cloudflare, Route53, etc.)
|
|
1383
1383
|
3. Wait for DNS propagation (up to 48 hours)
|
|
1384
|
-
4. Run: emailr domains verify <domain_id>`).option("--receiving-subdomain <subdomain>","Subdomain for receiving emails").option("--format <format>","Output format (json|table)","table").action(async(
|
|
1384
|
+
4. Run: emailr domains verify <domain_id>`).option("--receiving-subdomain <subdomain>","Subdomain for receiving emails").option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let i=d(),n=new Emailr({apiKey:i.apiKey,baseUrl:i.baseUrl}),a={domain:t};e.receivingSubdomain&&(a.receivingSubdomain=e.receivingSubdomain);let o=await n.domains.add(a);if(e.format==="json")m(o,"json");else {if(p(`Domain added: ${o.domain}`),u("Add the following DNS records to verify your domain:"),console.log(""),o.dns_records){let s=[{Type:"DKIM",...ae(o.dns_records.dkim)},{Type:"SPF",...ae(o.dns_records.spf)},{Type:"DMARC",...ae(o.dns_records.dmarc)}];m(s,"table");}console.log(""),u(`Run 'emailr domains verify ${o.id}' after adding DNS records`);}}catch(i){l(i instanceof Error?i.message:"Failed to add domain"),process.exit(1);}}),r.command("verify <domain_id>").description(`Verify a domain
|
|
1385
1385
|
|
|
1386
1386
|
USAGE
|
|
1387
1387
|
emailr domains verify <domain_id> [options]
|
|
@@ -1419,7 +1419,7 @@ TROUBLESHOOTING
|
|
|
1419
1419
|
1. Run 'check-dns' to see which records are missing
|
|
1420
1420
|
2. Verify records are correctly configured with your DNS provider
|
|
1421
1421
|
3. Wait for DNS propagation (can take up to 48 hours)
|
|
1422
|
-
4. Try verification again`).option("--format <format>","Output format (json|table)","table").action(async(
|
|
1422
|
+
4. Try verification again`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let i=d(),a=await new Emailr({apiKey:i.apiKey,baseUrl:i.baseUrl}).domains.verify(t);e.format==="json"?m(a,"json"):a.verified?p("Domain verified successfully!"):(u(`Domain status: ${a.status}`),a.dkim_status&&u(`DKIM status: ${a.dkim_status}`));}catch(i){l(i instanceof Error?i.message:"Failed to verify domain"),process.exit(1);}}),r.command("check-dns <domain_id>").description(`Check DNS records for a domain
|
|
1423
1423
|
|
|
1424
1424
|
USAGE
|
|
1425
1425
|
emailr domains check-dns <domain_id> [options]
|
|
@@ -1466,7 +1466,7 @@ COMMON ISSUES
|
|
|
1466
1466
|
|
|
1467
1467
|
Multiple records found:
|
|
1468
1468
|
- Remove duplicate TXT records
|
|
1469
|
-
- Keep only the Emailr-specific record`).option("--format <format>","Output format (json|table)","table").action(async(
|
|
1469
|
+
- Keep only the Emailr-specific record`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let i=d(),a=await new Emailr({apiKey:i.apiKey,baseUrl:i.baseUrl}).domains.checkDns(t);if(e.format==="json")m(a,"json");else {let o=Object.entries(a).map(([s,c])=>({Record:s,Verified:c.verified,Expected:c.expected||"-",Found:c.found?.join(", ")||"-"}));m(o,"table");}}catch(i){l(i instanceof Error?i.message:"Failed to check DNS"),process.exit(1);}}),r.command("delete <domain_id>").description(`Delete a domain
|
|
1470
1470
|
|
|
1471
1471
|
USAGE
|
|
1472
1472
|
emailr domains delete <domain_id> [options]
|
|
@@ -1496,7 +1496,7 @@ WARNING
|
|
|
1496
1496
|
This action is permanent and cannot be undone.
|
|
1497
1497
|
- Emails from this domain will fail to send
|
|
1498
1498
|
- DNS records can be removed from your DNS provider
|
|
1499
|
-
- Re-add the domain if you need to restore functionality`).option("--format <format>","Output format (json|table)","table").action(async
|
|
1499
|
+
- Re-add the domain if you need to restore functionality`).option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=d();await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).domains.delete(t),p(`Domain deleted: ${t}`);}catch(e){l(e instanceof Error?e.message:"Failed to delete domain"),process.exit(1);}}),r}function ae(r){return {"Record Type":r.type,Name:r.name,Value:r.value.length>50?r.value.substring(0,47)+"...":r.value,...r.priority!==void 0&&{Priority:r.priority}}}function Ne(){let r=new Command("config").description(`Manage CLI configuration
|
|
1500
1500
|
|
|
1501
1501
|
USAGE
|
|
1502
1502
|
emailr config <subcommand> [options]
|
|
@@ -1559,7 +1559,7 @@ EXAMPLES
|
|
|
1559
1559
|
emailr templates list
|
|
1560
1560
|
|
|
1561
1561
|
SEE ALSO
|
|
1562
|
-
emailr --help Show all available commands`);return
|
|
1562
|
+
emailr --help Show all available commands`);return r.command("set <key> <value>").description(`Set a configuration value
|
|
1563
1563
|
|
|
1564
1564
|
USAGE
|
|
1565
1565
|
emailr config set <key> <value>
|
|
@@ -1589,7 +1589,7 @@ EXAMPLES
|
|
|
1589
1589
|
|
|
1590
1590
|
NOTE
|
|
1591
1591
|
Environment variables (EMAILR_API_KEY, EMAILR_BASE_URL) take precedence
|
|
1592
|
-
over config file values at runtime.`).action(async(
|
|
1592
|
+
over config file values at runtime.`).action(async(t,e)=>{try{let i=["api-key","base-url","format"],n=t.toLowerCase();i.includes(n)||(l(`Invalid config key: ${t}`),u(`Valid keys: ${i.join(", ")}`),process.exit(1));let o={"api-key":"apiKey","base-url":"baseUrl",format:"format"}[n];n==="format"&&!["json","table"].includes(e)&&(l(`Invalid format value: ${e}`),u("Valid formats: json, table"),process.exit(1)),G({[o]:e}),p(`Configuration saved: ${t} = ${n==="api-key"?"***":e}`),u(`Config file: ${I()}`);}catch(i){l(i instanceof Error?i.message:"Failed to save configuration"),process.exit(1);}}),r.command("get <key>").description(`Get a configuration value
|
|
1593
1593
|
|
|
1594
1594
|
USAGE
|
|
1595
1595
|
emailr config get <key>
|
|
@@ -1617,7 +1617,7 @@ EXAMPLES
|
|
|
1617
1617
|
emailr config get format
|
|
1618
1618
|
|
|
1619
1619
|
SEE ALSO
|
|
1620
|
-
emailr config list Show all configuration values`).action(async
|
|
1620
|
+
emailr config list Show all configuration values`).action(async t=>{try{let e=["api-key","base-url","format"],i=t.toLowerCase();e.includes(i)||(l(`Invalid config key: ${t}`),u(`Valid keys: ${e.join(", ")}`),process.exit(1));let a={"api-key":"apiKey","base-url":"baseUrl",format:"format"}[i],o=ce(a);o?console.log(i==="api-key"?o.substring(0,8)+"..."+o.substring(o.length-4):o):u(`${t} is not set`);}catch(e){l(e instanceof Error?e.message:"Failed to get configuration"),process.exit(1);}}),r.command("list").description(`List all configuration values
|
|
1621
1621
|
|
|
1622
1622
|
USAGE
|
|
1623
1623
|
emailr config list [options]
|
|
@@ -1645,7 +1645,7 @@ EXAMPLES
|
|
|
1645
1645
|
|
|
1646
1646
|
SEE ALSO
|
|
1647
1647
|
emailr config get Get a single configuration value
|
|
1648
|
-
emailr config path Show config file location`).option("--format <format>","Output format (json|table)","table").action(async
|
|
1648
|
+
emailr config path Show config file location`).option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=d(),i={"api-key":e.apiKey?e.apiKey.substring(0,8)+"..."+e.apiKey.substring(e.apiKey.length-4):"(not set)","base-url":e.baseUrl||"(default)",format:e.format||"table"};if(t.format==="json")m(i,"json");else {let n=Object.entries(i).map(([a,o])=>({Key:a,Value:o}));m(n,"table");}console.log(""),u(`Config file: ${I()}`);}catch(e){e instanceof Error&&e.message.includes("No API key configured")?(u("No configuration found."),u("Run 'emailr config set api-key <your-api-key>' to get started.")):(l(e instanceof Error?e.message:"Failed to list configuration"),process.exit(1));}}),r.command("path").description(`Show the configuration file path
|
|
1649
1649
|
|
|
1650
1650
|
USAGE
|
|
1651
1651
|
emailr config path
|
|
@@ -1672,7 +1672,7 @@ EXAMPLES
|
|
|
1672
1672
|
open $(emailr config path)
|
|
1673
1673
|
|
|
1674
1674
|
# View config file contents
|
|
1675
|
-
cat $(emailr config path)`).action(()=>{console.log(I());}),
|
|
1675
|
+
cat $(emailr config path)`).action(()=>{console.log(I());}),r.command("init").description(`Initialize configuration interactively
|
|
1676
1676
|
|
|
1677
1677
|
USAGE
|
|
1678
1678
|
emailr config init [options]
|
|
@@ -1705,7 +1705,7 @@ ALTERNATIVE: ENVIRONMENT VARIABLES
|
|
|
1705
1705
|
|
|
1706
1706
|
SEE ALSO
|
|
1707
1707
|
emailr config set Set individual configuration values
|
|
1708
|
-
emailr config list View current configuration`).option("--api-key <key>","API key to use").option("--base-url <url>","Base URL for API").action(async
|
|
1708
|
+
emailr config list View current configuration`).option("--api-key <key>","API key to use").option("--base-url <url>","Base URL for API").action(async t=>{try{t.apiKey?(G({apiKey:t.apiKey,baseUrl:t.baseUrl}),p("Configuration initialized!"),u(`Config file: ${I()}`)):(u("Initialize your Emailr CLI configuration:"),console.log(""),u("Run with --api-key flag:"),console.log(" emailr config init --api-key <your-api-key>"),console.log(""),u("Or set environment variable:"),console.log(" export EMAILR_API_KEY=<your-api-key>"));}catch(e){l(e instanceof Error?e.message:"Failed to initialize configuration"),process.exit(1);}}),r}function Ue(){let r=new Command("broadcasts").description(`Manage broadcast campaigns
|
|
1709
1709
|
|
|
1710
1710
|
USAGE
|
|
1711
1711
|
emailr broadcasts <subcommand> [options]
|
|
@@ -1810,7 +1810,7 @@ EXAMPLES
|
|
|
1810
1810
|
SEE ALSO
|
|
1811
1811
|
emailr templates Manage email templates
|
|
1812
1812
|
emailr segments Manage contact segments
|
|
1813
|
-
emailr contacts Manage individual contacts`);return
|
|
1813
|
+
emailr contacts Manage individual contacts`);return r.command("list").description(`List all broadcasts
|
|
1814
1814
|
|
|
1815
1815
|
USAGE
|
|
1816
1816
|
emailr broadcasts list [options]
|
|
@@ -1855,7 +1855,7 @@ EXAMPLES
|
|
|
1855
1855
|
emailr broadcasts list --format json
|
|
1856
1856
|
|
|
1857
1857
|
# Pipe JSON to jq for processing
|
|
1858
|
-
emailr broadcasts list --format json | jq '.[] | select(.status == "scheduled")'`).option("--status <status>","Filter by status (draft, scheduled, sending, sent)").option("--limit <number>","Number of broadcasts to return","20").option("--tags <tags>","Filter by tags (comma-separated)").option("--format <format>","Output format (json|table)","table").action(async
|
|
1858
|
+
emailr broadcasts list --format json | jq '.[] | select(.status == "scheduled")'`).option("--status <status>","Filter by status (draft, scheduled, sending, sent)").option("--limit <number>","Number of broadcasts to return","20").option("--tags <tags>","Filter by tags (comma-separated)").option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=d(),i=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),n={status:t.status,limit:parseInt(t.limit)};if(t.tags){let o=t.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean);o.length>0&&(n.tags=o.join(","));}let a=await i.broadcasts.list(n);if(t.format==="json")m(a,"json");else {if(a.length===0){console.log("No broadcasts found.");return}let o=a.map(s=>({ID:s.id,Name:s.name,Subject:s.subject.substring(0,30)+(s.subject.length>30?"...":""),Status:s.status,Tags:s.tags?.join(", ")||"-",Recipients:s.total_recipients||0,Sent:s.sent_count||0,Created:new Date(s.created_at).toLocaleDateString()}));m(o,"table");}}catch(e){l(e instanceof Error?e.message:"Failed to list broadcasts"),process.exit(1);}}),r.command("get <broadcast_id>").description(`Get broadcast details
|
|
1859
1859
|
|
|
1860
1860
|
USAGE
|
|
1861
1861
|
emailr broadcasts get <broadcast_id> [options]
|
|
@@ -1890,7 +1890,7 @@ EXAMPLES
|
|
|
1890
1890
|
emailr broadcasts get brd_abc123 --format json
|
|
1891
1891
|
|
|
1892
1892
|
# Pipe JSON to jq for processing
|
|
1893
|
-
emailr broadcasts get brd_abc123 --format json | jq '{sent: .sent_count, opened: .opened_count}'`).option("--format <format>","Output format (json|table)","table").action(async(
|
|
1893
|
+
emailr broadcasts get brd_abc123 --format json | jq '{sent: .sent_count, opened: .opened_count}'`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let i=d(),a=await new Emailr({apiKey:i.apiKey,baseUrl:i.baseUrl}).broadcasts.get(t);e.format==="json"?m(a,"json"):m({ID:a.id,Name:a.name,Subject:a.subject,"From Email":a.from_email,"From Name":a.from_name||"-",Status:a.status,Tags:a.tags?.join(", ")||"-","Total Recipients":a.total_recipients||0,"Sent Count":a.sent_count||0,Delivered:a.delivered_count||0,Opened:a.opened_count||0,Clicked:a.clicked_count||0,Bounced:a.bounced_count||0,"Scheduled At":a.scheduled_at||"N/A","Started At":a.started_at||"N/A","Completed At":a.completed_at||"N/A","Created At":a.created_at},"table");}catch(i){l(i instanceof Error?i.message:"Failed to get broadcast"),process.exit(1);}}),r.command("create").description(`Create a new broadcast
|
|
1894
1894
|
|
|
1895
1895
|
USAGE
|
|
1896
1896
|
emailr broadcasts create --name <name> --subject <subject> --from <email> [options]
|
|
@@ -1971,7 +1971,7 @@ EXAMPLES
|
|
|
1971
1971
|
|
|
1972
1972
|
SEE ALSO
|
|
1973
1973
|
emailr templates Create and manage email templates
|
|
1974
|
-
emailr segments Create and manage contact segments`).requiredOption("--name <name>","Broadcast name").requiredOption("--subject <subject>","Email subject").requiredOption("--from <email>","Sender email address").option("--from-name <name>","Sender display name").option("--reply-to <email>","Reply-To email address").option("--preview-text <text>","Preview text (preheader)").option("--inbox-id <inbox_id>","Inbox ID for sender identity defaults").option("--inbox-ids <ids>","Comma-separated inbox IDs for inbox rotation").option("--sending-speed <speed>","Sending speed: auto | slow | normal | instant (default: auto)").option("--template <id>","Template ID to use").option("--segment <id>","Segment ID to target").option("--html <html>","HTML content").option("--text <text>","Plain text content").option("--schedule <datetime>","Schedule time (ISO 8601)").option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format (json|table)","table").action(async
|
|
1974
|
+
emailr segments Create and manage contact segments`).requiredOption("--name <name>","Broadcast name").requiredOption("--subject <subject>","Email subject").requiredOption("--from <email>","Sender email address").option("--from-name <name>","Sender display name").option("--reply-to <email>","Reply-To email address").option("--preview-text <text>","Preview text (preheader)").option("--inbox-id <inbox_id>","Inbox ID for sender identity defaults").option("--inbox-ids <ids>","Comma-separated inbox IDs for inbox rotation").option("--sending-speed <speed>","Sending speed: auto | slow | normal | instant (default: auto)").option("--template <id>","Template ID to use").option("--segment <id>","Segment ID to target").option("--html <html>","HTML content").option("--text <text>","Plain text content").option("--schedule <datetime>","Schedule time (ISO 8601)").option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=d(),i=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),n={name:t.name,subject:t.subject,from_email:t.from,from_name:t.fromName,reply_to:t.replyTo,preview_text:t.previewText,inbox_id:t.inboxId,template_id:t.template,segment_id:t.segment,html_content:t.html,text_content:t.text,scheduled_at:t.schedule};t.inboxIds&&(n.inbox_ids=t.inboxIds.split(",").map(o=>o.trim()).filter(Boolean)),t.sendingSpeed&&(n.sending_speed=t.sendingSpeed),t.tags&&(n.tags=t.tags.split(",").map(o=>o.trim().toLowerCase()).filter(Boolean));let a=await i.broadcasts.create(n);t.format==="json"?m(a,"json"):(p("Broadcast created successfully!"),m({ID:a.id,Name:a.name,Status:a.status,Tags:a.tags?.join(", ")||"-","Scheduled At":a.scheduled_at||"Not scheduled"},"table"));}catch(e){l(e instanceof Error?e.message:"Failed to create broadcast"),process.exit(1);}}),r.command("send <broadcast_id>").description(`Send a broadcast immediately
|
|
1975
1975
|
|
|
1976
1976
|
USAGE
|
|
1977
1977
|
emailr broadcasts send <broadcast_id> [options]
|
|
@@ -2004,7 +2004,7 @@ EXAMPLES
|
|
|
2004
2004
|
NOTE
|
|
2005
2005
|
Sending is asynchronous. The command returns when sending starts,
|
|
2006
2006
|
not when all emails are delivered. Use 'emailr broadcasts get' to
|
|
2007
|
-
check delivery progress.`).option("--format <format>","Output format (json|table)","table").action(async(
|
|
2007
|
+
check delivery progress.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let i=d(),a=await new Emailr({apiKey:i.apiKey,baseUrl:i.baseUrl}).broadcasts.send(t);e.format==="json"?m(a,"json"):(p("Broadcast sent successfully!"),m({Success:a.success,Sent:a.sent,Total:a.total},"table"));}catch(i){l(i instanceof Error?i.message:"Failed to send broadcast"),process.exit(1);}}),r.command("schedule <broadcast_id>").description(`Schedule a broadcast for future delivery
|
|
2008
2008
|
|
|
2009
2009
|
USAGE
|
|
2010
2010
|
emailr broadcasts schedule <broadcast_id> --at <datetime> [options]
|
|
@@ -2054,7 +2054,7 @@ EXAMPLES
|
|
|
2054
2054
|
emailr broadcasts schedule brd_abc123 --at "2024-12-25T10:00:00Z" --format json
|
|
2055
2055
|
|
|
2056
2056
|
SEE ALSO
|
|
2057
|
-
emailr broadcasts cancel Cancel a scheduled broadcast`).requiredOption("--at <datetime>","Schedule time (ISO 8601)").option("--format <format>","Output format (json|table)","table").action(async(
|
|
2057
|
+
emailr broadcasts cancel Cancel a scheduled broadcast`).requiredOption("--at <datetime>","Schedule time (ISO 8601)").option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let i=d(),a=await new Emailr({apiKey:i.apiKey,baseUrl:i.baseUrl}).broadcasts.schedule(t,e.at);e.format==="json"?m(a,"json"):(p("Broadcast scheduled successfully!"),m({ID:a.id,Name:a.name,Status:a.status,"Scheduled At":a.scheduled_at},"table"));}catch(i){l(i instanceof Error?i.message:"Failed to schedule broadcast"),process.exit(1);}}),r.command("cancel <broadcast_id>").description(`Cancel a scheduled broadcast
|
|
2058
2058
|
|
|
2059
2059
|
USAGE
|
|
2060
2060
|
emailr broadcasts cancel <broadcast_id> [options]
|
|
@@ -2082,7 +2082,7 @@ EXAMPLES
|
|
|
2082
2082
|
emailr broadcasts cancel brd_abc123 --format json
|
|
2083
2083
|
|
|
2084
2084
|
NOTE
|
|
2085
|
-
Broadcasts that are already 'sending' or 'sent' cannot be cancelled.`).option("--format <format>","Output format (json|table)","table").action(async(
|
|
2085
|
+
Broadcasts that are already 'sending' or 'sent' cannot be cancelled.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let i=d(),a=await new Emailr({apiKey:i.apiKey,baseUrl:i.baseUrl}).broadcasts.cancel(t);e.format==="json"?m(a,"json"):p("Broadcast cancelled successfully!");}catch(i){l(i instanceof Error?i.message:"Failed to cancel broadcast"),process.exit(1);}}),r.command("update <broadcast_id>").description(`Update a broadcast
|
|
2086
2086
|
|
|
2087
2087
|
USAGE
|
|
2088
2088
|
emailr broadcasts update <broadcast_id> [options]
|
|
@@ -2135,7 +2135,7 @@ EXAMPLES
|
|
|
2135
2135
|
emailr broadcasts update brd_abc123 --name "Updated" --format json
|
|
2136
2136
|
|
|
2137
2137
|
NOTE
|
|
2138
|
-
Only broadcasts in 'draft' or 'scheduled' status can be updated.`).option("--name <name>","Broadcast name").option("--subject <subject>","Email subject").option("--from <email>","Sender email address").option("--from-name <name>","Sender display name").option("--reply-to <email>","Reply-To email address").option("--preview-text <text>","Preview text (preheader)").option("--inbox-id <inbox_id>",'Inbox ID for sender identity (use "none" to clear)').option("--inbox-ids <ids>",'Comma-separated inbox IDs for rotation (use "none" to clear)').option("--sending-speed <speed>",'Sending speed: auto | slow | normal | instant (use "none" to clear)').option("--template <id>",'Template ID (use "none" to clear)').option("--segment <id>",'Segment ID (use "none" to clear)').option("--topic <id>",'Topic ID (use "none" to clear)').option("--html <html>","HTML content").option("--text <text>","Plain text content").option("--schedule <datetime>",'Schedule time ISO 8601 (use "none" to clear)').option("--tags <tags>","Comma-separated tags (replaces existing)").option("--format <format>","Output format (json|table)","table").action(async(
|
|
2138
|
+
Only broadcasts in 'draft' or 'scheduled' status can be updated.`).option("--name <name>","Broadcast name").option("--subject <subject>","Email subject").option("--from <email>","Sender email address").option("--from-name <name>","Sender display name").option("--reply-to <email>","Reply-To email address").option("--preview-text <text>","Preview text (preheader)").option("--inbox-id <inbox_id>",'Inbox ID for sender identity (use "none" to clear)').option("--inbox-ids <ids>",'Comma-separated inbox IDs for rotation (use "none" to clear)').option("--sending-speed <speed>",'Sending speed: auto | slow | normal | instant (use "none" to clear)').option("--template <id>",'Template ID (use "none" to clear)').option("--segment <id>",'Segment ID (use "none" to clear)').option("--topic <id>",'Topic ID (use "none" to clear)').option("--html <html>","HTML content").option("--text <text>","Plain text content").option("--schedule <datetime>",'Schedule time ISO 8601 (use "none" to clear)').option("--tags <tags>","Comma-separated tags (replaces existing)").option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let i=d(),n=new Emailr({apiKey:i.apiKey,baseUrl:i.baseUrl}),a={};e.name&&(a.name=e.name),e.subject&&(a.subject=e.subject),e.from&&(a.from_email=e.from),e.fromName&&(a.from_name=e.fromName),e.replyTo&&(a.reply_to=e.replyTo),e.previewText&&(a.preview_text=e.previewText),e.html&&(a.html_content=e.html),e.text&&(a.text_content=e.text),e.inboxId&&(a.inbox_id=e.inboxId==="none"?null:e.inboxId),e.inboxIds&&(a.inbox_ids=e.inboxIds==="none"?null:e.inboxIds.split(",").map(s=>s.trim()).filter(Boolean)),e.sendingSpeed&&(a.sending_speed=e.sendingSpeed==="none"?null:e.sendingSpeed),e.template&&(a.template_id=e.template==="none"?null:e.template),e.segment&&(a.segment_id=e.segment==="none"?null:e.segment),e.topic&&(a.topic_id=e.topic==="none"?null:e.topic),e.schedule&&(a.scheduled_at=e.schedule==="none"?null:e.schedule),e.tags&&(a.tags=e.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean)),Object.keys(a).length===0&&(l("No update fields specified. Use --help to see available options."),process.exit(1));let o=await n.broadcasts.update(t,a);e.format==="json"?m(o,"json"):(p("Broadcast updated successfully!"),m({ID:o.id,Name:o.name,Subject:o.subject,Status:o.status,Tags:o.tags?.join(", ")||"-","Scheduled At":o.scheduled_at||"Not scheduled"},"table"));}catch(i){l(i instanceof Error?i.message:"Failed to update broadcast"),process.exit(1);}}),r.command("delete <broadcast_id>").description(`Delete a broadcast
|
|
2139
2139
|
|
|
2140
2140
|
USAGE
|
|
2141
2141
|
emailr broadcasts delete <broadcast_id> [options]
|
|
@@ -2163,391 +2163,76 @@ EXAMPLES
|
|
|
2163
2163
|
|
|
2164
2164
|
WARNING
|
|
2165
2165
|
This action is permanent and cannot be undone.
|
|
2166
|
-
All delivery statistics will be lost.`).option("--format <format>","Output format (json|table)","table").action(async(
|
|
2166
|
+
All delivery statistics will be lost.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let i=d(),a=await new Emailr({apiKey:i.apiKey,baseUrl:i.baseUrl}).broadcasts.delete(t);e.format==="json"?m(a,"json"):p("Broadcast deleted successfully!");}catch(i){l(i instanceof Error?i.message:"Failed to delete broadcast"),process.exit(1);}}),r}function Pe(){let r=new Command("webhooks").description(`Manage webhooks
|
|
2167
2167
|
|
|
2168
2168
|
USAGE
|
|
2169
2169
|
emailr webhooks <subcommand> [options]
|
|
2170
2170
|
|
|
2171
2171
|
DESCRIPTION
|
|
2172
|
-
Create
|
|
2173
|
-
notifications about email and
|
|
2174
|
-
integrate Emailr with your own systems and automate workflows.
|
|
2172
|
+
Create and manage webhook endpoints for receiving real-time
|
|
2173
|
+
notifications about email, contact, and domain events.
|
|
2175
2174
|
|
|
2176
2175
|
SUBCOMMANDS
|
|
2177
2176
|
list List all webhooks
|
|
2178
|
-
get <id> Get webhook details including secret
|
|
2179
2177
|
create Create a new webhook endpoint
|
|
2180
|
-
|
|
2181
|
-
enable <id> Enable a disabled webhook
|
|
2182
|
-
disable <id> Disable a webhook (stops event delivery)
|
|
2178
|
+
toggle <id> Toggle webhook active state (enable/disable)
|
|
2183
2179
|
delete <id> Delete a webhook permanently
|
|
2180
|
+
deliveries <id> List recent deliveries for a webhook
|
|
2184
2181
|
|
|
2185
|
-
|
|
2186
|
-
Email
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
email.bounced Email permanently rejected by recipient server
|
|
2190
|
-
email.complained Recipient marked email as spam
|
|
2191
|
-
email.opened Recipient opened the email
|
|
2192
|
-
email.clicked Recipient clicked a link in the email
|
|
2193
|
-
email.failed Email delivery failed
|
|
2194
|
-
email.delivery_delayed Email delivery temporarily delayed
|
|
2195
|
-
|
|
2196
|
-
Contact Events:
|
|
2197
|
-
contact.created New contact added to audience
|
|
2198
|
-
contact.updated Contact information updated
|
|
2199
|
-
contact.deleted Contact removed from audience
|
|
2200
|
-
|
|
2201
|
-
Domain Events:
|
|
2202
|
-
domain.verified Domain identity verified
|
|
2203
|
-
domain.verification_failed Domain verification failed
|
|
2204
|
-
domain.mail_from_verified MAIL FROM domain verified
|
|
2205
|
-
domain.mail_from_failed MAIL FROM verification failed
|
|
2206
|
-
domain.deactivated Domain deactivated
|
|
2207
|
-
|
|
2208
|
-
OPTIONS
|
|
2209
|
-
--format <format> Output format: json | table (default: table)
|
|
2210
|
-
|
|
2211
|
-
OUTPUT FORMATS
|
|
2212
|
-
--format json Machine-readable JSON output
|
|
2213
|
-
--format table Human-readable table output (default)
|
|
2214
|
-
|
|
2215
|
-
EVENTS OPTION FORMAT
|
|
2216
|
-
The --events option accepts a comma-separated list of event types:
|
|
2217
|
-
|
|
2218
|
-
Single event:
|
|
2219
|
-
--events "email.sent"
|
|
2220
|
-
|
|
2221
|
-
Multiple events:
|
|
2222
|
-
--events "email.sent,email.delivered,email.bounced"
|
|
2223
|
-
|
|
2224
|
-
All email events:
|
|
2225
|
-
--events "email.sent,email.delivered,email.bounced,email.complained,email.opened,email.clicked,email.failed"
|
|
2226
|
-
|
|
2227
|
-
Contact events:
|
|
2228
|
-
--events "contact.created,contact.updated,contact.deleted"
|
|
2229
|
-
|
|
2230
|
-
Mixed events:
|
|
2231
|
-
--events "email.delivered,email.bounced,contact.created"
|
|
2182
|
+
WEBHOOK TYPES
|
|
2183
|
+
transactional Email lifecycle events (sent, delivered, bounced, etc.)
|
|
2184
|
+
domain Domain verification lifecycle events
|
|
2185
|
+
receiving Inbound email received events
|
|
2232
2186
|
|
|
2233
2187
|
EXAMPLES
|
|
2234
2188
|
# List all webhooks
|
|
2235
2189
|
emailr webhooks list
|
|
2236
2190
|
|
|
2237
|
-
# Get webhook details (includes secret for signature verification)
|
|
2238
|
-
emailr webhooks get whk_abc123
|
|
2239
|
-
|
|
2240
2191
|
# Create webhook for email delivery events
|
|
2241
2192
|
emailr webhooks create --name "Delivery Tracker" \\
|
|
2242
2193
|
--url "https://example.com/webhooks/emailr" \\
|
|
2243
|
-
--
|
|
2244
|
-
|
|
2245
|
-
# Create webhook for all email tracking events
|
|
2246
|
-
emailr webhooks create --name "Email Analytics" \\
|
|
2247
|
-
--url "https://example.com/webhooks/analytics" \\
|
|
2248
|
-
--events "email.delivered,email.opened,email.clicked,email.bounced"
|
|
2194
|
+
--type transactional
|
|
2249
2195
|
|
|
2250
|
-
# Create webhook for
|
|
2251
|
-
emailr webhooks create --name "
|
|
2252
|
-
--url "https://example.com/webhooks/
|
|
2253
|
-
--
|
|
2196
|
+
# Create webhook for inbound emails scoped to specific inboxes
|
|
2197
|
+
emailr webhooks create --name "Inbound" \\
|
|
2198
|
+
--url "https://example.com/webhooks/inbound" \\
|
|
2199
|
+
--type receiving --inbox-ids "inbox-uuid-1,inbox-uuid-2"
|
|
2254
2200
|
|
|
2255
|
-
#
|
|
2256
|
-
emailr webhooks
|
|
2201
|
+
# Toggle webhook on/off
|
|
2202
|
+
emailr webhooks toggle whk_abc123
|
|
2257
2203
|
|
|
2258
|
-
#
|
|
2259
|
-
emailr webhooks
|
|
2260
|
-
|
|
2261
|
-
# Disable webhook temporarily
|
|
2262
|
-
emailr webhooks disable whk_abc123
|
|
2263
|
-
|
|
2264
|
-
# Re-enable webhook
|
|
2265
|
-
emailr webhooks enable whk_abc123
|
|
2204
|
+
# View recent deliveries
|
|
2205
|
+
emailr webhooks deliveries whk_abc123
|
|
2266
2206
|
|
|
2267
2207
|
# Delete webhook
|
|
2268
|
-
emailr webhooks delete whk_abc123
|
|
2269
|
-
|
|
2270
|
-
# Get JSON output for scripting
|
|
2271
|
-
emailr webhooks list --format json
|
|
2272
|
-
|
|
2273
|
-
WEBHOOK PAYLOAD
|
|
2274
|
-
Webhooks receive POST requests with JSON payloads:
|
|
2275
|
-
|
|
2276
|
-
{
|
|
2277
|
-
"type": "email.delivered",
|
|
2278
|
-
"created_at": "2024-02-22T23:41:12.126Z",
|
|
2279
|
-
"data": {
|
|
2280
|
-
"email_id": "em_abc123",
|
|
2281
|
-
"to": "recipient@example.com",
|
|
2282
|
-
"subject": "Your order confirmation"
|
|
2283
|
-
}
|
|
2284
|
-
}
|
|
2285
|
-
|
|
2286
|
-
SIGNATURE VERIFICATION
|
|
2287
|
-
Each webhook request includes an X-Emailr-Signature header.
|
|
2288
|
-
Use the webhook secret (shown in 'get' command) to verify signatures.
|
|
2289
|
-
|
|
2290
|
-
SEE ALSO
|
|
2291
|
-
emailr domains Manage sending domains
|
|
2292
|
-
emailr send Send emails directly`);return i.command("list").description(`List all webhooks
|
|
2293
|
-
|
|
2294
|
-
USAGE
|
|
2295
|
-
emailr webhooks list [options]
|
|
2296
|
-
|
|
2297
|
-
DESCRIPTION
|
|
2298
|
-
Retrieves a list of all webhook endpoints configured for your account.
|
|
2299
|
-
Shows webhook ID, name, URL, subscribed events, and active status.
|
|
2300
|
-
|
|
2301
|
-
OPTIONS
|
|
2302
|
-
--format <format> Output format: json | table (default: table)
|
|
2208
|
+
emailr webhooks delete whk_abc123`);return r.command("list").description(`List all webhooks
|
|
2303
2209
|
|
|
2304
2210
|
OUTPUT FORMATS
|
|
2305
2211
|
--format json Machine-readable JSON array of webhook objects
|
|
2306
|
-
--format table Human-readable table with
|
|
2212
|
+
--format table Human-readable table with ID, Name, URL, Type, Events, Active`).option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=d(),n=await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).webhooks.list();if(t.format==="json")m(n,"json");else {if(n.length===0){console.log("No webhooks found.");return}let a=n.map(o=>({ID:o.id,Name:o.name,URL:o.url.substring(0,40)+(o.url.length>40?"...":""),Type:o.type,Events:o.events.join(", "),Active:o.active?"Yes":"No"}));m(a,"table");}}catch(e){l(e instanceof Error?e.message:"Failed to list webhooks"),process.exit(1);}}),r.command("create").description(`Create a new webhook
|
|
2307
2213
|
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
# Filter active webhooks with jq
|
|
2316
|
-
emailr webhooks list --format json | jq '.[] | select(.active == true)'
|
|
2317
|
-
|
|
2318
|
-
# Count webhooks
|
|
2319
|
-
emailr webhooks list --format json | jq 'length'`).option("--format <format>","Output format (json|table)","table").action(async a=>{try{let e=d(),n=await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).webhooks.list();if(a.format==="json")m(n,"json");else {if(n.data.length===0){console.log("No webhooks found.");return}let t=n.data.map(r=>({ID:r.id,Name:r.name,URL:r.url.substring(0,40)+(r.url.length>40?"...":""),Events:r.events.join(", "),Active:r.active?"Yes":"No"}));m(t,"table");}}catch(e){l(e instanceof Error?e.message:"Failed to list webhooks"),process.exit(1);}}),i.command("get <webhook_id>").description(`Get webhook details
|
|
2320
|
-
|
|
2321
|
-
USAGE
|
|
2322
|
-
emailr webhooks get <webhook_id> [options]
|
|
2323
|
-
|
|
2324
|
-
DESCRIPTION
|
|
2325
|
-
Retrieves detailed information about a specific webhook including
|
|
2326
|
-
the webhook secret used for signature verification.
|
|
2327
|
-
|
|
2328
|
-
ARGUMENTS
|
|
2329
|
-
<webhook_id> The unique webhook identifier (e.g., whk_abc123)
|
|
2330
|
-
|
|
2331
|
-
OPTIONS
|
|
2332
|
-
--format <format> Output format: json | table (default: table)
|
|
2333
|
-
|
|
2334
|
-
OUTPUT FORMATS
|
|
2335
|
-
--format json Full webhook object with all fields including secret
|
|
2336
|
-
--format table Summary table with webhook details
|
|
2337
|
-
|
|
2338
|
-
WEBHOOK SECRET
|
|
2339
|
-
The secret is used to verify webhook signatures. Each webhook request
|
|
2340
|
-
includes an X-Emailr-Signature header that you can verify using this secret.
|
|
2341
|
-
|
|
2342
|
-
EXAMPLES
|
|
2343
|
-
# Get webhook details
|
|
2344
|
-
emailr webhooks get whk_abc123
|
|
2345
|
-
|
|
2346
|
-
# Get full webhook data as JSON
|
|
2347
|
-
emailr webhooks get whk_abc123 --format json
|
|
2348
|
-
|
|
2349
|
-
# Extract just the secret
|
|
2350
|
-
emailr webhooks get whk_abc123 --format json | jq -r '.secret'`).option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let o=d(),t=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).webhooks.get(a);e.format==="json"?m(t,"json"):m({ID:t.id,Name:t.name,URL:t.url,Events:t.events.join(", "),Active:t.active?"Yes":"No",Secret:t.secret,"Created At":t.created_at},"table");}catch(o){l(o instanceof Error?o.message:"Failed to get webhook"),process.exit(1);}}),i.command("create").description(`Create a new webhook
|
|
2351
|
-
|
|
2352
|
-
USAGE
|
|
2353
|
-
emailr webhooks create --name <name> --url <url> --events <events> [options]
|
|
2354
|
-
|
|
2355
|
-
DESCRIPTION
|
|
2356
|
-
Creates a new webhook endpoint to receive real-time notifications
|
|
2357
|
-
about email and contact events. The webhook is enabled by default.
|
|
2358
|
-
|
|
2359
|
-
OPTIONS
|
|
2360
|
-
--name <webhook_name> Webhook name for identification (required)
|
|
2361
|
-
--url <endpoint_url> HTTPS URL to receive webhook POST requests (required)
|
|
2362
|
-
--events <event_list> Comma-separated list of event types (required)
|
|
2363
|
-
--format <format> Output format: json | table (default: table)
|
|
2364
|
-
|
|
2365
|
-
AVAILABLE EVENT TYPES
|
|
2366
|
-
Email Events:
|
|
2367
|
-
email.sent Email accepted for delivery
|
|
2368
|
-
email.delivered Email successfully delivered
|
|
2369
|
-
email.bounced Email permanently rejected
|
|
2370
|
-
email.complained Recipient marked as spam
|
|
2371
|
-
email.opened Recipient opened email
|
|
2372
|
-
email.clicked Recipient clicked link
|
|
2373
|
-
email.failed Delivery failed
|
|
2374
|
-
email.delivery_delayed Delivery temporarily delayed
|
|
2375
|
-
|
|
2376
|
-
Contact Events:
|
|
2377
|
-
contact.created New contact added
|
|
2378
|
-
contact.updated Contact updated
|
|
2379
|
-
contact.deleted Contact removed
|
|
2380
|
-
|
|
2381
|
-
Domain Events:
|
|
2382
|
-
domain.verified Domain verified
|
|
2383
|
-
domain.verification_failed Verification failed
|
|
2384
|
-
domain.mail_from_verified MAIL FROM verified
|
|
2385
|
-
domain.mail_from_failed MAIL FROM failed
|
|
2386
|
-
domain.deactivated Domain deactivated
|
|
2387
|
-
|
|
2388
|
-
EVENTS FORMAT
|
|
2389
|
-
Provide events as a comma-separated list (no spaces after commas):
|
|
2390
|
-
--events "email.sent,email.delivered,email.bounced"
|
|
2214
|
+
WEBHOOK TYPES
|
|
2215
|
+
transactional Subscribes to: email.sent, email.delivered, email.bounced,
|
|
2216
|
+
email.complained, email.opened, email.clicked, email.failed
|
|
2217
|
+
domain Subscribes to: domain.verified, domain.verification_failed,
|
|
2218
|
+
domain.mail_from_verified, domain.mail_from_failed, domain.deactivated
|
|
2219
|
+
receiving Subscribes to: email.received (optionally scoped to inbox IDs)
|
|
2391
2220
|
|
|
2392
2221
|
OUTPUT FORMATS
|
|
2393
2222
|
--format json Full webhook object including generated secret
|
|
2394
|
-
--format table Summary with ID, Name, URL, and Secret
|
|
2395
|
-
|
|
2396
|
-
EXAMPLES
|
|
2397
|
-
# Create webhook for delivery tracking
|
|
2398
|
-
emailr webhooks create --name "Delivery Tracker" \\
|
|
2399
|
-
--url "https://example.com/webhooks/emailr" \\
|
|
2400
|
-
--events "email.sent,email.delivered,email.bounced"
|
|
2401
|
-
|
|
2402
|
-
# Create webhook for email analytics
|
|
2403
|
-
emailr webhooks create --name "Analytics" \\
|
|
2404
|
-
--url "https://analytics.example.com/hook" \\
|
|
2405
|
-
--events "email.delivered,email.opened,email.clicked"
|
|
2406
|
-
|
|
2407
|
-
# Create webhook for CRM integration
|
|
2408
|
-
emailr webhooks create --name "CRM Sync" \\
|
|
2409
|
-
--url "https://crm.example.com/emailr" \\
|
|
2410
|
-
--events "contact.created,contact.updated,contact.deleted"
|
|
2411
|
-
|
|
2412
|
-
# Create webhook for bounce handling
|
|
2413
|
-
emailr webhooks create --name "Bounce Handler" \\
|
|
2414
|
-
--url "https://example.com/bounces" \\
|
|
2415
|
-
--events "email.bounced,email.complained"
|
|
2416
|
-
|
|
2417
|
-
# Get JSON output with secret
|
|
2418
|
-
emailr webhooks create --name "Test" \\
|
|
2419
|
-
--url "https://example.com/test" \\
|
|
2420
|
-
--events "email.sent" --format json
|
|
2421
|
-
|
|
2422
|
-
NOTE
|
|
2423
|
-
Save the webhook secret returned by this command. You'll need it
|
|
2424
|
-
to verify webhook signatures in your endpoint.`).requiredOption("--name <name>","Webhook name").requiredOption("--url <url>","Webhook URL").requiredOption("--events <events>","Events to subscribe to (comma-separated)").option("--format <format>","Output format (json|table)","table").action(async a=>{try{let e=d(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),n=a.events.split(",").map(r=>r.trim()),t=await o.webhooks.create({name:a.name,url:a.url,events:n});a.format==="json"?m(t,"json"):(p("Webhook created successfully!"),m({ID:t.id,Name:t.name,URL:t.url,Secret:t.secret},"table"));}catch(e){l(e instanceof Error?e.message:"Failed to create webhook"),process.exit(1);}}),i.command("update <webhook_id>").description(`Update a webhook
|
|
2425
|
-
|
|
2426
|
-
USAGE
|
|
2427
|
-
emailr webhooks update <webhook_id> [options]
|
|
2428
|
-
|
|
2429
|
-
DESCRIPTION
|
|
2430
|
-
Updates an existing webhook's name, URL, or subscribed events.
|
|
2431
|
-
Only provide the options you want to change.
|
|
2432
|
-
|
|
2433
|
-
ARGUMENTS
|
|
2434
|
-
<webhook_id> The unique webhook identifier (e.g., whk_abc123)
|
|
2435
|
-
|
|
2436
|
-
OPTIONS
|
|
2437
|
-
--name <webhook_name> New webhook name
|
|
2438
|
-
--url <endpoint_url> New webhook URL
|
|
2439
|
-
--events <event_list> New comma-separated list of events (replaces existing)
|
|
2440
|
-
--format <format> Output format: json | table (default: table)
|
|
2441
|
-
|
|
2442
|
-
EVENTS FORMAT
|
|
2443
|
-
The --events option replaces all existing events:
|
|
2444
|
-
--events "email.sent,email.delivered"
|
|
2445
|
-
|
|
2446
|
-
To add events, first get current events, then include all in update.
|
|
2447
|
-
|
|
2448
|
-
OUTPUT FORMATS
|
|
2449
|
-
--format json Updated webhook object
|
|
2450
|
-
--format table Summary with ID, Name, URL
|
|
2451
|
-
|
|
2452
|
-
EXAMPLES
|
|
2453
|
-
# Update webhook name
|
|
2454
|
-
emailr webhooks update whk_abc123 --name "New Name"
|
|
2455
|
-
|
|
2456
|
-
# Update webhook URL
|
|
2457
|
-
emailr webhooks update whk_abc123 --url "https://new-url.com/webhook"
|
|
2458
|
-
|
|
2459
|
-
# Update subscribed events
|
|
2460
|
-
emailr webhooks update whk_abc123 --events "email.sent,email.delivered,email.bounced"
|
|
2461
|
-
|
|
2462
|
-
# Update multiple fields
|
|
2463
|
-
emailr webhooks update whk_abc123 \\
|
|
2464
|
-
--name "Updated Webhook" \\
|
|
2465
|
-
--url "https://new-url.com/hook" \\
|
|
2466
|
-
--events "email.delivered,email.bounced"
|
|
2467
|
-
|
|
2468
|
-
# Get JSON output
|
|
2469
|
-
emailr webhooks update whk_abc123 --name "New Name" --format json`).option("--name <name>","New webhook name").option("--url <url>","New webhook URL").option("--events <events>","New events (comma-separated)").option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let o=d(),n=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),t={};e.name&&(t.name=e.name),e.url&&(t.url=e.url),e.events&&(t.events=e.events.split(",").map(s=>s.trim()));let r=await n.webhooks.update(a,t);e.format==="json"?m(r,"json"):(p("Webhook updated successfully!"),m({ID:r.id,Name:r.name,URL:r.url},"table"));}catch(o){l(o instanceof Error?o.message:"Failed to update webhook"),process.exit(1);}}),i.command("enable <webhook_id>").description(`Enable a webhook
|
|
2470
|
-
|
|
2471
|
-
USAGE
|
|
2472
|
-
emailr webhooks enable <webhook_id> [options]
|
|
2473
|
-
|
|
2474
|
-
DESCRIPTION
|
|
2475
|
-
Enables a disabled webhook to resume receiving event notifications.
|
|
2476
|
-
Use this after fixing issues with your webhook endpoint.
|
|
2477
|
-
|
|
2478
|
-
ARGUMENTS
|
|
2479
|
-
<webhook_id> The unique webhook identifier (e.g., whk_abc123)
|
|
2480
|
-
|
|
2481
|
-
OPTIONS
|
|
2482
|
-
--format <format> Output format: json | table (default: table)
|
|
2223
|
+
--format table Summary with ID, Name, URL, Type, and Secret`).requiredOption("--name <name>","Webhook name").requiredOption("--url <url>","Webhook URL (HTTPS)").requiredOption("--type <type>","Webhook type: transactional | domain | receiving").option("--inbox-ids <ids>","Comma-separated inbox UUIDs (only for receiving type)").option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=["transactional","domain","receiving"];e.includes(t.type)||(l(`Invalid type "${t.type}". Must be one of: ${e.join(", ")}`),process.exit(1));let i=d(),n=new Emailr({apiKey:i.apiKey,baseUrl:i.baseUrl}),a={name:t.name,url:t.url,type:t.type};t.inboxIds&&(a.inbox_ids=t.inboxIds.split(",").map(s=>s.trim()));let o=await n.webhooks.create(a);t.format==="json"?m(o,"json"):(p("Webhook created successfully!"),m({ID:o.id,Name:o.name,URL:o.url,Type:o.type,Events:o.events.join(", "),Secret:o.secret},"table"));}catch(e){l(e instanceof Error?e.message:"Failed to create webhook"),process.exit(1);}}),r.command("toggle <webhook_id>").description(`Toggle webhook active state (enable/disable)
|
|
2483
2224
|
|
|
2484
2225
|
OUTPUT FORMATS
|
|
2485
2226
|
--format json Returns: { success: boolean, active: boolean }
|
|
2486
|
-
--format table Human-readable success message
|
|
2487
|
-
|
|
2488
|
-
EXAMPLES
|
|
2489
|
-
# Enable a webhook
|
|
2490
|
-
emailr webhooks enable whk_abc123
|
|
2491
|
-
|
|
2492
|
-
# Get JSON output
|
|
2493
|
-
emailr webhooks enable whk_abc123 --format json`).option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let o=d(),t=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).webhooks.enable(a);e.format==="json"?m(t,"json"):p("Webhook enabled successfully!");}catch(o){l(o instanceof Error?o.message:"Failed to enable webhook"),process.exit(1);}}),i.command("disable <webhook_id>").description(`Disable a webhook
|
|
2494
|
-
|
|
2495
|
-
USAGE
|
|
2496
|
-
emailr webhooks disable <webhook_id> [options]
|
|
2497
|
-
|
|
2498
|
-
DESCRIPTION
|
|
2499
|
-
Disables a webhook to temporarily stop receiving event notifications.
|
|
2500
|
-
Events that occur while disabled are not queued or retried.
|
|
2501
|
-
Use 'enable' to resume receiving events.
|
|
2502
|
-
|
|
2503
|
-
ARGUMENTS
|
|
2504
|
-
<webhook_id> The unique webhook identifier (e.g., whk_abc123)
|
|
2505
|
-
|
|
2506
|
-
OPTIONS
|
|
2507
|
-
--format <format> Output format: json | table (default: table)
|
|
2227
|
+
--format table Human-readable success message`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let i=d(),a=await new Emailr({apiKey:i.apiKey,baseUrl:i.baseUrl}).webhooks.toggle(t);e.format==="json"?m(a,"json"):p(`Webhook ${a.active?"enabled":"disabled"} successfully!`);}catch(i){l(i instanceof Error?i.message:"Failed to toggle webhook"),process.exit(1);}}),r.command("deliveries <webhook_id>").description(`List recent deliveries for a webhook
|
|
2508
2228
|
|
|
2509
2229
|
OUTPUT FORMATS
|
|
2510
|
-
--format json
|
|
2511
|
-
--format table Human-readable
|
|
2512
|
-
|
|
2513
|
-
EXAMPLES
|
|
2514
|
-
# Disable a webhook
|
|
2515
|
-
emailr webhooks disable whk_abc123
|
|
2516
|
-
|
|
2517
|
-
# Get JSON output
|
|
2518
|
-
emailr webhooks disable whk_abc123 --format json
|
|
2519
|
-
|
|
2520
|
-
NOTE
|
|
2521
|
-
Events are not queued while webhook is disabled. If you need to
|
|
2522
|
-
temporarily stop processing, consider handling this in your endpoint.`).option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let o=d(),t=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).webhooks.disable(a);e.format==="json"?m(t,"json"):p("Webhook disabled successfully!");}catch(o){l(o instanceof Error?o.message:"Failed to disable webhook"),process.exit(1);}}),i.command("delete <webhook_id>").description(`Delete a webhook
|
|
2523
|
-
|
|
2524
|
-
USAGE
|
|
2525
|
-
emailr webhooks delete <webhook_id> [options]
|
|
2526
|
-
|
|
2527
|
-
DESCRIPTION
|
|
2528
|
-
Permanently deletes a webhook endpoint. This action cannot be undone.
|
|
2529
|
-
The webhook will immediately stop receiving events.
|
|
2530
|
-
|
|
2531
|
-
ARGUMENTS
|
|
2532
|
-
<webhook_id> The unique webhook identifier (e.g., whk_abc123)
|
|
2533
|
-
|
|
2534
|
-
OPTIONS
|
|
2535
|
-
--format <format> Output format: json | table (default: table)
|
|
2230
|
+
--format json Machine-readable JSON array of delivery objects
|
|
2231
|
+
--format table Human-readable table with ID, Event, Status, Attempts, Dates`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let i=d(),a=await new Emailr({apiKey:i.apiKey,baseUrl:i.baseUrl}).webhooks.listDeliveries(t);if(e.format==="json")m(a,"json");else {if(a.length===0){console.log("No deliveries found.");return}let o=a.map(s=>({ID:s.id,Event:s.event_type,Status:s.response_status??"-",Attempts:s.attempt_count,"Delivered At":s.delivered_at??"-",Created:new Date(s.created_at).toLocaleString()}));m(o,"table");}}catch(i){l(i instanceof Error?i.message:"Failed to list deliveries"),process.exit(1);}}),r.command("delete <webhook_id>").description(`Delete a webhook permanently
|
|
2536
2232
|
|
|
2537
2233
|
OUTPUT FORMATS
|
|
2538
2234
|
--format json Returns: { success: boolean }
|
|
2539
|
-
--format table Human-readable success message
|
|
2540
|
-
|
|
2541
|
-
EXAMPLES
|
|
2542
|
-
# Delete a webhook
|
|
2543
|
-
emailr webhooks delete whk_abc123
|
|
2544
|
-
|
|
2545
|
-
# Get JSON output
|
|
2546
|
-
emailr webhooks delete whk_abc123 --format json
|
|
2547
|
-
|
|
2548
|
-
WARNING
|
|
2549
|
-
This action is permanent and cannot be undone.
|
|
2550
|
-
Create a new webhook if you need to restore functionality.`).option("--format <format>","Output format (json|table)","table").action(async(a,e)=>{try{let o=d(),t=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).webhooks.delete(a);e.format==="json"?m(t,"json"):p("Webhook deleted successfully!");}catch(o){l(o instanceof Error?o.message:"Failed to delete webhook"),process.exit(1);}}),i}function Pe(){let i=new Command("segments").description(`Manage contact segments
|
|
2235
|
+
--format table Human-readable success message`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let i=d(),a=await new Emailr({apiKey:i.apiKey,baseUrl:i.baseUrl}).webhooks.delete(t);e.format==="json"?m(a,"json"):p("Webhook deleted successfully!");}catch(i){l(i instanceof Error?i.message:"Failed to delete webhook"),process.exit(1);}}),r}function Ae(){let r=new Command("segments").description(`Manage contact segments
|
|
2551
2236
|
|
|
2552
2237
|
USAGE
|
|
2553
2238
|
emailr segments <subcommand> [options]
|
|
@@ -2662,7 +2347,7 @@ EXAMPLES
|
|
|
2662
2347
|
|
|
2663
2348
|
SEE ALSO
|
|
2664
2349
|
emailr contacts Manage individual contacts
|
|
2665
|
-
emailr broadcasts Send emails to segments`);return
|
|
2350
|
+
emailr broadcasts Send emails to segments`);return r.command("list").description(`List all segments
|
|
2666
2351
|
|
|
2667
2352
|
USAGE
|
|
2668
2353
|
emailr segments list [options]
|
|
@@ -2687,7 +2372,7 @@ EXAMPLES
|
|
|
2687
2372
|
emailr segments list --format json
|
|
2688
2373
|
|
|
2689
2374
|
# Pipe JSON to jq for processing
|
|
2690
|
-
emailr segments list --format json | jq '.[].name'`).option("--tags <tags>","Filter by tags (comma-separated)").option("--format <format>","Output format (json|table)","table").action(async
|
|
2375
|
+
emailr segments list --format json | jq '.[].name'`).option("--tags <tags>","Filter by tags (comma-separated)").option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=d(),i=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),n={};if(t.tags){let o=t.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean);o.length>0&&(n.tags=o.join(","));}let a=await i.segments.list(n);if(t.format==="json")m(a,"json");else {if(a.length===0){console.log("No segments found.");return}let o=a.map(s=>({ID:s.id,Name:s.name,Description:(s.description||"").substring(0,30)+((s.description?.length||0)>30?"...":""),Tags:s.tags?.join(", ")||"-","Created At":new Date(s.created_at).toLocaleDateString()}));m(o,"table");}}catch(e){l(e instanceof Error?e.message:"Failed to list segments"),process.exit(1);}}),r.command("get <segment_id>").description(`Get segment details
|
|
2691
2376
|
|
|
2692
2377
|
USAGE
|
|
2693
2378
|
emailr segments get <segment_id> [options]
|
|
@@ -2714,7 +2399,7 @@ EXAMPLES
|
|
|
2714
2399
|
emailr segments get seg_abc123 --format json
|
|
2715
2400
|
|
|
2716
2401
|
# Pipe JSON to jq to view conditions
|
|
2717
|
-
emailr segments get seg_abc123 --format json | jq '.conditions'`).option("--format <format>","Output format (json|table)","table").action(async(
|
|
2402
|
+
emailr segments get seg_abc123 --format json | jq '.conditions'`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let i=d(),a=await new Emailr({apiKey:i.apiKey,baseUrl:i.baseUrl}).segments.get(t);e.format==="json"?m(a,"json"):m({ID:a.id,Name:a.name,Description:a.description||"N/A",Conditions:JSON.stringify(a.conditions),Tags:a.tags?.join(", ")||"-","Created At":a.created_at,"Updated At":a.updated_at},"table");}catch(i){l(i instanceof Error?i.message:"Failed to get segment"),process.exit(1);}}),r.command("create").description(`Create a new segment
|
|
2718
2403
|
|
|
2719
2404
|
USAGE
|
|
2720
2405
|
emailr segments create --name <segment_name> --conditions <json> [options]
|
|
@@ -2764,7 +2449,7 @@ EXAMPLES
|
|
|
2764
2449
|
# Get JSON output for scripting
|
|
2765
2450
|
emailr segments create --name "Test" \\
|
|
2766
2451
|
--conditions '[{"field": "subscribed", "operator": "equals", "value": true}]' \\
|
|
2767
|
-
--format json`).requiredOption("--name <name>","Segment name").requiredOption("--conditions <json>","Segment conditions as JSON").option("--description <description>","Segment description").option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format (json|table)","table").action(async
|
|
2452
|
+
--format json`).requiredOption("--name <name>","Segment name").requiredOption("--conditions <json>","Segment conditions as JSON").option("--description <description>","Segment description").option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=d(),i=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),n;try{n=JSON.parse(t.conditions);}catch{l("Invalid JSON for --conditions"),process.exit(1);}let a={name:t.name,description:t.description,conditions:n};t.tags&&(a.tags=t.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean));let o=await i.segments.create(a);t.format==="json"?m(o,"json"):(p("Segment created successfully!"),m({ID:o.id,Name:o.name,Tags:o.tags?.join(", ")||"-"},"table"));}catch(e){l(e instanceof Error?e.message:"Failed to create segment"),process.exit(1);}}),r.command("update <segment_id>").description(`Update a segment
|
|
2768
2453
|
|
|
2769
2454
|
USAGE
|
|
2770
2455
|
emailr segments update <segment_id> [options]
|
|
@@ -2810,7 +2495,7 @@ EXAMPLES
|
|
|
2810
2495
|
--conditions '[{"field": "metadata.plan", "operator": "equals", "value": "enterprise"}]'
|
|
2811
2496
|
|
|
2812
2497
|
# Get JSON output
|
|
2813
|
-
emailr segments update seg_abc123 --name "Updated" --format json`).option("--name <name>","New segment name").option("--description <description>","New description").option("--conditions <json>","New conditions as JSON").option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format (json|table)","table").action(async(
|
|
2498
|
+
emailr segments update seg_abc123 --name "Updated" --format json`).option("--name <name>","New segment name").option("--description <description>","New description").option("--conditions <json>","New conditions as JSON").option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let i=d(),n=new Emailr({apiKey:i.apiKey,baseUrl:i.baseUrl}),a={};if(e.name&&(a.name=e.name),e.description&&(a.description=e.description),e.conditions)try{a.conditions=JSON.parse(e.conditions);}catch{l("Invalid JSON for --conditions"),process.exit(1);}e.tags&&(a.tags=e.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean));let o=await n.segments.update(t,a);e.format==="json"?m(o,"json"):(p("Segment updated successfully!"),m({ID:o.id,Name:o.name,Tags:o.tags?.join(", ")||"-"},"table"));}catch(i){l(i instanceof Error?i.message:"Failed to update segment"),process.exit(1);}}),r.command("delete <segment_id>").description(`Delete a segment
|
|
2814
2499
|
|
|
2815
2500
|
USAGE
|
|
2816
2501
|
emailr segments delete <segment_id>
|
|
@@ -2835,7 +2520,7 @@ EXAMPLES
|
|
|
2835
2520
|
|
|
2836
2521
|
WARNING
|
|
2837
2522
|
This action is permanent and cannot be undone.
|
|
2838
|
-
Any broadcasts targeting this segment will need to be updated.`).option("--format <format>","Output format (json|table)","table").action(async(
|
|
2523
|
+
Any broadcasts targeting this segment will need to be updated.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let i=d(),a=await new Emailr({apiKey:i.apiKey,baseUrl:i.baseUrl}).segments.delete(t);e.format==="json"?m(a,"json"):p("Segment deleted successfully!");}catch(i){l(i instanceof Error?i.message:"Failed to delete segment"),process.exit(1);}}),r.command("count <segment_id>").description(`Get the number of contacts in a segment
|
|
2839
2524
|
|
|
2840
2525
|
USAGE
|
|
2841
2526
|
emailr segments count <segment_id> [options]
|
|
@@ -2866,7 +2551,7 @@ EXAMPLES
|
|
|
2866
2551
|
|
|
2867
2552
|
TIP
|
|
2868
2553
|
Use this before sending broadcasts to verify your segment
|
|
2869
|
-
targets the expected number of contacts.`).option("--format <format>","Output format (json|table)","table").action(async(
|
|
2554
|
+
targets the expected number of contacts.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let i=d(),a=await new Emailr({apiKey:i.apiKey,baseUrl:i.baseUrl}).segments.getContactsCount(t);e.format==="json"?m(a,"json"):console.log(`Segment contains ${a.count} contacts.`);}catch(i){l(i instanceof Error?i.message:"Failed to get segment count"),process.exit(1);}}),r}function wt(r){try{let t=r.startsWith("http")?r:`http://localhost${r}`,e=new URL(t);return {key:e.searchParams.get("key")??void 0,code:e.searchParams.get("code")??void 0,state:e.searchParams.get("state")??void 0,error:e.searchParams.get("error")??void 0,message:e.searchParams.get("message")??void 0}}catch{return {}}}function St(){return `<!DOCTYPE html>
|
|
2870
2555
|
<html lang="en">
|
|
2871
2556
|
<head>
|
|
2872
2557
|
<meta charset="UTF-8">
|
|
@@ -2912,7 +2597,7 @@ TIP
|
|
|
2912
2597
|
<p>You can close this window and return to your terminal.</p>
|
|
2913
2598
|
</div>
|
|
2914
2599
|
</body>
|
|
2915
|
-
</html>`}function
|
|
2600
|
+
</html>`}function ie(r){return `<!DOCTYPE html>
|
|
2916
2601
|
<html lang="en">
|
|
2917
2602
|
<head>
|
|
2918
2603
|
<meta charset="UTF-8">
|
|
@@ -2963,11 +2648,11 @@ TIP
|
|
|
2963
2648
|
<div class="icon">\u2717</div>
|
|
2964
2649
|
<h1>Login Failed</h1>
|
|
2965
2650
|
<p>Something went wrong during authentication.</p>
|
|
2966
|
-
<div class="error-message">${
|
|
2651
|
+
<div class="error-message">${r.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}</div>
|
|
2967
2652
|
<p style="margin-top: 1rem;">Please close this window and try again.</p>
|
|
2968
2653
|
</div>
|
|
2969
2654
|
</body>
|
|
2970
|
-
</html>`}function
|
|
2655
|
+
</html>`}function Re(){let r=null,t=0,e=null,i=null,n=null;return {async start(){return new Promise((a,o)=>{r=at.createServer((s,c)=>{if(s.method!=="GET"||!s.url?.startsWith("/callback")){c.writeHead(404,{"Content-Type":"text/plain"}),c.end("Not Found");return}let b=wt(s.url);if(n&&b.state!==n){c.writeHead(400,{"Content-Type":"text/html"}),c.end(ie("Security verification failed. State parameter mismatch.")),e&&e({success:false,error:"State parameter mismatch"});return}if(b.error){let f=b.message||b.error;c.writeHead(200,{"Content-Type":"text/html"}),c.end(ie(f)),e&&e({success:false,error:f});return}let g=b.key||b.code;if(g){c.writeHead(200,{"Content-Type":"text/html"}),c.end(St()),e&&e({success:true,apiKey:g});return}c.writeHead(400,{"Content-Type":"text/html"}),c.end(ie("Invalid callback: missing required parameters.")),e&&e({success:false,error:"Invalid callback: missing required parameters"});}),r.listen(0,"127.0.0.1",()=>{let s=r.address();s&&typeof s=="object"?(t=s.port,a({port:t,url:`http://127.0.0.1:${t}/callback`})):o(new Error("Failed to get server address"));}),r.on("error",s=>{o(new Error(`Failed to start callback server: ${s.message}`));});})},async waitForCallback(a,o){return n=a,new Promise(s=>{e=s,i=setTimeout(()=>{e&&e({success:false,error:"Login timed out. Please try again."});},o);})},async stop(){if(i&&(clearTimeout(i),i=null),r)return new Promise(a=>{r.close(()=>{r=null,a();});})}}}function De(){return vt.randomBytes(32).toString("hex")}function ke(r){return new Promise(t=>{let e=process.platform,i;switch(e){case "darwin":i=`open "${r}"`;break;case "win32":i=`start "" "${r}"`;break;default:i=`xdg-open "${r}"`;break}exec(i,n=>{t(!n);});})}var X=120,Ot=process.env.EMAILR_WEB_URL||"https://app.emailr.dev";function Et(r,t){let e=`http://127.0.0.1:${t}/callback`,i=new URLSearchParams({state:r,callback_url:e});return `${Ot}/consent/authorize?${i.toString()}`}function Me(){return new Command("login").description("Log in to Emailr via browser authentication").option("-t, --timeout <seconds>","Timeout in seconds",String(X)).option("--no-browser","Don't automatically open the browser").action(async t=>{await _t({timeout:parseInt(t.timeout,10)||X,noBrowser:t.browser===false});})}async function _t(r){let t=Re(),e=(r.timeout||X)*1e3;try{u("Starting authentication server...");let{port:i,url:n}=await t.start(),a=De(),o=Et(a,i);console.log(""),u("Authorization URL:"),console.log(` ${o}`),console.log(""),r.noBrowser?u("Please open the URL above in your browser to continue."):await ke(o)?u("Browser opened. Please complete authentication in your browser."):(C("Could not open browser automatically."),u("Please open the URL above in your browser to continue.")),console.log(""),u(`Waiting for authentication (timeout: ${r.timeout||X}s)...`);let s=await t.waitForCallback(a,e);s.success&&s.apiKey?(G({apiKey:s.apiKey}),console.log(""),p("Login successful!"),u(`API key saved to: ${I()}`),u("You can now use the Emailr CLI.")):(console.log(""),l(s.error||"Authentication failed."),u("Please try again or use manual configuration:"),console.log(" emailr config set api-key <your-api-key>"),process.exit(1));}catch(i){console.log(""),l(i instanceof Error?i.message:"An unexpected error occurred."),u("Please try again or use manual configuration:"),console.log(" emailr config set api-key <your-api-key>"),process.exit(1);}finally{await t.stop();}}var re=E.join(V.homedir(),".config","opencode","skills","emailr-cli"),Nt=`---
|
|
2971
2656
|
name: emailr-cli
|
|
2972
2657
|
description: Operate the Emailr CLI to send emails, reply to threads, manage contacts, templates, inboxes, domains, broadcasts, webhooks, and segments. Includes thread reply auto-resolution and live preview editing for templates.
|
|
2973
2658
|
---
|
|
@@ -3083,7 +2768,7 @@ emailr domains add example.com
|
|
|
3083
2768
|
emailr domains verify example.com
|
|
3084
2769
|
emailr domains list
|
|
3085
2770
|
\`\`\`
|
|
3086
|
-
`;function Ut(){try{return execSync("which opencode",{stdio:"ignore"}),!0}catch{return false}}function
|
|
2771
|
+
`;function Ut(){try{return execSync("which opencode",{stdio:"ignore"}),!0}catch{return false}}function Pt(){console.log("Installing OpenCode AI agent...");try{return execSync("npm install -g opencode-ai@latest",{stdio:"inherit"}),!0}catch{if(process.platform==="darwin")try{return execSync("brew install anomalyco/tap/opencode",{stdio:"inherit"}),!0}catch{return false}return false}}function At(){T.existsSync(re)||T.mkdirSync(re,{recursive:true});let r=E.join(re,"SKILL.md");T.writeFileSync(r,Nt,"utf-8");}function Fe(){return new Command("agent").description(`Launch an AI agent with Emailr CLI expertise
|
|
3087
2772
|
|
|
3088
2773
|
This opens OpenCode (opencode.ai), an AI coding agent that knows how to use all Emailr CLI commands.
|
|
3089
2774
|
The agent can help you:
|
|
@@ -3091,10 +2776,10 @@ The agent can help you:
|
|
|
3091
2776
|
- Manage contacts, broadcasts, and segments
|
|
3092
2777
|
- Configure domains and webhooks
|
|
3093
2778
|
|
|
3094
|
-
The agent runs in your terminal with full access to the emailr CLI.`).option("--install","Install OpenCode if not already installed").option("--model <model>","Model to use (e.g., anthropic/claude-sonnet-4)").action(async
|
|
3095
|
-
Install it with one of:`),console.log(" emailr agent --install"),console.log(" npm install -g opencode-ai@latest"),console.log(" brew install anomalyco/tap/opencode"),process.exit(1)));try{
|
|
2779
|
+
The agent runs in your terminal with full access to the emailr CLI.`).option("--install","Install OpenCode if not already installed").option("--model <model>","Model to use (e.g., anthropic/claude-sonnet-4)").action(async t=>{Ut()||(t.install?Pt()||(l("Failed to install OpenCode. Please install manually:"),console.log(" npm install -g opencode-ai@latest"),console.log(" # or"),console.log(" brew install anomalyco/tap/opencode"),process.exit(1)):(l("OpenCode AI agent is not installed."),console.log(`
|
|
2780
|
+
Install it with one of:`),console.log(" emailr agent --install"),console.log(" npm install -g opencode-ai@latest"),console.log(" brew install anomalyco/tap/opencode"),process.exit(1)));try{At(),p("Emailr CLI skill loaded");}catch(n){C(`Could not install skill: ${n instanceof Error?n.message:String(n)}`);}let e=[];t.model&&e.push("--model",t.model),console.log(`
|
|
3096
2781
|
Starting Emailr AI Agent...`),console.log("The agent has the emailr-cli skill loaded."),console.log(`Ask it to help with emails, templates, contacts, or broadcasts.
|
|
3097
|
-
`);let
|
|
2782
|
+
`);let i=spawn("opencode",e,{stdio:"inherit",env:process.env});i.on("error",n=>{l(`Failed to start agent: ${n.message}`),process.exit(1);}),i.on("exit",n=>{process.exit(n??0);});})}function He(){let r=new Command("inbox").description(`Manage inbound emails (inbox)
|
|
3098
2783
|
|
|
3099
2784
|
USAGE
|
|
3100
2785
|
emailr inbox <subcommand> [options]
|
|
@@ -3146,7 +2831,7 @@ EXAMPLES
|
|
|
3146
2831
|
|
|
3147
2832
|
SEE ALSO
|
|
3148
2833
|
emailr send Send individual emails
|
|
3149
|
-
emailr emails View all emails (sent and received)`);return
|
|
2834
|
+
emailr emails View all emails (sent and received)`);return r.command("list").description(`List received emails
|
|
3150
2835
|
|
|
3151
2836
|
USAGE
|
|
3152
2837
|
emailr inbox list [options]
|
|
@@ -3174,7 +2859,7 @@ EXAMPLES
|
|
|
3174
2859
|
|
|
3175
2860
|
OUTPUT FORMATS
|
|
3176
2861
|
--format json Machine-readable JSON with data array and pagination
|
|
3177
|
-
--format table Human-readable table with ID, From, Subject, To, Date (default)`).option("--limit <count>","Number of emails to return","20").option("--page <number>","Page number","1").option("--email <address>","Filter by sender email (partial match)").option("--domain <domain>","Filter by sender domain").option("--inbox-id <inbox_id>","Filter by inbox ID").option("--format <format>","Output format (json|table)","table").action(async
|
|
2862
|
+
--format table Human-readable table with ID, From, Subject, To, Date (default)`).option("--limit <count>","Number of emails to return","20").option("--page <number>","Page number","1").option("--email <address>","Filter by sender email (partial match)").option("--domain <domain>","Filter by sender domain").option("--inbox-id <inbox_id>","Filter by inbox ID").option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=d(),i=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),n={status:"received",page:parseInt(t.page),limit:Math.min(parseInt(t.limit),100),email:t.email,domain:t.domain};t.inboxId&&(n.inbox_id=t.inboxId);let a=await i.emails.list(n);if(t.format==="json")m(a,"json");else {if(!a.data||a.data.length===0){u("No emails in inbox");return}let s=a.data.map(c=>({ID:c.id,From:c.from_email,Subject:Ke(c.subject||"(no subject)",40),To:c.to_email,Date:se(c.created_at),Attachments:c.attachments?.length||0}));m(s,"table"),u(`Page ${a.pagination.page} of ${a.pagination.pages} (${a.pagination.total} total)`);}}catch(e){l(e instanceof Error?e.message:"Failed to list inbox"),process.exit(1);}}),r.command("get <id>").description(`View a received email
|
|
3178
2863
|
|
|
3179
2864
|
USAGE
|
|
3180
2865
|
emailr inbox get <email-id> [options]
|
|
@@ -3195,7 +2880,7 @@ EXAMPLES
|
|
|
3195
2880
|
|
|
3196
2881
|
OUTPUT FORMATS
|
|
3197
2882
|
--format json Full email object with all fields as JSON
|
|
3198
|
-
--format table Key-value table with email metadata and content preview (default)`).option("--content <type>","Content to display: preview | text | html","preview").option("--format <format>","Output format (json|table)","table").action(async(
|
|
2883
|
+
--format table Key-value table with email metadata and content preview (default)`).option("--content <type>","Content to display: preview | text | html","preview").option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let i=d(),a=await new Emailr({apiKey:i.apiKey,baseUrl:i.baseUrl}).emails.get(t);if(e.format==="json")m(a,"json");else {if(m({ID:a.id,From:a.from_email,To:a.to_email,Subject:a.subject||"(no subject)",Date:se(a.created_at),Status:a.status,"Thread ID":a.thread_id||"-","Parent Email":a.parent_email_id||"-",Attachments:a.attachments?.length||0},"table"),console.log(""),e.content==="html")console.log(a.html_content||"(no HTML content)");else if(e.content==="text")console.log(a.text_content||"(no text content)");else {let s=a.text_content||a.html_content?.replace(/<[^>]*>/g,"")||"(no content)";console.log(s);}if(a.attachments&&a.attachments.length>0){console.log(""),u("Attachments:");let s=a.attachments.map(c=>({Filename:c.filename,Type:c.contentType||c.content_type||"-",Size:Dt(c.size||0)}));m(s,"table");}}}catch(i){l(i instanceof Error?i.message:"Failed to get email"),process.exit(1);}}),r.command("thread <id>").description(`View conversation thread for an email
|
|
3199
2884
|
|
|
3200
2885
|
USAGE
|
|
3201
2886
|
emailr inbox thread <email-id> [options]
|
|
@@ -3214,7 +2899,7 @@ EXAMPLES
|
|
|
3214
2899
|
|
|
3215
2900
|
OUTPUT FORMATS
|
|
3216
2901
|
--format json JSON array of all emails in the thread
|
|
3217
|
-
--format table Chronological conversation view with direction indicators (default)`).option("--format <format>","Output format (json|table)","table").action(async(
|
|
2902
|
+
--format table Chronological conversation view with direction indicators (default)`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let i=d(),n=new Emailr({apiKey:i.apiKey,baseUrl:i.baseUrl}),a=await n.emails.get(t),o=a.thread_id||a.id,s=[],c=new Set;if(s.push(a),c.add(a.id),a.thread_id&&a.thread_id!==a.id)try{let f=await n.emails.get(a.thread_id);c.has(f.id)||(s.push(f),c.add(f.id));}catch{}let b=await n.emails.list({limit:100});if(b.data)for(let f of b.data)c.has(f.id)||(f.thread_id===o||f.parent_email_id===a.id||f.id===a.parent_email_id)&&(s.push(f),c.add(f.id));if(s.sort((f,h)=>new Date(f.created_at).getTime()-new Date(h.created_at).getTime()),e.format==="json")m(s,"json");else {s.length<=1&&u("No other emails in this conversation"),u(`Conversation (${s.length} email${s.length!==1?"s":""}):`),console.log("");for(let f of s){let h=f.status==="received"?"\u2190 IN ":"\u2192 OUT",S=f.id===t?" \u25C0 (selected)":"";console.log(`${h} ${se(f.created_at)}${S}`),console.log(` From: ${f.from_email}`),console.log(` To: ${f.to_email}`),console.log(` Subject: ${f.subject||"(no subject)"}`);let _=f.text_content||f.html_content?.replace(/<[^>]*>/g,"")||"";_&&console.log(` ${Ke(_.trim(),120)}`),console.log("");}}await new Promise(f=>process.stdout.write("",()=>f())),process.exit(0);}catch(i){l(i instanceof Error?i.message:"Failed to load thread"),process.exit(1);}}),r.command("reply <id>").description(`Reply to a received email
|
|
3218
2903
|
|
|
3219
2904
|
USAGE
|
|
3220
2905
|
emailr inbox reply <email-id> [options]
|
|
@@ -3250,7 +2935,7 @@ EXAMPLES
|
|
|
3250
2935
|
|
|
3251
2936
|
OUTPUT FORMATS
|
|
3252
2937
|
--format json Machine-readable JSON with message_id and status
|
|
3253
|
-
--format table Human-readable summary with Message ID, To, Subject, Status (default)`).option("--html <content>","HTML content for reply").option("--text <content>","Plain text content for reply").option("--html-file <path>","Read HTML content from file").option("--text-file <path>","Read plain text content from file").option("--from <email>","Override sender address").option("--cc <emails>","CC recipients (comma-separated)").option("--bcc <emails>","BCC recipients (comma-separated)").option("--subject <subject>","Override reply subject").option("--format <format>","Output format (json|table)","table").action(async(
|
|
2938
|
+
--format table Human-readable summary with Message ID, To, Subject, Status (default)`).option("--html <content>","HTML content for reply").option("--text <content>","Plain text content for reply").option("--html-file <path>","Read HTML content from file").option("--text-file <path>","Read plain text content from file").option("--from <email>","Override sender address").option("--cc <emails>","CC recipients (comma-separated)").option("--bcc <emails>","BCC recipients (comma-separated)").option("--subject <subject>","Override reply subject").option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let i=d(),n=new Emailr({apiKey:i.apiKey,baseUrl:i.baseUrl}),a=await n.emails.get(t),o=e.html,s=e.text;if(e.htmlFile)try{o=readFileSync(e.htmlFile,"utf-8");}catch{l(`Failed to read HTML file: ${e.htmlFile}`),process.exit(1);}if(e.textFile)try{s=readFileSync(e.textFile,"utf-8");}catch{l(`Failed to read text file: ${e.textFile}`),process.exit(1);}!o&&!s&&(l("Reply content is required. Use --html, --text, --html-file, or --text-file"),process.exit(1));let c=e.subject||(a.subject?.startsWith("Re:")?a.subject:`Re: ${a.subject||""}`),b={to:a.from_email,from:e.from||a.to_email,subject:c,html:o||void 0,text:s||o?.replace(/<[^>]*>/g,"")||void 0,replyTo:{in_reply_to:a.message_id||a.ses_message_id,thread_id:a.thread_id||a.id,parent_email_id:a.id}};if(e.cc){let h=e.cc.split(",").map(S=>S.trim());b.cc=h.length===1?h[0]:h;}if(e.bcc){let h=e.bcc.split(",").map(S=>S.trim());b.bcc=h.length===1?h[0]:h;}let g=await n.emails.send(b);e.format==="json"?m(g,"json"):(p("Reply sent successfully!"),m({"Message ID":g.message_id,To:a.from_email,Subject:c,Status:g.status},"table")),await new Promise(h=>process.stdout.write("",()=>h())),process.exit(0);}catch(i){l(i instanceof Error?i.message:"Failed to send reply"),process.exit(1);}}),r.command("forward <id>").description(`Forward a received email
|
|
3254
2939
|
|
|
3255
2940
|
USAGE
|
|
3256
2941
|
emailr inbox forward <email-id> --to <recipients> [options]
|
|
@@ -3276,7 +2961,7 @@ EXAMPLES
|
|
|
3276
2961
|
|
|
3277
2962
|
OUTPUT FORMATS
|
|
3278
2963
|
--format json Machine-readable JSON with message_id and status
|
|
3279
|
-
--format table Human-readable summary with Message ID, To, Recipients, Status (default)`).requiredOption("--to <emails>","Recipient email addresses (comma-separated)").option("--message <text>","Message to include with forwarded email").option("--format <format>","Output format (json|table)","table").action(async(
|
|
2964
|
+
--format table Human-readable summary with Message ID, To, Recipients, Status (default)`).requiredOption("--to <emails>","Recipient email addresses (comma-separated)").option("--message <text>","Message to include with forwarded email").option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let i=d(),n=new Emailr({apiKey:i.apiKey,baseUrl:i.baseUrl}),a=e.to.split(",").map(c=>c.trim()).filter(Boolean),o=await n.emails.forward({email_id:t,to:a.length===1?a[0]:a,message:e.message});e.format==="json"?m(o,"json"):(p("Email forwarded successfully!"),m({"Message ID":o.message_id,To:a.join(", "),Recipients:o.recipients,Status:o.status},"table")),await new Promise(c=>process.stdout.write("",()=>c())),process.exit(0);}catch(i){l(i instanceof Error?i.message:"Failed to forward email"),process.exit(1);}}),r}function Ke(r,t){return r.length<=t?r:r.slice(0,t-1)+"\u2026"}function se(r){return new Date(r).toLocaleString()}function Dt(r){return r<1024?r+" B":r<1024*1024?(r/1024).toFixed(1)+" KB":(r/(1024*1024)).toFixed(1)+" MB"}function qe(){let r=new Command("inboxes").description(`Manage inboxes
|
|
3280
2965
|
|
|
3281
2966
|
USAGE
|
|
3282
2967
|
emailr inboxes <subcommand> [options]
|
|
@@ -3306,7 +2991,7 @@ EXAMPLES
|
|
|
3306
2991
|
emailr inboxes update inb_abc123 --name "Customer Support"
|
|
3307
2992
|
|
|
3308
2993
|
# Delete an inbox
|
|
3309
|
-
emailr inboxes delete inb_abc123`);return
|
|
2994
|
+
emailr inboxes delete inb_abc123`);return r.command("create").description(`Create a new inbox
|
|
3310
2995
|
|
|
3311
2996
|
USAGE
|
|
3312
2997
|
emailr inboxes create --name <name> --username <username> --domain <domain> [options]
|
|
@@ -3329,7 +3014,7 @@ EXAMPLES
|
|
|
3329
3014
|
emailr inboxes create --name "Support" --username support --domain example.com --reply-to replies@example.com
|
|
3330
3015
|
|
|
3331
3016
|
# Create and get JSON output
|
|
3332
|
-
emailr inboxes create --name "Sales" --username sales --domain example.com --format json`).requiredOption("--name <name>","Inbox display name").requiredOption("--username <username>","Username for the email address").requiredOption("--domain <domain>","Domain for the email address").option("--reply-to <email>","Custom reply-to address (defaults to username@mail.domain)").option("--format <format>","Output format: json | table","table").action(async
|
|
3017
|
+
emailr inboxes create --name "Sales" --username sales --domain example.com --format json`).requiredOption("--name <name>","Inbox display name").requiredOption("--username <username>","Username for the email address").requiredOption("--domain <domain>","Domain for the email address").option("--reply-to <email>","Custom reply-to address (defaults to username@mail.domain)").option("--format <format>","Output format: json | table","table").action(async t=>{try{let e=d(),i=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),n={name:t.name,username:t.username,domain:t.domain};t.replyTo&&(n.reply_to=t.replyTo);let a=await i.inboxes.create(n);t.format==="json"?m(a,"json"):(p(`Inbox created: ${a.id}`),m({ID:a.id,Name:a.name,"From Address":a.from_address,"Reply To":a.reply_to,"Inbound Address":a.inbound_address,Created:a.created_at},"table"));}catch(e){l(e instanceof Error?e.message:"Failed to create inbox"),process.exit(1);}}),r.command("list").description(`List all inboxes
|
|
3333
3018
|
|
|
3334
3019
|
USAGE
|
|
3335
3020
|
emailr inboxes list [options]
|
|
@@ -3345,8 +3030,8 @@ EXAMPLES
|
|
|
3345
3030
|
emailr inboxes list
|
|
3346
3031
|
|
|
3347
3032
|
# Get JSON output
|
|
3348
|
-
emailr inboxes list --format json`).option("--format <format>","Output format: json | table","table").action(async
|
|
3349
|
-
Total: ${n.length}`);}}catch(e){l(e instanceof Error?e.message:"Failed to list inboxes"),process.exit(1);}}),
|
|
3033
|
+
emailr inboxes list --format json`).option("--format <format>","Output format: json | table","table").action(async t=>{try{let e=d(),n=await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).inboxes.list();if(t.format==="json")m(n,"json");else {if(n.length===0){console.log("No inboxes found.");return}let a=n.map(o=>({ID:o.id,Name:o.name,"From Address":o.from_address,"Reply To":o.reply_to,"Inbound Address":o.inbound_address,Created:new Date(o.created_at).toLocaleDateString()}));m(a,"table"),console.log(`
|
|
3034
|
+
Total: ${n.length}`);}}catch(e){l(e instanceof Error?e.message:"Failed to list inboxes"),process.exit(1);}}),r.command("get <inbox_id>").description(`Get an inbox by ID
|
|
3350
3035
|
|
|
3351
3036
|
USAGE
|
|
3352
3037
|
emailr inboxes get <inbox_id> [options]
|
|
@@ -3365,7 +3050,7 @@ EXAMPLES
|
|
|
3365
3050
|
emailr inboxes get inb_abc123
|
|
3366
3051
|
|
|
3367
3052
|
# Get JSON output
|
|
3368
|
-
emailr inboxes get inb_abc123 --format json`).option("--format <format>","Output format: json | table","table").action(async(
|
|
3053
|
+
emailr inboxes get inb_abc123 --format json`).option("--format <format>","Output format: json | table","table").action(async(t,e)=>{try{let i=d(),a=await new Emailr({apiKey:i.apiKey,baseUrl:i.baseUrl}).inboxes.get(t);e.format==="json"?m(a,"json"):m({ID:a.id,Name:a.name,Username:a.username,Domain:a.domain,"From Address":a.from_address,"Reply To":a.reply_to,"Inbound Address":a.inbound_address,Created:a.created_at,Updated:a.updated_at},"table");}catch(i){l(i instanceof Error?i.message:"Failed to get inbox"),process.exit(1);}}),r.command("update <inbox_id>").description(`Update an inbox
|
|
3369
3054
|
|
|
3370
3055
|
USAGE
|
|
3371
3056
|
emailr inboxes update <inbox_id> --name <name> [options]
|
|
@@ -3392,7 +3077,7 @@ EXAMPLES
|
|
|
3392
3077
|
emailr inboxes update inb_abc123 --reply-to none
|
|
3393
3078
|
|
|
3394
3079
|
# Get JSON output
|
|
3395
|
-
emailr inboxes update inb_abc123 --name "New Name" --format json`).option("--name <name>","New inbox display name").option("--reply-to <email>",'New reply-to address (use "none" to reset to default)').option("--format <format>","Output format: json | table","table").action(async(
|
|
3080
|
+
emailr inboxes update inb_abc123 --name "New Name" --format json`).option("--name <name>","New inbox display name").option("--reply-to <email>",'New reply-to address (use "none" to reset to default)').option("--format <format>","Output format: json | table","table").action(async(t,e)=>{try{!e.name&&!e.replyTo&&(l("No update fields specified. Use --name or --reply-to to update the inbox."),process.exit(1));let i=d(),n=new Emailr({apiKey:i.apiKey,baseUrl:i.baseUrl}),a={};e.name&&(a.name=e.name),e.replyTo&&(a.reply_to=e.replyTo==="none"?null:e.replyTo);let o=await n.inboxes.update(t,a);e.format==="json"?m(o,"json"):(p(`Inbox updated: ${o.id}`),m({ID:o.id,Name:o.name,"From Address":o.from_address,"Reply To":o.reply_to,"Inbound Address":o.inbound_address,Updated:o.updated_at},"table"));}catch(i){l(i instanceof Error?i.message:"Failed to update inbox"),process.exit(1);}}),r.command("delete <inbox_id>").description(`Delete an inbox
|
|
3396
3081
|
|
|
3397
3082
|
USAGE
|
|
3398
3083
|
emailr inboxes delete <inbox_id> [options]
|
|
@@ -3415,7 +3100,7 @@ EXAMPLES
|
|
|
3415
3100
|
emailr inboxes delete inb_abc123 --format json
|
|
3416
3101
|
|
|
3417
3102
|
WARNING
|
|
3418
|
-
This action is permanent and cannot be undone.`).option("--format <format>","Output format: json | table","table").action(async(
|
|
3103
|
+
This action is permanent and cannot be undone.`).option("--format <format>","Output format: json | table","table").action(async(t,e)=>{try{let i=d(),a=await new Emailr({apiKey:i.apiKey,baseUrl:i.baseUrl}).inboxes.delete(t);e.format==="json"?m(a,"json"):p(`Inbox deleted: ${t}`);}catch(i){l(i instanceof Error?i.message:"Failed to delete inbox"),process.exit(1);}}),r}function Je(){let r=new Command("threads").description(`Manage email threads, labels, replies, and drafts
|
|
3419
3104
|
|
|
3420
3105
|
USAGE
|
|
3421
3106
|
emailr threads <subcommand> [options]
|
|
@@ -3447,9 +3132,9 @@ EXAMPLES
|
|
|
3447
3132
|
emailr threads list
|
|
3448
3133
|
|
|
3449
3134
|
# Star a thread
|
|
3450
|
-
emailr threads label <thread-id> --add starred`);
|
|
3135
|
+
emailr threads label <thread-id> --add starred`);r.command("list").description("List threads filtered by label").option("--label <label>","Filter by label (inbox, sent, starred, spam, trash, archived, all)","inbox").option("--limit <count>","Number of threads to return","20").option("--page <number>","Page number","1").option("--search <query>","Search by subject or sender").option("--inbox-id <id>","Filter by inbox ID").option("--format <format>","Output format (json|table)","table").action(async e=>{try{let i=d(),a=await new Emailr({apiKey:i.apiKey,baseUrl:i.baseUrl}).threads.list({label:e.label,page:parseInt(e.page),limit:Math.min(parseInt(e.limit),100),search:e.search,inbox_id:e.inboxId});if(e.format==="json")m(a,"json");else {if(!a.data||a.data.length===0){u(`No threads in ${e.label}`);return}let s=a.data.map(c=>({"Thread ID":c.thread_id.slice(0,8)+"\u2026",Subject:le(c.subject||"(no subject)",40),From:c.from_email,Messages:c.message_count,Labels:(c.labels||[]).join(", "),Updated:$e(c.updated_at)}));m(s,"table"),u(`Page ${a.pagination.page} of ${a.pagination.pages} (${a.pagination.total} total)`);}}catch(i){l(i instanceof Error?i.message:"Failed to list threads"),process.exit(1);}}),r.command("get <id>").description("View a thread with all messages").option("--format <format>","Output format (json|table)","table").action(async(e,i)=>{try{let n=d(),o=await new Emailr({apiKey:n.apiKey,baseUrl:n.baseUrl}).threads.get(e);if(i.format==="json")m(o,"json");else {u(`Thread: ${o.subject||"(no subject)"}`),u(`Labels: ${o.labels.join(", ")||"none"}`),u(`Messages: ${o.messages.length}`),console.log("");for(let c of o.messages){let b=c.status==="received"?"\u2190 IN ":"\u2192 OUT";console.log(`${b} ${$e(c.created_at)}`),console.log(` From: ${c.from_email}`),console.log(` To: ${c.to_email}`),c.cc_emails?.length&&console.log(` Cc: ${c.cc_emails.join(", ")}`),console.log(` Labels: ${c.labels.join(", ")||"none"}`);let g=c.text_content||c.html_content?.replace(/<[^>]*>/g,"")||"";g&&console.log(` ${le(g.trim(),120)}`),console.log("");}}await new Promise(c=>process.stdout.write("",()=>c())),process.exit(0);}catch(n){l(n instanceof Error?n.message:"Failed to get thread"),process.exit(1);}}),r.command("label <id>").description("Add or remove labels from a thread").option("--add <labels>","Labels to add (comma-separated)").option("--remove <labels>","Labels to remove (comma-separated)").option("--format <format>","Output format (json|table)","table").action(async(e,i)=>{try{!i.add&&!i.remove&&(l("Specify --add and/or --remove labels"),process.exit(1));let n=d(),a=new Emailr({apiKey:n.apiKey,baseUrl:n.baseUrl}),o=i.add?i.add.split(",").map(g=>g.trim()):void 0,s=i.remove?i.remove.split(",").map(g=>g.trim()):void 0,c=await a.threads.updateLabels(e,{add:o,remove:s});i.format==="json"?m(c,"json"):(p(`Updated ${c.updated} email(s) in thread`),o&&u(`Added: ${o.join(", ")}`),s&&u(`Removed: ${s.join(", ")}`)),await new Promise(g=>process.stdout.write("",()=>g())),process.exit(0);}catch(n){l(n instanceof Error?n.message:"Failed to update labels"),process.exit(1);}}),r.command("reply <id>").description("Reply to a thread (from/to/subject auto-resolved from inbox)").option("--html <content>","HTML content for the reply").option("--text <content>","Plain text content for the reply").option("--to <email>","Override recipient (auto-resolved if omitted)").option("--cc <emails>","CC recipients (comma-separated)").option("--bcc <emails>","BCC recipients (comma-separated)").option("--from <email>","Override sender (auto-resolved from inbox if omitted)").option("--from-name <name>","Override sender name (auto-resolved from inbox if omitted)").option("--reply-to <email>","Override Reply-To (auto-resolved from inbox if omitted)").option("--format <format>","Output format (json|table)","table").action(async(e,i)=>{try{!i.html&&!i.text&&(l("Provide --html or --text for the reply body"),process.exit(1));let n=d(),a=new Emailr({apiKey:n.apiKey,baseUrl:n.baseUrl}),o={};i.html&&(o.html=i.html),i.text&&(o.text=i.text),i.to&&(o.to=i.to),i.cc&&(o.cc=i.cc.split(",").map(b=>b.trim())),i.bcc&&(o.bcc=i.bcc.split(",").map(b=>b.trim())),i.from&&(o.from=i.from),i.fromName&&(o.from_name=i.fromName),i.replyTo&&(o.reply_to_email=i.replyTo);let s=await a.threads.reply(e,o);i.format==="json"?m(s,"json"):(p(`Reply sent to ${s.recipients} recipient(s)`),u(`Message ID: ${s.message_id}`)),await new Promise(b=>process.stdout.write("",()=>b())),process.exit(0);}catch(n){l(n instanceof Error?n.message:"Failed to send reply"),process.exit(1);}});let t=r.command("draft").description("Manage draft replies for threads");return t.command("save <id>").description("Save a draft reply for a thread").option("--html <content>","HTML content").option("--text <content>","Plain text content").option("--to <email>","Recipient").option("--cc <emails>","CC recipients").option("--bcc <emails>","BCC recipients").option("--from <email>","Sender").option("--reply-to <email>","Reply-To address").option("--format <format>","Output format (json|table)","table").action(async(e,i)=>{try{let n=d(),a=new Emailr({apiKey:n.apiKey,baseUrl:n.baseUrl}),o={};i.html&&(o.html=i.html),i.text&&(o.text=i.text),i.to&&(o.to=i.to),i.cc&&(o.cc=i.cc),i.bcc&&(o.bcc=i.bcc),i.from&&(o.from=i.from),i.replyTo&&(o.reply_to_email=i.replyTo);let s=await a.threads.saveDraft(e,o);i.format==="json"?m(s,"json"):(p(`Draft saved for thread ${e}`),u(`Draft ID: ${s.id}`)),await new Promise(b=>process.stdout.write("",()=>b())),process.exit(0);}catch(n){l(n instanceof Error?n.message:"Failed to save draft"),process.exit(1);}}),t.command("get <id>").description("Get the saved draft for a thread").option("--format <format>","Output format (json|table)","table").action(async(e,i)=>{try{let n=d(),o=await new Emailr({apiKey:n.apiKey,baseUrl:n.baseUrl}).threads.getDraft(e);i.format==="json"?m(o,"json"):(u(`Draft for thread: ${e}`),u(`To: ${o.to_email||"(auto)"}`),u(`From: ${o.from_email||"(auto)"}`),u(`Subject: ${o.subject||"(auto)"}`),o.html_content&&console.log(`
|
|
3451
3136
|
Content:
|
|
3452
|
-
${le(
|
|
3137
|
+
${le(o.html_content.replace(/<[^>]*>/g,""),200)}`)),await new Promise(c=>process.stdout.write("",()=>c())),process.exit(0);}catch(n){l(n instanceof Error?n.message:"No draft found"),process.exit(1);}}),t.command("delete <id>").description("Delete the draft for a thread").option("--format <format>","Output format (json|table)","table").action(async(e,i)=>{try{let n=d();await new Emailr({apiKey:n.apiKey,baseUrl:n.baseUrl}).threads.deleteDraft(e),i.format==="json"?m({success:!0},"json"):p(`Draft deleted for thread ${e}`),await new Promise(s=>process.stdout.write("",()=>s())),process.exit(0);}catch(n){l(n instanceof Error?n.message:"Failed to delete draft"),process.exit(1);}}),r}function le(r,t){return r.length<=t?r:r.slice(0,t-1)+"\u2026"}function $e(r){return new Date(r).toLocaleString()}var Ft=`# Emailr CLI \u2014 Agent Skill Guide
|
|
3453
3138
|
|
|
3454
3139
|
## Setup
|
|
3455
3140
|
|
|
@@ -3574,14 +3259,13 @@ emailr broadcasts delete <id>
|
|
|
3574
3259
|
### webhooks \u2014 Configure event notifications
|
|
3575
3260
|
\`\`\`bash
|
|
3576
3261
|
emailr webhooks list
|
|
3577
|
-
emailr webhooks create --name "Tracker" --url "https://x.com/hook" --
|
|
3578
|
-
emailr webhooks
|
|
3579
|
-
emailr webhooks
|
|
3580
|
-
emailr webhooks
|
|
3581
|
-
emailr webhooks disable <id>
|
|
3262
|
+
emailr webhooks create --name "Tracker" --url "https://x.com/hook" --type transactional
|
|
3263
|
+
emailr webhooks create --name "Inbound" --url "https://x.com/hook" --type receiving --inbox-ids "id1,id2"
|
|
3264
|
+
emailr webhooks toggle <id> # enable/disable
|
|
3265
|
+
emailr webhooks deliveries <id> # view recent deliveries
|
|
3582
3266
|
emailr webhooks delete <id>
|
|
3583
3267
|
\`\`\`
|
|
3584
|
-
|
|
3268
|
+
Types: transactional (email events), domain (domain events), receiving (inbound email)
|
|
3585
3269
|
|
|
3586
3270
|
### domains \u2014 Manage sending domains
|
|
3587
3271
|
\`\`\`bash
|
|
@@ -3677,7 +3361,7 @@ EXAMPLES
|
|
|
3677
3361
|
emailr skill > emailr-skill.md
|
|
3678
3362
|
|
|
3679
3363
|
# Feed to an AI agent context
|
|
3680
|
-
emailr skill | pbcopy`).action(()=>{process.stdout.write(Ft);})}var
|
|
3364
|
+
emailr skill | pbcopy`).action(()=>{process.stdout.write(Ft);})}var w=new Command;w.name("emailr").description(`Emailr CLI - Send emails and manage your email infrastructure
|
|
3681
3365
|
|
|
3682
3366
|
USAGE
|
|
3683
3367
|
emailr <command> [subcommand] [options]
|
|
@@ -3771,7 +3455,7 @@ EXAMPLES
|
|
|
3771
3455
|
|
|
3772
3456
|
# Configure a webhook for delivery events
|
|
3773
3457
|
emailr webhooks create --name "Deliveries" --url "https://..." \\
|
|
3774
|
-
--
|
|
3458
|
+
--type transactional
|
|
3775
3459
|
|
|
3776
3460
|
# Get JSON output for scripting
|
|
3777
3461
|
emailr contacts list --format json | jq '.[].email'
|
|
@@ -3792,4 +3476,4 @@ AGENTIC WORKFLOW
|
|
|
3792
3476
|
|
|
3793
3477
|
MORE INFORMATION
|
|
3794
3478
|
Run 'emailr <command> --help' for detailed help on any command.
|
|
3795
|
-
Run 'emailr <command> <subcommand> --help' for subcommand details.`).version("1.12.
|
|
3479
|
+
Run 'emailr <command> <subcommand> --help' for subcommand details.`).version("1.12.1");w.addCommand(fe());w.addCommand(He());w.addCommand(qe());w.addCommand(Je());w.addCommand(be());w.addCommand(Ie());w.addCommand(Ce());w.addCommand(Ue());w.addCommand(Pe());w.addCommand(Ae());w.addCommand(Ne());w.addCommand(Me());w.addCommand(Fe());w.addCommand(Be());w.parse();
|