emailr-cli 1.7.7 → 1.8.0
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 +286 -87
- 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 O,{readFileSync}from'fs';import V from'os';import _ from'path';import le from'cli-table3';import T from'chalk';import Xe from'http';import {URL}from'url';import ft from'crypto';import {spawn,execSync,exec}from'child_process';var Ge=[_.join(V.homedir(),".emailrrc"),_.join(V.homedir(),".config","emailr","config.json")];function c(){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 i of Ge)if(O.existsSync(i))try{let t=O.readFileSync(i,"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
|
|
11
|
-
`);}function
|
|
10
|
+
Or run: emailr config set api-key <your-api-key>`)}function N(){let i=_.join(V.homedir(),".config","emailr");return _.join(i,"config.json")}function G(i){let t=N(),e=_.dirname(t);O.existsSync(e)||O.mkdirSync(e,{recursive:true});let o={};if(O.existsSync(t))try{o=JSON.parse(O.readFileSync(t,"utf-8"));}catch{}let s={...o,...i};O.writeFileSync(t,JSON.stringify(s,null,2)+`
|
|
11
|
+
`);}function se(i){try{return c()[i]?.toString()}catch{return}}function m(i,t="table"){t==="json"?console.log(JSON.stringify(i,null,2)):Ke(i);}function Ke(i){Array.isArray(i)?He(i):typeof i=="object"&&i!==null?qe(i):console.log(i);}function He(i){if(i.length===0){console.log(T.gray("No results"));return}let t=i[0];if(typeof t!="object"||t===null){i.forEach(s=>console.log(s));return}let e=Object.keys(t),o=new le({head:e.map(s=>T.cyan(s)),style:{head:[],border:[]}});for(let s of i){let a=e.map(r=>{let n=s[r];return me(n)});o.push(a);}console.log(o.toString());}function qe(i){let t=new le({style:{head:[],border:[]}});for(let[e,o]of Object.entries(i))t.push([T.cyan(e),me(o)]);console.log(t.toString());}function me(i){return i==null?T.gray("-"):typeof i=="boolean"?i?T.green("\u2713"):T.red("\u2717"):typeof i=="object"?JSON.stringify(i):String(i)}function p(i){console.log(T.green("\u2713"),i);}function l(i){console.error(T.red("\u2717"),i);}function I(i){console.warn(T.yellow("\u26A0"),i);}function f(i){console.log(T.blue("\u2139"),i);}function de(){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 t=>{try{let e=
|
|
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=c(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),s=t.to.split(",").map(n=>n.trim()),a={to:s.length===1?s[0]:s};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 n=t.cc.split(",").map(d=>d.trim());a.cc=n.length===1?n[0]:n;}if(t.bcc){let n=t.bcc.split(",").map(d=>d.trim());a.bcc=n.length===1?n[0]:n;}t.replyTo&&(a.reply_to_email=t.replyTo),t.schedule&&(a.scheduled_at=t.schedule);let r=await o.emails.send(a);t.format==="json"?m(r,"json"):(p("Email sent successfully!"),m({"Message ID":r.message_id,Recipients:r.recipients,Status:r.status,...r.scheduled_at&&{"Scheduled At":r.scheduled_at}},"table"));}catch(e){l(e instanceof Error?e.message:"Failed to send email"),process.exit(1);}})}function pe(){let i=new Command("contacts").description(`Manage contacts
|
|
160
160
|
|
|
161
161
|
USAGE
|
|
162
162
|
emailr contacts <subcommand> [options]
|
|
@@ -286,7 +286,7 @@ 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 t=>{try{let e=
|
|
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=c(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),s={limit:parseInt(t.limit,10),offset:parseInt(t.offset,10)};if(t.subscribed&&(s.subscribed=!0),t.unsubscribed&&(s.subscribed=!1),t.search&&(s.search=t.search),t.tags){let r=t.tags.split(",").map(n=>n.trim().toLowerCase()).filter(Boolean);r.length>0&&(s.tags=r.join(","));}let a=await o.contacts.list(s);if(t.format==="json")m(a,"json");else {let r=a.contacts.map(n=>({ID:n.id,Email:n.email,Name:[n.first_name,n.last_name].filter(Boolean).join(" ")||"-",Subscribed:n.subscribed,Tags:n.tags?.join(", ")||"-",Created:n.created_at}));m(r,"table"),console.log(`
|
|
290
290
|
Total: ${a.total}`);}}catch(e){l(e instanceof Error?e.message:"Failed to list contacts"),process.exit(1);}}),i.command("get <contact_id>").description(`Get a contact by ID
|
|
291
291
|
|
|
292
292
|
USAGE
|
|
@@ -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(t,e)=>{try{let o=
|
|
317
|
+
emailr contacts get con_abc123 --format json | jq '.metadata'`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=c(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).contacts.get(t);m(a,e.format);}catch(o){l(o instanceof Error?o.message:"Failed to get contact"),process.exit(1);}}),i.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 t=>{try{let e=
|
|
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=c(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),s={email:t.email};if(t.firstName&&(s.first_name=t.firstName),t.lastName&&(s.last_name=t.lastName),t.subscribed!==void 0&&(s.subscribed=t.subscribed),t.metadata)try{s.metadata=JSON.parse(t.metadata);}catch{l("Invalid JSON for --metadata"),process.exit(1);}t.tags&&(s.tags=t.tags.split(",").map(r=>r.trim().toLowerCase()).filter(Boolean));let a=await o.contacts.create(s);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);}}),i.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(t,e)=>{try{let o=
|
|
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 o=c(),s=new Emailr({apiKey:o.apiKey,baseUrl:o.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(n=>n.trim().toLowerCase()).filter(Boolean));let r=await s.contacts.update(t,a);e.format==="json"?m(r,"json"):(p(`Contact updated: ${r.id}`),m(r,"table"));}catch(o){l(o instanceof Error?o.message:"Failed to update contact"),process.exit(1);}}),i.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 t=>{try{let e=
|
|
426
|
+
This action is permanent and cannot be undone.`).action(async t=>{try{let e=c();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);}}),i}function fe(){return _.join(V.homedir(),".config","emailr","templates")}function We(){let i=fe();O.existsSync(i)||O.mkdirSync(i,{recursive:true});}function W(i){return _.join(fe(),`${i}.html`)}function X(i,t){We();let e=W(i);O.writeFileSync(e,t,"utf-8");}function be(i){let t=W(i);return O.existsSync(t)?O.readFileSync(t,"utf-8"):null}function he(i){let t=W(i);return O.existsSync(t)}var v=null,P=null,H=false;function we(i){return i.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function ze(i){return i===null||i.trim()===""}function Ye(i){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">${
|
|
492
|
+
<div class="template-id">${we(i)}</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
|
|
499
|
+
</html>`}function ge(i){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">${
|
|
551
|
+
<div class="template-id">${we(i)}</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
|
|
555
|
+
</html>`}function Ze(i){let t=i.match(/^\/preview\/([^/]+)$/);return t?t[1]:null}function Qe(){return (i,t)=>{if(i.method!=="GET"){t.writeHead(405,{"Content-Type":"text/plain"}),t.end("Method Not Allowed");return}let e=i.url||"/",o=Ze(e);if(!o){t.writeHead(404,{"Content-Type":"text/plain"}),t.end("Not Found");return}if(!he(o)){t.writeHead(404,{"Content-Type":"text/html; charset=utf-8"}),t.end(ge(o));return}let s=be(o);if(s===null){t.writeHead(404,{"Content-Type":"text/html; charset=utf-8"}),t.end(ge(o));return}if(ze(s)){t.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),t.end(Ye(o));return}t.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),t.end(s);}}var ye={async start(){return H&&P!==null?P:new Promise((i,t)=>{v=Xe.createServer(Qe()),v.listen(0,"127.0.0.1",()=>{let e=v.address();e&&typeof e=="object"?(P=e.port,H=true,v.unref(),i(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(i=>{v.close(()=>{v=null,P=null,H=false,i();});})}};function Se(){return ye}async function z(i){try{return `http://127.0.0.1:${await ye.start()}/preview/${i}`}catch{return null}}function ve(){v&&v.ref();}var k=null,Y=null,$=null,M=[],Oe=`
|
|
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
|
|
569
|
+
`;function at(i){return i.includes("</body>")?i.replace("</body>",`${Oe}</body>`):i+Oe}function ot(){M.forEach(i=>{try{i.write(`data: reload
|
|
570
570
|
|
|
571
|
-
`);}catch{}});}async function
|
|
571
|
+
`);}catch{}});}async function Z(i,t){let e=_.resolve(i);return new Promise((o,s)=>{k=Xe.createServer((a,r)=>{if(a.url==="/__live-reload"){r.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive","Access-Control-Allow-Origin":"*"}),r.write(`data: connected
|
|
572
572
|
|
|
573
|
-
`),
|
|
573
|
+
`),M.push(r),a.on("close",()=>{M=M.filter(n=>n!==r);});return}if(a.method==="GET"){try{let n=O.readFileSync(e,"utf-8"),d=at(n);r.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),r.end(d);}catch(n){r.writeHead(500,{"Content-Type":"text/plain"}),r.end(`Error reading file: ${n instanceof Error?n.message:String(n)}`);}return}r.writeHead(405,{"Content-Type":"text/plain"}),r.end("Method Not Allowed");}),k.listen(0,"127.0.0.1",()=>{let a=k.address();if(a&&typeof a=="object"){Y=a.port;let r=null;$=O.watch(e,n=>{n==="change"&&(r&&clearTimeout(r),r=setTimeout(()=>{ot(),t?.();},100));}),o(Y);}else s(new Error("Failed to get server address"));}),k.on("error",a=>{s(new Error(`Failed to start server: ${a.message}`));});})}async function Q(){if($&&($.close(),$=null),M.forEach(i=>{try{i.end();}catch{}}),M=[],k)return new Promise(i=>{k.close(()=>{k=null,Y=null,i();});})}async function Ee(i){try{let t=i.html_content??"";X(i.id,t);}catch(t){return I(`Could not save template for preview: ${t instanceof Error?t.message:String(t)}`),null}try{let t=await z(i.id);return t===null?(I("Could not start preview server"),null):t}catch(t){return I(`Could not generate preview URL: ${t instanceof Error?t.message:String(t)}`),null}}function _e(){let i=new Command("templates").description(`Manage email templates
|
|
574
574
|
|
|
575
575
|
USAGE
|
|
576
576
|
emailr templates <subcommand> [options]
|
|
@@ -671,7 +671,7 @@ 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 t=>{try{let e=
|
|
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=c(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),s={limit:parseInt(t.limit,10),page:parseInt(t.page,10)};if(t.tags){let r=t.tags.split(",").map(n=>n.trim().toLowerCase()).filter(Boolean);r.length>0&&(s.tags=r.join(","));}let a=await o.templates.list(s);if(t.format==="json")m(a,"json");else {let r=a.map(n=>({ID:n.id,Name:n.name,Subject:n.subject,Variables:n.variables?.join(", ")||"-",Tags:n.tags?.join(", ")||"-",Created:n.created_at}));m(r,"table"),console.log(`
|
|
675
675
|
Total: ${a.length}`);}}catch(e){l(e instanceof Error?e.message:"Failed to list templates"),process.exit(1);}}),i.command("get <template_id>").description(`Get a template by ID
|
|
676
676
|
|
|
677
677
|
USAGE
|
|
@@ -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(t,e)=>{try{let o=
|
|
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 o=c(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).templates.get(t),r=await Ee({id:a.id,html_content:a.html_content??void 0}),n=a.preview_html?`${o.baseUrl}/preview/${a.id}`:null;if(e.format==="json")m({...a,preview_url:n??r},"json");else {let d={ID:a.id,Name:a.name,Subject:a.subject,Variables:a.variables?.join(", ")||"-",Created:a.created_at};n?d["Preview URL"]=n:r&&(d["Local Preview"]=r),m(d,"table");}}catch(o){l(o instanceof Error?o.message:"Failed to get template"),process.exit(1);}}),i.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(t,e)=>{try{let o=
|
|
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 o=c(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.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 r=_.resolve(e.output);O.writeFileSync(r,a,"utf-8"),p(`HTML saved to: ${r}`);}else console.log(a);}catch(o){l(o instanceof Error?o.message:"Failed to fetch template"),process.exit(1);}}),i.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>
|
|
@@ -779,7 +779,7 @@ AGENTIC WORKFLOW
|
|
|
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
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 o=
|
|
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 o=c(),s=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),a;if(e.htmlFile){let d=_.resolve(e.htmlFile);try{a=O.readFileSync(d,"utf-8");}catch{l(`Failed to read file: ${d}`),process.exit(1);}}else a=e.html;let r=await s.templates.pushPreview(t,a),n="updated";e.format==="json"?m({template_id:t,preview_url:r.preview_url,status:n},"json"):(p("Preview uploaded successfully"),m({"Template ID":t,"Preview URL":r.preview_url,Status:n},"table"),console.log(`
|
|
783
783
|
Share this URL with your AI agent for feedback.`));}catch(o){l(o instanceof Error?o.message:"Failed to push preview"),process.exit(1);}}),i.command("create").description(`Create a new email template
|
|
784
784
|
|
|
785
785
|
USAGE
|
|
@@ -827,7 +827,7 @@ EXAMPLES
|
|
|
827
827
|
|
|
828
828
|
TIP
|
|
829
829
|
For live preview while building, use "emailr templates draft" first.
|
|
830
|
-
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("--tags <tags>","Comma-separated tags").option("--format <format>","Output format: json | table","table").action(async t=>{try{let e=
|
|
830
|
+
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("--tags <tags>","Comma-separated tags").option("--format <format>","Output format: json | table","table").action(async t=>{try{let e=c(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),s={name:t.name,subject:t.subject};if(t.htmlFile){let n=await import('fs');s.html_content=n.readFileSync(t.htmlFile,"utf-8");}else t.html&&(s.html_content=t.html);if(t.textFile){let n=await import('fs');s.text_content=n.readFileSync(t.textFile,"utf-8");}else t.text&&(s.text_content=t.text);t.from&&(s.from_email=t.from),t.fromName&&(s.from_name=t.fromName),t.replyTo&&(s.reply_to=t.replyTo),t.previewText&&(s.preview_text=t.previewText),t.tags&&(s.tags=t.tags.split(",").map(n=>n.trim().toLowerCase()).filter(Boolean));let a=await o.templates.create(s),r=await Ee({id:a.id,html_content:a.html_content??void 0});if(t.format==="json")m({...a,preview_url:r},"json");else {p(`Template created: ${a.id}`);let n={ID:a.id,Name:a.name,Subject:a.subject,Variables:a.variables?.join(", ")||"-",Tags:a.tags?.join(", ")||"-"};r&&(n["Preview URL"]=r),m(n,"table"),r&&console.log(`
|
|
831
831
|
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);}}),i.command("update <template_id>").description(`Update an existing email template
|
|
832
832
|
|
|
833
833
|
USAGE
|
|
@@ -882,7 +882,7 @@ AGENTIC WORKFLOW
|
|
|
882
882
|
2. Edit locally or with AI assistance
|
|
883
883
|
3. Push preview: emailr templates push-preview <id> --html-file template.html
|
|
884
884
|
4. Share URL with AI agent, iterate on feedback
|
|
885
|
-
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("--tags <tags>","Comma-separated tags").option("--format <format>","Output format: json | table","table").action(async(t,e)=>{try{let o=
|
|
885
|
+
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("--tags <tags>","Comma-separated tags").option("--format <format>","Output format: json | table","table").action(async(t,e)=>{try{let o=c(),s=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),a={};if(e.name&&(a.name=e.name),e.subject&&(a.subject=e.subject),e.htmlFile){let n=await import('fs');a.html_content=n.readFileSync(e.htmlFile,"utf-8");}else e.html&&(a.html_content=e.html);if(e.textFile){let n=await import('fs');a.text_content=n.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.tags&&(a.tags=e.tags.split(",").map(n=>n.trim().toLowerCase()).filter(Boolean));let r=await s.templates.update(t,a);if(e.format==="json")m(r,"json");else {p(`Template updated: ${r.id}`);let n={ID:r.id,Name:r.name,Subject:r.subject,Variables:r.variables?.join(", ")||"-",Tags:r.tags?.join(", ")||"-",Updated:r.updated_at};m(n,"table");}}catch(o){l(o instanceof Error?o.message:"Failed to update template"),process.exit(1);}}),i.command("delete <template_id>").description(`Delete a template
|
|
886
886
|
|
|
887
887
|
USAGE
|
|
888
888
|
emailr templates delete <template_id>
|
|
@@ -899,7 +899,7 @@ EXAMPLES
|
|
|
899
899
|
emailr templates delete tpl_abc123
|
|
900
900
|
|
|
901
901
|
WARNING
|
|
902
|
-
This action is permanent and cannot be undone.`).action(async t=>{try{let e=
|
|
902
|
+
This action is permanent and cannot be undone.`).action(async t=>{try{let e=c();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);}}),i.command("preview <template_id>").description(`Preview a template in the browser
|
|
903
903
|
|
|
904
904
|
USAGE
|
|
905
905
|
emailr templates preview <template_id> [options]
|
|
@@ -928,17 +928,17 @@ EXAMPLES
|
|
|
928
928
|
|
|
929
929
|
SEE ALSO
|
|
930
930
|
emailr templates edit Live editing with hot-reload
|
|
931
|
-
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 o=
|
|
932
|
-
Template: ${a.name}`),console.log(`Preview URL: ${
|
|
931
|
+
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 o=c(),s=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl});console.log(`Fetching template ${t}...`);let a=await s.templates.get(t),r=a.html_content??"";if(X(a.id,r),e.foreground){let g=await z(a.id);if(g||(l("Failed to start preview server"),process.exit(1)),ve(),console.log(`
|
|
932
|
+
Template: ${a.name}`),console.log(`Preview URL: ${g}`),e.open!==!1)try{await(await import('open')).default(g),console.log(`
|
|
933
933
|
Browser opened.`);}catch{console.log(`
|
|
934
934
|
Could not open browser automatically. Open the URL above manually.`);}process.on("SIGINT",async()=>{console.log(`
|
|
935
935
|
|
|
936
|
-
Stopping preview server...`),await
|
|
936
|
+
Stopping preview server...`),await Se().stop(),console.log("Done."),process.exit(0);});return}let n=_.join(process.cwd(),`.template-preview-${a.id}.html`);O.writeFileSync(n,r,"utf-8");let{spawn:d}=await import('child_process'),h=await import('os'),y=_.join(h.tmpdir(),"emailr-preview.pid");try{let g=O.readFileSync(y,"utf-8").trim();process.kill(parseInt(g,10),"SIGTERM");}catch{}let u=`
|
|
937
937
|
const http = require('http');
|
|
938
938
|
const fs = require('fs');
|
|
939
939
|
const path = require('path');
|
|
940
940
|
const os = require('os');
|
|
941
|
-
const filePath = ${JSON.stringify(
|
|
941
|
+
const filePath = ${JSON.stringify(n)};
|
|
942
942
|
const pidFile = path.join(os.tmpdir(), 'emailr-preview.pid');
|
|
943
943
|
const portFile = path.join(os.tmpdir(), 'emailr-preview.port');
|
|
944
944
|
const server = http.createServer((req, res) => {
|
|
@@ -958,9 +958,9 @@ Stopping preview server...`),await we().stop(),console.log("Done."),process.exit
|
|
|
958
958
|
console.log('PORT:' + port);
|
|
959
959
|
});
|
|
960
960
|
process.on('SIGTERM', () => { try { fs.unlinkSync(pidFile); fs.unlinkSync(portFile); fs.unlinkSync(filePath); } catch {} process.exit(0); });
|
|
961
|
-
`,
|
|
962
|
-
Template: ${a.name}`),console.log(`Preview URL: ${
|
|
963
|
-
To stop: emailr templates stop-preview`),e.open!==!1)try{await(await import('open')).default(
|
|
961
|
+
`,b=d("node",["-e",u],{detached:!0,stdio:["ignore","pipe","ignore"]}),w="";await new Promise(g=>{b.stdout?.on("data",x=>{let J=x.toString().match(/PORT:(\d+)/);J&&(w=J[1],g());}),setTimeout(g,3e3);}),b.unref();let j=`http://127.0.0.1:${w}/`;if(console.log(`
|
|
962
|
+
Template: ${a.name}`),console.log(`Preview URL: ${j}`),console.log(`
|
|
963
|
+
To stop: emailr templates stop-preview`),e.open!==!1)try{await(await import('open')).default(j);}catch{}process.exit(0);}catch(o){l(o instanceof Error?o.message:"Failed to preview template"),process.exit(1);}}),i.command("edit <template_id>").description(`Start a live editing session for a template with hot-reload
|
|
964
964
|
|
|
965
965
|
USAGE
|
|
966
966
|
emailr templates edit <template_id> [options]
|
|
@@ -1000,12 +1000,12 @@ EXAMPLES
|
|
|
1000
1000
|
SEE ALSO
|
|
1001
1001
|
emailr templates draft Draft a new template with live preview
|
|
1002
1002
|
emailr templates update Save changes to the template
|
|
1003
|
-
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 o=
|
|
1004
|
-
Template: ${
|
|
1005
|
-
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(
|
|
1003
|
+
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 o=c(),s=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),a=_.resolve(e.file);console.log(`Fetching template ${t}...`);let r=await s.templates.get(t),n=r.html_content??"";if(O.writeFileSync(a,n,"utf-8"),console.log(`Template saved to: ${a}`),e.foreground){let x=`http://127.0.0.1:${await Z(a,()=>{console.log("File changed - browser refreshed");})}/`;if(console.log(`
|
|
1004
|
+
Template: ${r.name}`),console.log(`Template ID: ${r.id}`),console.log(`Live Preview: ${x}`),console.log(`File: ${a}`),console.log(`
|
|
1005
|
+
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(x);}catch{}process.on("SIGINT",async()=>{console.log(`
|
|
1006
1006
|
|
|
1007
|
-
Stopping live preview server...`),await
|
|
1008
|
-
To save changes: emailr templates update ${t} --html-file ${e.file}`),process.exit(0);});return}let{spawn:
|
|
1007
|
+
Stopping live preview server...`),await Q(),console.log("Done."),console.log(`
|
|
1008
|
+
To save changes: emailr templates update ${t} --html-file ${e.file}`),process.exit(0);});return}let{spawn:d}=await import('child_process'),h=await import('os'),y=_.join(h.tmpdir(),"emailr-preview.pid");try{let g=O.readFileSync(y,"utf-8").trim();process.kill(parseInt(g,10),"SIGTERM");}catch{}let u=`
|
|
1009
1009
|
const http = require('http');
|
|
1010
1010
|
const fs = require('fs');
|
|
1011
1011
|
const path = require('path');
|
|
@@ -1045,10 +1045,10 @@ To save changes: emailr templates update ${t} --html-file ${e.file}`),process.ex
|
|
|
1045
1045
|
});
|
|
1046
1046
|
});
|
|
1047
1047
|
process.on('SIGTERM', () => { try { fs.unlinkSync(pidFile); fs.unlinkSync(portFile); } catch {} process.exit(0); });
|
|
1048
|
-
`,
|
|
1049
|
-
Template: ${
|
|
1048
|
+
`,b=d("node",["-e",u],{detached:!0,stdio:["ignore","pipe","ignore"]}),w="";await new Promise(g=>{b.stdout?.on("data",x=>{let ne=x.toString().match(/PORT:(\d+)/);ne&&(w=ne[1],g());}),setTimeout(g,3e3);}),b.unref();let j=`http://127.0.0.1:${w}/`;if(console.log(`
|
|
1049
|
+
Template: ${r.name}`),console.log(`Template ID: ${r.id}`),console.log(`Live Preview: ${j}`),console.log(`File: ${a}`),console.log(`
|
|
1050
1050
|
Edit the file and see live updates in the browser.`),console.log(`
|
|
1051
|
-
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(
|
|
1051
|
+
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(j);}catch{}process.exit(0);}catch(o){l(o instanceof Error?o.message:"Failed to edit template"),process.exit(1);}}),i.command("draft").description(`Start a live drafting session for a new template with hot-reload
|
|
1052
1052
|
|
|
1053
1053
|
USAGE
|
|
1054
1054
|
emailr templates draft [options]
|
|
@@ -1125,13 +1125,13 @@ SEE ALSO
|
|
|
1125
1125
|
<p><a href="{{unsubscribe_link}}">Unsubscribe</a></p>
|
|
1126
1126
|
</div>
|
|
1127
1127
|
</body>
|
|
1128
|
-
</html>`,
|
|
1129
|
-
Live Preview: ${
|
|
1128
|
+
</html>`,O.writeFileSync(e,o,"utf-8"),console.log(`Template draft created: ${e}`),t.foreground){let b=`http://127.0.0.1:${await Z(e,()=>{console.log("File changed - browser refreshed");})}/`;if(console.log(`
|
|
1129
|
+
Live Preview: ${b}`),console.log(`File: ${e}`),console.log(`
|
|
1130
1130
|
Watching for changes... Edit the file and see live updates.`),console.log(`
|
|
1131
|
-
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(
|
|
1131
|
+
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(b);}catch{}process.on("SIGINT",async()=>{console.log(`
|
|
1132
1132
|
|
|
1133
|
-
Stopping live preview server...`),await
|
|
1134
|
-
To create template: emailr templates create --name "Template Name" --subject "Email Subject" --html-file ${t.file}`),process.exit(0);});return}let{spawn:
|
|
1133
|
+
Stopping live preview server...`),await Q(),console.log("Done."),console.log(`
|
|
1134
|
+
To create template: emailr templates create --name "Template Name" --subject "Email Subject" --html-file ${t.file}`),process.exit(0);});return}let{spawn:s}=await import('child_process'),a=await import('os'),r=_.join(a.tmpdir(),"emailr-preview.pid");try{let u=O.readFileSync(r,"utf-8").trim();process.kill(parseInt(u,10),"SIGTERM");}catch{}let n=`
|
|
1135
1135
|
const http = require('http');
|
|
1136
1136
|
const fs = require('fs');
|
|
1137
1137
|
const path = require('path');
|
|
@@ -1171,10 +1171,10 @@ To create template: emailr templates create --name "Template Name" --subject "Em
|
|
|
1171
1171
|
});
|
|
1172
1172
|
});
|
|
1173
1173
|
process.on('SIGTERM', () => { try { fs.unlinkSync(pidFile); fs.unlinkSync(portFile); } catch {} process.exit(0); });
|
|
1174
|
-
`,
|
|
1175
|
-
Live Preview: ${
|
|
1174
|
+
`,d=s("node",["-e",n],{detached:!0,stdio:["ignore","pipe","ignore"]}),h="";await new Promise(u=>{d.stdout?.on("data",b=>{let w=b.toString().match(/PORT:(\d+)/);w&&(h=w[1],u());}),setTimeout(u,3e3);}),d.unref();let y=`http://127.0.0.1:${h}/`;if(console.log(`
|
|
1175
|
+
Live Preview: ${y}`),console.log(`File: ${e}`),console.log(`
|
|
1176
1176
|
Edit the file and see live updates in the browser.`),console.log(`
|
|
1177
|
-
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(
|
|
1177
|
+
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(y);}catch{}process.exit(0);}catch(e){l(e instanceof Error?e.message:"Failed to start draft session"),process.exit(1);}}),i.command("stop-preview").description(`Stop any running background preview server
|
|
1178
1178
|
|
|
1179
1179
|
USAGE
|
|
1180
1180
|
emailr templates stop-preview
|
|
@@ -1191,7 +1191,7 @@ EXAMPLES
|
|
|
1191
1191
|
SEE ALSO
|
|
1192
1192
|
emailr templates edit Start live editing session
|
|
1193
1193
|
emailr templates draft Start live drafting session
|
|
1194
|
-
emailr templates preview Preview a template in browser`).action(async()=>{let t=await import('os'),e=_.join(t.tmpdir(),"emailr-preview.pid");try{let o=
|
|
1194
|
+
emailr templates preview Preview a template in browser`).action(async()=>{let t=await import('os'),e=_.join(t.tmpdir(),"emailr-preview.pid");try{let o=O.readFileSync(e,"utf-8").trim();process.kill(parseInt(o,10),"SIGTERM"),O.unlinkSync(e),p("Preview server stopped");}catch{p("No preview server running");}}),i}function je(){let i=new Command("domains").description(`Manage sending domains
|
|
1195
1195
|
|
|
1196
1196
|
USAGE
|
|
1197
1197
|
emailr domains <subcommand> [options]
|
|
@@ -1299,7 +1299,7 @@ EXAMPLES
|
|
|
1299
1299
|
emailr domains list --format json | jq '.[] | select(.status == "verified")'
|
|
1300
1300
|
|
|
1301
1301
|
# Count domains
|
|
1302
|
-
emailr domains list --format json | jq 'length'`).option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=
|
|
1302
|
+
emailr domains list --format json | jq 'length'`).option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=c(),s=await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).domains.list();if(t.format==="json")m(s,"json");else {let a=s.map(r=>({ID:r.id,Domain:r.domain,Status:r.status,DKIM:r.dkim_verified,SPF:r.spf_verified,DMARC:r.dmarc_verified,Created:r.created_at}));m(a,"table");}}catch(e){l(e instanceof Error?e.message:"Failed to list domains"),process.exit(1);}}),i.command("get <domain_id>").description(`Get domain details
|
|
1303
1303
|
|
|
1304
1304
|
USAGE
|
|
1305
1305
|
emailr domains get <domain_id> [options]
|
|
@@ -1326,7 +1326,7 @@ EXAMPLES
|
|
|
1326
1326
|
emailr domains get dom_abc123 --format json
|
|
1327
1327
|
|
|
1328
1328
|
# Extract DNS records
|
|
1329
|
-
emailr domains get dom_abc123 --format json | jq '.dns_records'`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=
|
|
1329
|
+
emailr domains get dom_abc123 --format json | jq '.dns_records'`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=c(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).domains.get(t);m(a,e.format);}catch(o){l(o instanceof Error?o.message:"Failed to get domain"),process.exit(1);}}),i.command("add <domain_name>").description(`Add a new domain
|
|
1330
1330
|
|
|
1331
1331
|
USAGE
|
|
1332
1332
|
emailr domains add <domain_name> [options]
|
|
@@ -1379,7 +1379,7 @@ NEXT STEPS
|
|
|
1379
1379
|
1. Copy the DNS records shown in the output
|
|
1380
1380
|
2. Add them to your DNS provider (Cloudflare, Route53, etc.)
|
|
1381
1381
|
3. Wait for DNS propagation (up to 48 hours)
|
|
1382
|
-
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 o=
|
|
1382
|
+
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 o=c(),s=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),a={domain:t};e.receivingSubdomain&&(a.receivingSubdomain=e.receivingSubdomain);let r=await s.domains.add(a);if(e.format==="json")m(r,"json");else {if(p(`Domain added: ${r.domain}`),f("Add the following DNS records to verify your domain:"),console.log(""),r.dns_records){let n=[{Type:"DKIM",...ee(r.dns_records.dkim)},{Type:"SPF",...ee(r.dns_records.spf)},{Type:"DMARC",...ee(r.dns_records.dmarc)}];m(n,"table");}console.log(""),f(`Run 'emailr domains verify ${r.id}' after adding DNS records`);}}catch(o){l(o instanceof Error?o.message:"Failed to add domain"),process.exit(1);}}),i.command("verify <domain_id>").description(`Verify a domain
|
|
1383
1383
|
|
|
1384
1384
|
USAGE
|
|
1385
1385
|
emailr domains verify <domain_id> [options]
|
|
@@ -1417,7 +1417,7 @@ TROUBLESHOOTING
|
|
|
1417
1417
|
1. Run 'check-dns' to see which records are missing
|
|
1418
1418
|
2. Verify records are correctly configured with your DNS provider
|
|
1419
1419
|
3. Wait for DNS propagation (can take up to 48 hours)
|
|
1420
|
-
4. Try verification again`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=
|
|
1420
|
+
4. Try verification again`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=c(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).domains.verify(t);e.format==="json"?m(a,"json"):a.verified?p("Domain verified successfully!"):(f(`Domain status: ${a.status}`),a.dkim_status&&f(`DKIM status: ${a.dkim_status}`));}catch(o){l(o instanceof Error?o.message:"Failed to verify domain"),process.exit(1);}}),i.command("check-dns <domain_id>").description(`Check DNS records for a domain
|
|
1421
1421
|
|
|
1422
1422
|
USAGE
|
|
1423
1423
|
emailr domains check-dns <domain_id> [options]
|
|
@@ -1464,7 +1464,7 @@ COMMON ISSUES
|
|
|
1464
1464
|
|
|
1465
1465
|
Multiple records found:
|
|
1466
1466
|
- Remove duplicate TXT records
|
|
1467
|
-
- Keep only the Emailr-specific record`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=
|
|
1467
|
+
- Keep only the Emailr-specific record`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=c(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).domains.checkDns(t);if(e.format==="json")m(a,"json");else {let r=Object.entries(a).map(([n,d])=>({Record:n,Verified:d.verified,Expected:d.expected||"-",Found:d.found?.join(", ")||"-"}));m(r,"table");}}catch(o){l(o instanceof Error?o.message:"Failed to check DNS"),process.exit(1);}}),i.command("delete <domain_id>").description(`Delete a domain
|
|
1468
1468
|
|
|
1469
1469
|
USAGE
|
|
1470
1470
|
emailr domains delete <domain_id> [options]
|
|
@@ -1494,7 +1494,7 @@ WARNING
|
|
|
1494
1494
|
This action is permanent and cannot be undone.
|
|
1495
1495
|
- Emails from this domain will fail to send
|
|
1496
1496
|
- DNS records can be removed from your DNS provider
|
|
1497
|
-
- Re-add the domain if you need to restore functionality`).option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=
|
|
1497
|
+
- Re-add the domain if you need to restore functionality`).option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=c();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);}}),i}function ee(i){return {"Record Type":i.type,Name:i.name,Value:i.value.length>50?i.value.substring(0,47)+"...":i.value,...i.priority!==void 0&&{Priority:i.priority}}}function xe(){let i=new Command("config").description(`Manage CLI configuration
|
|
1498
1498
|
|
|
1499
1499
|
USAGE
|
|
1500
1500
|
emailr config <subcommand> [options]
|
|
@@ -1587,7 +1587,7 @@ EXAMPLES
|
|
|
1587
1587
|
|
|
1588
1588
|
NOTE
|
|
1589
1589
|
Environment variables (EMAILR_API_KEY, EMAILR_BASE_URL) take precedence
|
|
1590
|
-
over config file values at runtime.`).action(async(t,e)=>{try{let o=["api-key","base-url","format"],
|
|
1590
|
+
over config file values at runtime.`).action(async(t,e)=>{try{let o=["api-key","base-url","format"],s=t.toLowerCase();o.includes(s)||(l(`Invalid config key: ${t}`),f(`Valid keys: ${o.join(", ")}`),process.exit(1));let r={"api-key":"apiKey","base-url":"baseUrl",format:"format"}[s];s==="format"&&!["json","table"].includes(e)&&(l(`Invalid format value: ${e}`),f("Valid formats: json, table"),process.exit(1)),G({[r]:e}),p(`Configuration saved: ${t} = ${s==="api-key"?"***":e}`),f(`Config file: ${N()}`);}catch(o){l(o instanceof Error?o.message:"Failed to save configuration"),process.exit(1);}}),i.command("get <key>").description(`Get a configuration value
|
|
1591
1591
|
|
|
1592
1592
|
USAGE
|
|
1593
1593
|
emailr config get <key>
|
|
@@ -1615,7 +1615,7 @@ EXAMPLES
|
|
|
1615
1615
|
emailr config get format
|
|
1616
1616
|
|
|
1617
1617
|
SEE ALSO
|
|
1618
|
-
emailr config list Show all configuration values`).action(async t=>{try{let e=["api-key","base-url","format"],o=t.toLowerCase();e.includes(o)||(l(`Invalid config key: ${t}`),
|
|
1618
|
+
emailr config list Show all configuration values`).action(async t=>{try{let e=["api-key","base-url","format"],o=t.toLowerCase();e.includes(o)||(l(`Invalid config key: ${t}`),f(`Valid keys: ${e.join(", ")}`),process.exit(1));let a={"api-key":"apiKey","base-url":"baseUrl",format:"format"}[o],r=se(a);r?console.log(o==="api-key"?r.substring(0,8)+"..."+r.substring(r.length-4):r):f(`${t} is not set`);}catch(e){l(e instanceof Error?e.message:"Failed to get configuration"),process.exit(1);}}),i.command("list").description(`List all configuration values
|
|
1619
1619
|
|
|
1620
1620
|
USAGE
|
|
1621
1621
|
emailr config list [options]
|
|
@@ -1643,7 +1643,7 @@ EXAMPLES
|
|
|
1643
1643
|
|
|
1644
1644
|
SEE ALSO
|
|
1645
1645
|
emailr config get Get a single configuration value
|
|
1646
|
-
emailr config path Show config file location`).option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=
|
|
1646
|
+
emailr config path Show config file location`).option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=c(),o={"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(o,"json");else {let s=Object.entries(o).map(([a,r])=>({Key:a,Value:r}));m(s,"table");}console.log(""),f(`Config file: ${N()}`);}catch(e){e instanceof Error&&e.message.includes("No API key configured")?(f("No configuration found."),f("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));}}),i.command("path").description(`Show the configuration file path
|
|
1647
1647
|
|
|
1648
1648
|
USAGE
|
|
1649
1649
|
emailr config path
|
|
@@ -1670,7 +1670,7 @@ EXAMPLES
|
|
|
1670
1670
|
open $(emailr config path)
|
|
1671
1671
|
|
|
1672
1672
|
# View config file contents
|
|
1673
|
-
cat $(emailr config path)`).action(()=>{console.log(
|
|
1673
|
+
cat $(emailr config path)`).action(()=>{console.log(N());}),i.command("init").description(`Initialize configuration interactively
|
|
1674
1674
|
|
|
1675
1675
|
USAGE
|
|
1676
1676
|
emailr config init [options]
|
|
@@ -1703,7 +1703,7 @@ ALTERNATIVE: ENVIRONMENT VARIABLES
|
|
|
1703
1703
|
|
|
1704
1704
|
SEE ALSO
|
|
1705
1705
|
emailr config set Set individual configuration values
|
|
1706
|
-
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}),
|
|
1706
|
+
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!"),f(`Config file: ${N()}`)):(f("Initialize your Emailr CLI configuration:"),console.log(""),f("Run with --api-key flag:"),console.log(" emailr config init --api-key <your-api-key>"),console.log(""),f("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);}}),i}function Ne(){let i=new Command("broadcasts").description(`Manage broadcast campaigns
|
|
1707
1707
|
|
|
1708
1708
|
USAGE
|
|
1709
1709
|
emailr broadcasts <subcommand> [options]
|
|
@@ -1853,7 +1853,7 @@ EXAMPLES
|
|
|
1853
1853
|
emailr broadcasts list --format json
|
|
1854
1854
|
|
|
1855
1855
|
# Pipe JSON to jq for processing
|
|
1856
|
-
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=
|
|
1856
|
+
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=c(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),s={status:t.status,limit:parseInt(t.limit)};if(t.tags){let r=t.tags.split(",").map(n=>n.trim().toLowerCase()).filter(Boolean);r.length>0&&(s.tags=r.join(","));}let a=await o.broadcasts.list(s);if(t.format==="json")m(a,"json");else {if(a.length===0){console.log("No broadcasts found.");return}let r=a.map(n=>({ID:n.id,Name:n.name,Subject:n.subject.substring(0,30)+(n.subject.length>30?"...":""),Status:n.status,Tags:n.tags?.join(", ")||"-",Recipients:n.total_recipients||0,Sent:n.sent_count||0,Created:new Date(n.created_at).toLocaleDateString()}));m(r,"table");}}catch(e){l(e instanceof Error?e.message:"Failed to list broadcasts"),process.exit(1);}}),i.command("get <broadcast_id>").description(`Get broadcast details
|
|
1857
1857
|
|
|
1858
1858
|
USAGE
|
|
1859
1859
|
emailr broadcasts get <broadcast_id> [options]
|
|
@@ -1888,7 +1888,7 @@ EXAMPLES
|
|
|
1888
1888
|
emailr broadcasts get brd_abc123 --format json
|
|
1889
1889
|
|
|
1890
1890
|
# Pipe JSON to jq for processing
|
|
1891
|
-
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 o=
|
|
1891
|
+
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 o=c(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.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(o){l(o instanceof Error?o.message:"Failed to get broadcast"),process.exit(1);}}),i.command("create").description(`Create a new broadcast
|
|
1892
1892
|
|
|
1893
1893
|
USAGE
|
|
1894
1894
|
emailr broadcasts create --name <name> --subject <subject> --from <email> [options]
|
|
@@ -1902,6 +1902,8 @@ OPTIONS
|
|
|
1902
1902
|
--subject <subject_line> Email subject line (required)
|
|
1903
1903
|
--from <email_address> Sender email address (required)
|
|
1904
1904
|
--from-name <name> Sender display name (e.g. "Acme Inc")
|
|
1905
|
+
--reply-to <email> Reply-To email address
|
|
1906
|
+
--preview-text <text> Preview text (preheader) shown in email clients
|
|
1905
1907
|
--template <template_id> Template ID to use for content
|
|
1906
1908
|
--segment <segment_id> Segment ID to target recipients
|
|
1907
1909
|
--html <html_content> Inline HTML content (alternative to --template)
|
|
@@ -1966,7 +1968,7 @@ EXAMPLES
|
|
|
1966
1968
|
|
|
1967
1969
|
SEE ALSO
|
|
1968
1970
|
emailr templates Create and manage email templates
|
|
1969
|
-
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("--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=
|
|
1971
|
+
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("--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=c(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),s={name:t.name,subject:t.subject,from_email:t.from,from_name:t.fromName,reply_to:t.replyTo,preview_text:t.previewText,template_id:t.template,segment_id:t.segment,html_content:t.html,text_content:t.text,scheduled_at:t.schedule};t.tags&&(s.tags=t.tags.split(",").map(r=>r.trim().toLowerCase()).filter(Boolean));let a=await o.broadcasts.create(s);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);}}),i.command("send <broadcast_id>").description(`Send a broadcast immediately
|
|
1970
1972
|
|
|
1971
1973
|
USAGE
|
|
1972
1974
|
emailr broadcasts send <broadcast_id> [options]
|
|
@@ -1999,7 +2001,7 @@ EXAMPLES
|
|
|
1999
2001
|
NOTE
|
|
2000
2002
|
Sending is asynchronous. The command returns when sending starts,
|
|
2001
2003
|
not when all emails are delivered. Use 'emailr broadcasts get' to
|
|
2002
|
-
check delivery progress.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=
|
|
2004
|
+
check delivery progress.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=c(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.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(o){l(o instanceof Error?o.message:"Failed to send broadcast"),process.exit(1);}}),i.command("schedule <broadcast_id>").description(`Schedule a broadcast for future delivery
|
|
2003
2005
|
|
|
2004
2006
|
USAGE
|
|
2005
2007
|
emailr broadcasts schedule <broadcast_id> --at <datetime> [options]
|
|
@@ -2049,7 +2051,7 @@ EXAMPLES
|
|
|
2049
2051
|
emailr broadcasts schedule brd_abc123 --at "2024-12-25T10:00:00Z" --format json
|
|
2050
2052
|
|
|
2051
2053
|
SEE ALSO
|
|
2052
|
-
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 o=
|
|
2054
|
+
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 o=c(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.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(o){l(o instanceof Error?o.message:"Failed to schedule broadcast"),process.exit(1);}}),i.command("cancel <broadcast_id>").description(`Cancel a scheduled broadcast
|
|
2053
2055
|
|
|
2054
2056
|
USAGE
|
|
2055
2057
|
emailr broadcasts cancel <broadcast_id> [options]
|
|
@@ -2077,7 +2079,7 @@ EXAMPLES
|
|
|
2077
2079
|
emailr broadcasts cancel brd_abc123 --format json
|
|
2078
2080
|
|
|
2079
2081
|
NOTE
|
|
2080
|
-
Broadcasts that are already 'sending' or 'sent' cannot be cancelled.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=
|
|
2082
|
+
Broadcasts that are already 'sending' or 'sent' cannot be cancelled.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=c(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).broadcasts.cancel(t);e.format==="json"?m(a,"json"):p("Broadcast cancelled successfully!");}catch(o){l(o instanceof Error?o.message:"Failed to cancel broadcast"),process.exit(1);}}),i.command("update <broadcast_id>").description(`Update a broadcast
|
|
2081
2083
|
|
|
2082
2084
|
USAGE
|
|
2083
2085
|
emailr broadcasts update <broadcast_id> [options]
|
|
@@ -2094,6 +2096,8 @@ OPTIONS
|
|
|
2094
2096
|
--subject <subject> Update email subject line
|
|
2095
2097
|
--from <email> Update sender email address
|
|
2096
2098
|
--from-name <name> Update sender display name
|
|
2099
|
+
--reply-to <email> Update Reply-To email address
|
|
2100
|
+
--preview-text <text> Update preview text (preheader)
|
|
2097
2101
|
--template <id> Update template ID (use "none" to clear)
|
|
2098
2102
|
--segment <id> Update segment ID (use "none" to clear)
|
|
2099
2103
|
--topic <id> Update topic ID (use "none" to clear)
|
|
@@ -2103,6 +2107,10 @@ OPTIONS
|
|
|
2103
2107
|
--tags <tags> Update tags (comma-separated, replaces existing)
|
|
2104
2108
|
--format <format> Output format: json | table (default: table)
|
|
2105
2109
|
|
|
2110
|
+
OUTPUT FORMATS
|
|
2111
|
+
--format json Full updated broadcast object with all fields
|
|
2112
|
+
--format table Summary table with ID, Name, Subject, Status, Tags, Scheduled At
|
|
2113
|
+
|
|
2106
2114
|
EXAMPLES
|
|
2107
2115
|
# Update broadcast name and subject
|
|
2108
2116
|
emailr broadcasts update brd_abc123 --name "New Name" --subject "New Subject"
|
|
@@ -2123,7 +2131,7 @@ EXAMPLES
|
|
|
2123
2131
|
emailr broadcasts update brd_abc123 --name "Updated" --format json
|
|
2124
2132
|
|
|
2125
2133
|
NOTE
|
|
2126
|
-
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("--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 o=
|
|
2134
|
+
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("--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 o=c(),s=new Emailr({apiKey:o.apiKey,baseUrl:o.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.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(n=>n.trim().toLowerCase()).filter(Boolean)),Object.keys(a).length===0&&(l("No update fields specified. Use --help to see available options."),process.exit(1));let r=await s.broadcasts.update(t,a);e.format==="json"?m(r,"json"):(p("Broadcast updated successfully!"),m({ID:r.id,Name:r.name,Subject:r.subject,Status:r.status,Tags:r.tags?.join(", ")||"-","Scheduled At":r.scheduled_at||"Not scheduled"},"table"));}catch(o){l(o instanceof Error?o.message:"Failed to update broadcast"),process.exit(1);}}),i.command("delete <broadcast_id>").description(`Delete a broadcast
|
|
2127
2135
|
|
|
2128
2136
|
USAGE
|
|
2129
2137
|
emailr broadcasts delete <broadcast_id> [options]
|
|
@@ -2151,7 +2159,7 @@ EXAMPLES
|
|
|
2151
2159
|
|
|
2152
2160
|
WARNING
|
|
2153
2161
|
This action is permanent and cannot be undone.
|
|
2154
|
-
All delivery statistics will be lost.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=
|
|
2162
|
+
All delivery statistics will be lost.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=c(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).broadcasts.delete(t);e.format==="json"?m(a,"json"):p("Broadcast deleted successfully!");}catch(o){l(o instanceof Error?o.message:"Failed to delete broadcast"),process.exit(1);}}),i}function Ie(){let i=new Command("webhooks").description(`Manage webhooks
|
|
2155
2163
|
|
|
2156
2164
|
USAGE
|
|
2157
2165
|
emailr webhooks <subcommand> [options]
|
|
@@ -2304,7 +2312,7 @@ EXAMPLES
|
|
|
2304
2312
|
emailr webhooks list --format json | jq '.[] | select(.active == true)'
|
|
2305
2313
|
|
|
2306
2314
|
# Count webhooks
|
|
2307
|
-
emailr webhooks list --format json | jq 'length'`).option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=
|
|
2315
|
+
emailr webhooks list --format json | jq 'length'`).option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=c(),s=await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).webhooks.list();if(t.format==="json")m(s,"json");else {if(s.data.length===0){console.log("No webhooks found.");return}let a=s.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(a,"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
|
|
2308
2316
|
|
|
2309
2317
|
USAGE
|
|
2310
2318
|
emailr webhooks get <webhook_id> [options]
|
|
@@ -2335,7 +2343,7 @@ EXAMPLES
|
|
|
2335
2343
|
emailr webhooks get whk_abc123 --format json
|
|
2336
2344
|
|
|
2337
2345
|
# Extract just the secret
|
|
2338
|
-
emailr webhooks get whk_abc123 --format json | jq -r '.secret'`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=
|
|
2346
|
+
emailr webhooks get whk_abc123 --format json | jq -r '.secret'`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=c(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).webhooks.get(t);e.format==="json"?m(a,"json"):m({ID:a.id,Name:a.name,URL:a.url,Events:a.events.join(", "),Active:a.active?"Yes":"No",Secret:a.secret,"Created At":a.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
|
|
2339
2347
|
|
|
2340
2348
|
USAGE
|
|
2341
2349
|
emailr webhooks create --name <name> --url <url> --events <events> [options]
|
|
@@ -2409,7 +2417,7 @@ EXAMPLES
|
|
|
2409
2417
|
|
|
2410
2418
|
NOTE
|
|
2411
2419
|
Save the webhook secret returned by this command. You'll need it
|
|
2412
|
-
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 t=>{try{let e=
|
|
2420
|
+
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 t=>{try{let e=c(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),s=t.events.split(",").map(r=>r.trim()),a=await o.webhooks.create({name:t.name,url:t.url,events:s});t.format==="json"?m(a,"json"):(p("Webhook created successfully!"),m({ID:a.id,Name:a.name,URL:a.url,Secret:a.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
|
|
2413
2421
|
|
|
2414
2422
|
USAGE
|
|
2415
2423
|
emailr webhooks update <webhook_id> [options]
|
|
@@ -2454,7 +2462,7 @@ EXAMPLES
|
|
|
2454
2462
|
--events "email.delivered,email.bounced"
|
|
2455
2463
|
|
|
2456
2464
|
# Get JSON output
|
|
2457
|
-
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(t,e)=>{try{let o=
|
|
2465
|
+
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(t,e)=>{try{let o=c(),s=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),a={};e.name&&(a.name=e.name),e.url&&(a.url=e.url),e.events&&(a.events=e.events.split(",").map(n=>n.trim()));let r=await s.webhooks.update(t,a);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
|
|
2458
2466
|
|
|
2459
2467
|
USAGE
|
|
2460
2468
|
emailr webhooks enable <webhook_id> [options]
|
|
@@ -2478,7 +2486,7 @@ EXAMPLES
|
|
|
2478
2486
|
emailr webhooks enable whk_abc123
|
|
2479
2487
|
|
|
2480
2488
|
# Get JSON output
|
|
2481
|
-
emailr webhooks enable whk_abc123 --format json`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=
|
|
2489
|
+
emailr webhooks enable whk_abc123 --format json`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=c(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).webhooks.enable(t);e.format==="json"?m(a,"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
|
|
2482
2490
|
|
|
2483
2491
|
USAGE
|
|
2484
2492
|
emailr webhooks disable <webhook_id> [options]
|
|
@@ -2507,7 +2515,7 @@ EXAMPLES
|
|
|
2507
2515
|
|
|
2508
2516
|
NOTE
|
|
2509
2517
|
Events are not queued while webhook is disabled. If you need to
|
|
2510
|
-
temporarily stop processing, consider handling this in your endpoint.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=
|
|
2518
|
+
temporarily stop processing, consider handling this in your endpoint.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=c(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).webhooks.disable(t);e.format==="json"?m(a,"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
|
|
2511
2519
|
|
|
2512
2520
|
USAGE
|
|
2513
2521
|
emailr webhooks delete <webhook_id> [options]
|
|
@@ -2535,7 +2543,7 @@ EXAMPLES
|
|
|
2535
2543
|
|
|
2536
2544
|
WARNING
|
|
2537
2545
|
This action is permanent and cannot be undone.
|
|
2538
|
-
Create a new webhook if you need to restore functionality.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=
|
|
2546
|
+
Create a new webhook if you need to restore functionality.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=c(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).webhooks.delete(t);e.format==="json"?m(a,"json"):p("Webhook deleted successfully!");}catch(o){l(o instanceof Error?o.message:"Failed to delete webhook"),process.exit(1);}}),i}function Ce(){let i=new Command("segments").description(`Manage contact segments
|
|
2539
2547
|
|
|
2540
2548
|
USAGE
|
|
2541
2549
|
emailr segments <subcommand> [options]
|
|
@@ -2675,7 +2683,7 @@ EXAMPLES
|
|
|
2675
2683
|
emailr segments list --format json
|
|
2676
2684
|
|
|
2677
2685
|
# Pipe JSON to jq for processing
|
|
2678
|
-
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=
|
|
2686
|
+
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=c(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),s={};if(t.tags){let r=t.tags.split(",").map(n=>n.trim().toLowerCase()).filter(Boolean);r.length>0&&(s.tags=r.join(","));}let a=await o.segments.list(s);if(t.format==="json")m(a,"json");else {if(a.length===0){console.log("No segments found.");return}let r=a.map(n=>({ID:n.id,Name:n.name,Description:(n.description||"").substring(0,30)+((n.description?.length||0)>30?"...":""),Tags:n.tags?.join(", ")||"-","Created At":new Date(n.created_at).toLocaleDateString()}));m(r,"table");}}catch(e){l(e instanceof Error?e.message:"Failed to list segments"),process.exit(1);}}),i.command("get <segment_id>").description(`Get segment details
|
|
2679
2687
|
|
|
2680
2688
|
USAGE
|
|
2681
2689
|
emailr segments get <segment_id> [options]
|
|
@@ -2702,7 +2710,7 @@ EXAMPLES
|
|
|
2702
2710
|
emailr segments get seg_abc123 --format json
|
|
2703
2711
|
|
|
2704
2712
|
# Pipe JSON to jq to view conditions
|
|
2705
|
-
emailr segments get seg_abc123 --format json | jq '.conditions'`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=
|
|
2713
|
+
emailr segments get seg_abc123 --format json | jq '.conditions'`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=c(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.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(o){l(o instanceof Error?o.message:"Failed to get segment"),process.exit(1);}}),i.command("create").description(`Create a new segment
|
|
2706
2714
|
|
|
2707
2715
|
USAGE
|
|
2708
2716
|
emailr segments create --name <segment_name> --conditions <json> [options]
|
|
@@ -2752,7 +2760,7 @@ EXAMPLES
|
|
|
2752
2760
|
# Get JSON output for scripting
|
|
2753
2761
|
emailr segments create --name "Test" \\
|
|
2754
2762
|
--conditions '[{"field": "subscribed", "operator": "equals", "value": true}]' \\
|
|
2755
|
-
--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=
|
|
2763
|
+
--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=c(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),s;try{s=JSON.parse(t.conditions);}catch{l("Invalid JSON for --conditions"),process.exit(1);}let a={name:t.name,description:t.description,conditions:s};t.tags&&(a.tags=t.tags.split(",").map(n=>n.trim().toLowerCase()).filter(Boolean));let r=await o.segments.create(a);t.format==="json"?m(r,"json"):(p("Segment created successfully!"),m({ID:r.id,Name:r.name,Tags:r.tags?.join(", ")||"-"},"table"));}catch(e){l(e instanceof Error?e.message:"Failed to create segment"),process.exit(1);}}),i.command("update <segment_id>").description(`Update a segment
|
|
2756
2764
|
|
|
2757
2765
|
USAGE
|
|
2758
2766
|
emailr segments update <segment_id> [options]
|
|
@@ -2798,7 +2806,7 @@ EXAMPLES
|
|
|
2798
2806
|
--conditions '[{"field": "metadata.plan", "operator": "equals", "value": "enterprise"}]'
|
|
2799
2807
|
|
|
2800
2808
|
# Get JSON output
|
|
2801
|
-
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 o=
|
|
2809
|
+
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 o=c(),s=new Emailr({apiKey:o.apiKey,baseUrl:o.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(n=>n.trim().toLowerCase()).filter(Boolean));let r=await s.segments.update(t,a);e.format==="json"?m(r,"json"):(p("Segment updated successfully!"),m({ID:r.id,Name:r.name,Tags:r.tags?.join(", ")||"-"},"table"));}catch(o){l(o instanceof Error?o.message:"Failed to update segment"),process.exit(1);}}),i.command("delete <segment_id>").description(`Delete a segment
|
|
2802
2810
|
|
|
2803
2811
|
USAGE
|
|
2804
2812
|
emailr segments delete <segment_id>
|
|
@@ -2823,7 +2831,7 @@ EXAMPLES
|
|
|
2823
2831
|
|
|
2824
2832
|
WARNING
|
|
2825
2833
|
This action is permanent and cannot be undone.
|
|
2826
|
-
Any broadcasts targeting this segment will need to be updated.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=
|
|
2834
|
+
Any broadcasts targeting this segment will need to be updated.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=c(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).segments.delete(t);e.format==="json"?m(a,"json"):p("Segment deleted successfully!");}catch(o){l(o instanceof Error?o.message:"Failed to delete segment"),process.exit(1);}}),i.command("count <segment_id>").description(`Get the number of contacts in a segment
|
|
2827
2835
|
|
|
2828
2836
|
USAGE
|
|
2829
2837
|
emailr segments count <segment_id> [options]
|
|
@@ -2854,7 +2862,7 @@ EXAMPLES
|
|
|
2854
2862
|
|
|
2855
2863
|
TIP
|
|
2856
2864
|
Use this before sending broadcasts to verify your segment
|
|
2857
|
-
targets the expected number of contacts.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=
|
|
2865
|
+
targets the expected number of contacts.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=c(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).segments.getContactsCount(t);e.format==="json"?m(a,"json"):console.log(`Segment contains ${a.count} contacts.`);}catch(o){l(o instanceof Error?o.message:"Failed to get segment count"),process.exit(1);}}),i}function pt(i){try{let t=i.startsWith("http")?i:`http://localhost${i}`,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 ut(){return `<!DOCTYPE html>
|
|
2858
2866
|
<html lang="en">
|
|
2859
2867
|
<head>
|
|
2860
2868
|
<meta charset="UTF-8">
|
|
@@ -2900,7 +2908,7 @@ TIP
|
|
|
2900
2908
|
<p>You can close this window and return to your terminal.</p>
|
|
2901
2909
|
</div>
|
|
2902
2910
|
</body>
|
|
2903
|
-
</html>`}function
|
|
2911
|
+
</html>`}function te(i){return `<!DOCTYPE html>
|
|
2904
2912
|
<html lang="en">
|
|
2905
2913
|
<head>
|
|
2906
2914
|
<meta charset="UTF-8">
|
|
@@ -2955,7 +2963,7 @@ TIP
|
|
|
2955
2963
|
<p style="margin-top: 1rem;">Please close this window and try again.</p>
|
|
2956
2964
|
</div>
|
|
2957
2965
|
</body>
|
|
2958
|
-
</html>`}function
|
|
2966
|
+
</html>`}function Ue(){let i=null,t=0,e=null,o=null,s=null;return {async start(){return new Promise((a,r)=>{i=Xe.createServer((n,d)=>{if(n.method!=="GET"||!n.url?.startsWith("/callback")){d.writeHead(404,{"Content-Type":"text/plain"}),d.end("Not Found");return}let h=pt(n.url);if(s&&h.state!==s){d.writeHead(400,{"Content-Type":"text/html"}),d.end(te("Security verification failed. State parameter mismatch.")),e&&e({success:false,error:"State parameter mismatch"});return}if(h.error){let u=h.message||h.error;d.writeHead(200,{"Content-Type":"text/html"}),d.end(te(u)),e&&e({success:false,error:u});return}let y=h.key||h.code;if(y){d.writeHead(200,{"Content-Type":"text/html"}),d.end(ut()),e&&e({success:true,apiKey:y});return}d.writeHead(400,{"Content-Type":"text/html"}),d.end(te("Invalid callback: missing required parameters.")),e&&e({success:false,error:"Invalid callback: missing required parameters"});}),i.listen(0,"127.0.0.1",()=>{let n=i.address();n&&typeof n=="object"?(t=n.port,a({port:t,url:`http://127.0.0.1:${t}/callback`})):r(new Error("Failed to get server address"));}),i.on("error",n=>{r(new Error(`Failed to start callback server: ${n.message}`));});})},async waitForCallback(a,r){return s=a,new Promise(n=>{e=n,o=setTimeout(()=>{e&&e({success:false,error:"Login timed out. Please try again."});},r);})},async stop(){if(o&&(clearTimeout(o),o=null),i)return new Promise(a=>{i.close(()=>{i=null,a();});})}}}function Pe(){return ft.randomBytes(32).toString("hex")}function ke(i){return new Promise(t=>{let e=process.platform,o;switch(e){case "darwin":o=`open "${i}"`;break;case "win32":o=`start "" "${i}"`;break;default:o=`xdg-open "${i}"`;break}exec(o,s=>{t(!s);});})}var B=120,gt=process.env.EMAILR_WEB_URL||"https://app.emailr.dev";function wt(i,t){let e=`http://127.0.0.1:${t}/callback`,o=new URLSearchParams({state:i,callback_url:e});return `${gt}/consent/authorize?${o.toString()}`}function Ae(){return new Command("login").description("Log in to Emailr via browser authentication").option("-t, --timeout <seconds>","Timeout in seconds",String(B)).option("--no-browser","Don't automatically open the browser").action(async t=>{await yt({timeout:parseInt(t.timeout,10)||B,noBrowser:t.browser===false});})}async function yt(i){let t=Ue(),e=(i.timeout||B)*1e3;try{f("Starting authentication server...");let{port:o,url:s}=await t.start(),a=Pe(),r=wt(a,o);console.log(""),f("Authorization URL:"),console.log(` ${r}`),console.log(""),i.noBrowser?f("Please open the URL above in your browser to continue."):await ke(r)?f("Browser opened. Please complete authentication in your browser."):(I("Could not open browser automatically."),f("Please open the URL above in your browser to continue.")),console.log(""),f(`Waiting for authentication (timeout: ${i.timeout||B}s)...`);let n=await t.waitForCallback(a,e);n.success&&n.apiKey?(G({apiKey:n.apiKey}),console.log(""),p("Login successful!"),f(`API key saved to: ${N()}`),f("You can now use the Emailr CLI.")):(console.log(""),l(n.error||"Authentication failed."),f("Please try again or use manual configuration:"),console.log(" emailr config set api-key <your-api-key>"),process.exit(1));}catch(o){console.log(""),l(o instanceof Error?o.message:"An unexpected error occurred."),f("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 oe=_.join(V.homedir(),".config","opencode","skills","emailr-cli"),Ot=`---
|
|
2959
2967
|
name: emailr-cli
|
|
2960
2968
|
description: Operate the Emailr CLI to send emails, manage contacts, templates, domains, broadcasts, webhooks, and segments. Includes LIVE PREVIEW editing for templates with hot-reload.
|
|
2961
2969
|
---
|
|
@@ -2995,7 +3003,7 @@ IMPORTANT: Always use \`--background\` flag so the command returns immediately a
|
|
|
2995
3003
|
- Create: \`emailr templates create --name "Name" --subject "Subject" --html-file ./template.html\`
|
|
2996
3004
|
- Update: \`emailr templates update <id> --html-file ./template.html\`
|
|
2997
3005
|
- Delete: \`emailr templates delete <id>\`
|
|
2998
|
-
`;function
|
|
3006
|
+
`;function Et(){try{return execSync("which opencode",{stdio:"ignore"}),!0}catch{return false}}function _t(){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 jt(){O.existsSync(oe)||O.mkdirSync(oe,{recursive:true});let i=_.join(oe,"SKILL.md");O.writeFileSync(i,Ot,"utf-8");}function Me(){return new Command("agent").description(`Launch an AI agent with Emailr CLI expertise
|
|
2999
3007
|
|
|
3000
3008
|
This opens OpenCode (opencode.ai), an AI coding agent that knows how to use all Emailr CLI commands.
|
|
3001
3009
|
The agent can help you:
|
|
@@ -3003,10 +3011,185 @@ The agent can help you:
|
|
|
3003
3011
|
- Manage contacts, broadcasts, and segments
|
|
3004
3012
|
- Configure domains and webhooks
|
|
3005
3013
|
|
|
3006
|
-
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=>{
|
|
3007
|
-
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{
|
|
3014
|
+
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=>{Et()||(t.install?_t()||(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(`
|
|
3015
|
+
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{jt(),p("Emailr CLI skill loaded");}catch(s){I(`Could not install skill: ${s instanceof Error?s.message:String(s)}`);}let e=[];t.model&&e.push("--model",t.model),console.log(`
|
|
3008
3016
|
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.
|
|
3009
|
-
`);let o=spawn("opencode",e,{stdio:"inherit",env:process.env});o.on("error",
|
|
3017
|
+
`);let o=spawn("opencode",e,{stdio:"inherit",env:process.env});o.on("error",s=>{l(`Failed to start agent: ${s.message}`),process.exit(1);}),o.on("exit",s=>{process.exit(s??0);});})}function Fe(){let i=new Command("inbox").description(`Manage inbound emails (inbox)
|
|
3018
|
+
|
|
3019
|
+
USAGE
|
|
3020
|
+
emailr inbox <subcommand> [options]
|
|
3021
|
+
|
|
3022
|
+
DESCRIPTION
|
|
3023
|
+
View and manage received (inbound) emails. List your inbox, read individual
|
|
3024
|
+
emails, view conversation threads, reply to emails, and forward them.
|
|
3025
|
+
|
|
3026
|
+
SUBCOMMANDS
|
|
3027
|
+
list List received emails with pagination and search
|
|
3028
|
+
get <id> View a specific received email in detail
|
|
3029
|
+
thread <id> View the full conversation thread for an email
|
|
3030
|
+
reply <id> Reply to a received email
|
|
3031
|
+
forward <id> Forward a received email to other recipients
|
|
3032
|
+
|
|
3033
|
+
OPTIONS
|
|
3034
|
+
--format <format> Output format: json | table (default: table)
|
|
3035
|
+
|
|
3036
|
+
EXAMPLES
|
|
3037
|
+
# List all received emails
|
|
3038
|
+
emailr inbox list
|
|
3039
|
+
|
|
3040
|
+
# List with pagination
|
|
3041
|
+
emailr inbox list --limit 10 --page 2
|
|
3042
|
+
|
|
3043
|
+
# Search by sender email
|
|
3044
|
+
emailr inbox list --email sender@example.com
|
|
3045
|
+
|
|
3046
|
+
# View a specific email
|
|
3047
|
+
emailr inbox get <email-id>
|
|
3048
|
+
|
|
3049
|
+
# View conversation thread
|
|
3050
|
+
emailr inbox thread <email-id>
|
|
3051
|
+
|
|
3052
|
+
# Reply to an email
|
|
3053
|
+
emailr inbox reply <email-id> --html "<p>Thanks for your message!</p>"
|
|
3054
|
+
|
|
3055
|
+
# Reply from a file
|
|
3056
|
+
emailr inbox reply <email-id> --html-file ./reply.html
|
|
3057
|
+
|
|
3058
|
+
# Forward an email
|
|
3059
|
+
emailr inbox forward <email-id> --to recipient@example.com
|
|
3060
|
+
|
|
3061
|
+
# Forward with a message
|
|
3062
|
+
emailr inbox forward <email-id> --to recipient@example.com --message "FYI"
|
|
3063
|
+
|
|
3064
|
+
SEE ALSO
|
|
3065
|
+
emailr send Send individual emails
|
|
3066
|
+
emailr emails View all emails (sent and received)`);return i.command("list").description(`List received emails
|
|
3067
|
+
|
|
3068
|
+
USAGE
|
|
3069
|
+
emailr inbox list [options]
|
|
3070
|
+
|
|
3071
|
+
DESCRIPTION
|
|
3072
|
+
List all received (inbound) emails with optional search and pagination.
|
|
3073
|
+
|
|
3074
|
+
OPTIONS
|
|
3075
|
+
--limit <count> Number of emails to return (default: 20, max: 100)
|
|
3076
|
+
--page <number> Page number (default: 1)
|
|
3077
|
+
--email <address> Filter by sender email (partial match)
|
|
3078
|
+
--domain <domain> Filter by sender domain
|
|
3079
|
+
--format <format> Output format: json | table (default: table)
|
|
3080
|
+
|
|
3081
|
+
EXAMPLES
|
|
3082
|
+
emailr inbox list
|
|
3083
|
+
emailr inbox list --limit 50 --page 2
|
|
3084
|
+
emailr inbox list --email john@example.com
|
|
3085
|
+
emailr inbox list --domain example.com
|
|
3086
|
+
emailr inbox list --format json
|
|
3087
|
+
|
|
3088
|
+
OUTPUT FORMATS
|
|
3089
|
+
--format json Machine-readable JSON with data array and pagination
|
|
3090
|
+
--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("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=c(),s=await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).emails.list({status:"received",page:parseInt(t.page),limit:Math.min(parseInt(t.limit),100),email:t.email,domain:t.domain});if(t.format==="json")m(s,"json");else {if(!s.data||s.data.length===0){f("No emails in inbox");return}let r=s.data.map(n=>({ID:n.id,From:n.from_email,Subject:De(n.subject||"(no subject)",40),To:n.to_email,Date:re(n.created_at),Attachments:n.attachments?.length||0}));m(r,"table"),f(`Page ${s.pagination.page} of ${s.pagination.pages} (${s.pagination.total} total)`);}}catch(e){l(e instanceof Error?e.message:"Failed to list inbox"),process.exit(1);}}),i.command("get <id>").description(`View a received email
|
|
3091
|
+
|
|
3092
|
+
USAGE
|
|
3093
|
+
emailr inbox get <email-id> [options]
|
|
3094
|
+
|
|
3095
|
+
DESCRIPTION
|
|
3096
|
+
View the full details of a received email including headers, content,
|
|
3097
|
+
and attachment information.
|
|
3098
|
+
|
|
3099
|
+
OPTIONS
|
|
3100
|
+
--content <type> Content to display: preview | text | html (default: preview)
|
|
3101
|
+
--format <format> Output format: json | table (default: table)
|
|
3102
|
+
|
|
3103
|
+
EXAMPLES
|
|
3104
|
+
emailr inbox get abc-123-def
|
|
3105
|
+
emailr inbox get abc-123-def --content html
|
|
3106
|
+
emailr inbox get abc-123-def --content text
|
|
3107
|
+
emailr inbox get abc-123-def --format json
|
|
3108
|
+
|
|
3109
|
+
OUTPUT FORMATS
|
|
3110
|
+
--format json Full email object with all fields as JSON
|
|
3111
|
+
--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 o=c(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.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:re(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 n=a.text_content||a.html_content?.replace(/<[^>]*>/g,"")||"(no content)";console.log(n);}if(a.attachments&&a.attachments.length>0){console.log(""),f("Attachments:");let n=a.attachments.map(d=>({Filename:d.filename,Type:d.contentType||d.content_type||"-",Size:Nt(d.size||0)}));m(n,"table");}}}catch(o){l(o instanceof Error?o.message:"Failed to get email"),process.exit(1);}}),i.command("thread <id>").description(`View conversation thread for an email
|
|
3112
|
+
|
|
3113
|
+
USAGE
|
|
3114
|
+
emailr inbox thread <email-id> [options]
|
|
3115
|
+
|
|
3116
|
+
DESCRIPTION
|
|
3117
|
+
View the full conversation thread for a given email. Shows all emails
|
|
3118
|
+
in the thread ordered chronologically, including both sent and received
|
|
3119
|
+
messages.
|
|
3120
|
+
|
|
3121
|
+
OPTIONS
|
|
3122
|
+
--format <format> Output format: json | table (default: table)
|
|
3123
|
+
|
|
3124
|
+
EXAMPLES
|
|
3125
|
+
emailr inbox thread abc-123-def
|
|
3126
|
+
emailr inbox thread abc-123-def --format json
|
|
3127
|
+
|
|
3128
|
+
OUTPUT FORMATS
|
|
3129
|
+
--format json JSON array of all emails in the thread
|
|
3130
|
+
--format table Chronological conversation view with direction indicators (default)`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=c(),s=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),a=await s.emails.get(t),r=a.thread_id||a.id,n=[],d=new Set;if(n.push(a),d.add(a.id),a.thread_id&&a.thread_id!==a.id)try{let u=await s.emails.get(a.thread_id);d.has(u.id)||(n.push(u),d.add(u.id));}catch{}let h=await s.emails.list({limit:100});if(h.data)for(let u of h.data)d.has(u.id)||(u.thread_id===r||u.parent_email_id===a.id||u.id===a.parent_email_id)&&(n.push(u),d.add(u.id));if(n.sort((u,b)=>new Date(u.created_at).getTime()-new Date(b.created_at).getTime()),e.format==="json")m(n,"json");else {n.length<=1&&f("No other emails in this conversation"),f(`Conversation (${n.length} email${n.length!==1?"s":""}):`),console.log("");for(let u of n){let b=u.status==="received"?"\u2190 IN ":"\u2192 OUT",w=u.id===t?" \u25C0 (selected)":"";console.log(`${b} ${re(u.created_at)}${w}`),console.log(` From: ${u.from_email}`),console.log(` To: ${u.to_email}`),console.log(` Subject: ${u.subject||"(no subject)"}`);let j=u.text_content||u.html_content?.replace(/<[^>]*>/g,"")||"";j&&console.log(` ${De(j.trim(),120)}`),console.log("");}}await new Promise(u=>process.stdout.write("",()=>u())),process.exit(0);}catch(o){l(o instanceof Error?o.message:"Failed to load thread"),process.exit(1);}}),i.command("reply <id>").description(`Reply to a received email
|
|
3131
|
+
|
|
3132
|
+
USAGE
|
|
3133
|
+
emailr inbox reply <email-id> [options]
|
|
3134
|
+
|
|
3135
|
+
DESCRIPTION
|
|
3136
|
+
Send a reply to a received email. The reply is automatically threaded
|
|
3137
|
+
with the original conversation. The To, From, and Subject fields are
|
|
3138
|
+
pre-filled from the original email.
|
|
3139
|
+
|
|
3140
|
+
OPTIONS
|
|
3141
|
+
--html <content> HTML content for the reply body
|
|
3142
|
+
--text <content> Plain text content for the reply body
|
|
3143
|
+
--html-file <path> Read HTML content from a file
|
|
3144
|
+
--text-file <path> Read plain text content from a file
|
|
3145
|
+
--from <email> Override the sender address
|
|
3146
|
+
--cc <emails> CC recipients (comma-separated)
|
|
3147
|
+
--bcc <emails> BCC recipients (comma-separated)
|
|
3148
|
+
--subject <subject> Override the reply subject
|
|
3149
|
+
--format <format> Output format: json | table (default: table)
|
|
3150
|
+
|
|
3151
|
+
EXAMPLES
|
|
3152
|
+
# Reply with inline HTML
|
|
3153
|
+
emailr inbox reply abc-123 --html "<p>Thanks for reaching out!</p>"
|
|
3154
|
+
|
|
3155
|
+
# Reply with plain text
|
|
3156
|
+
emailr inbox reply abc-123 --text "Thanks for reaching out!"
|
|
3157
|
+
|
|
3158
|
+
# Reply from a file
|
|
3159
|
+
emailr inbox reply abc-123 --html-file ./reply.html
|
|
3160
|
+
|
|
3161
|
+
# Reply with CC
|
|
3162
|
+
emailr inbox reply abc-123 --html "<p>See reply</p>" --cc manager@example.com
|
|
3163
|
+
|
|
3164
|
+
OUTPUT FORMATS
|
|
3165
|
+
--format json Machine-readable JSON with message_id and status
|
|
3166
|
+
--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 o=c(),s=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),a=await s.emails.get(t),r=e.html,n=e.text;if(e.htmlFile)try{r=readFileSync(e.htmlFile,"utf-8");}catch{l(`Failed to read HTML file: ${e.htmlFile}`),process.exit(1);}if(e.textFile)try{n=readFileSync(e.textFile,"utf-8");}catch{l(`Failed to read text file: ${e.textFile}`),process.exit(1);}!r&&!n&&(l("Reply content is required. Use --html, --text, --html-file, or --text-file"),process.exit(1));let d=e.subject||(a.subject?.startsWith("Re:")?a.subject:`Re: ${a.subject||""}`),h={to:a.from_email,from:e.from||a.to_email,subject:d,html:r||void 0,text:n||r?.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 b=e.cc.split(",").map(w=>w.trim());h.cc=b.length===1?b[0]:b;}if(e.bcc){let b=e.bcc.split(",").map(w=>w.trim());h.bcc=b.length===1?b[0]:b;}let y=await s.emails.send(h);e.format==="json"?m(y,"json"):(p("Reply sent successfully!"),m({"Message ID":y.message_id,To:a.from_email,Subject:d,Status:y.status},"table")),await new Promise(b=>process.stdout.write("",()=>b())),process.exit(0);}catch(o){l(o instanceof Error?o.message:"Failed to send reply"),process.exit(1);}}),i.command("forward <id>").description(`Forward a received email
|
|
3167
|
+
|
|
3168
|
+
USAGE
|
|
3169
|
+
emailr inbox forward <email-id> --to <recipients> [options]
|
|
3170
|
+
|
|
3171
|
+
DESCRIPTION
|
|
3172
|
+
Forward a received email to one or more recipients. The original email
|
|
3173
|
+
content is included in the forwarded message.
|
|
3174
|
+
|
|
3175
|
+
OPTIONS
|
|
3176
|
+
--to <emails> Recipient email addresses (comma-separated, required)
|
|
3177
|
+
--message <text> Optional message to include above the forwarded content
|
|
3178
|
+
--format <format> Output format: json | table (default: table)
|
|
3179
|
+
|
|
3180
|
+
EXAMPLES
|
|
3181
|
+
# Forward to a single recipient
|
|
3182
|
+
emailr inbox forward abc-123 --to colleague@example.com
|
|
3183
|
+
|
|
3184
|
+
# Forward to multiple recipients
|
|
3185
|
+
emailr inbox forward abc-123 --to "a@example.com,b@example.com"
|
|
3186
|
+
|
|
3187
|
+
# Forward with a note
|
|
3188
|
+
emailr inbox forward abc-123 --to colleague@example.com --message "FYI - see below"
|
|
3189
|
+
|
|
3190
|
+
OUTPUT FORMATS
|
|
3191
|
+
--format json Machine-readable JSON with message_id and status
|
|
3192
|
+
--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 o=c(),s=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),a=e.to.split(",").map(d=>d.trim()).filter(Boolean),r=await s.emails.forward({email_id:t,to:a.length===1?a[0]:a,message:e.message});e.format==="json"?m(r,"json"):(p("Email forwarded successfully!"),m({"Message ID":r.message_id,To:a.join(", "),Recipients:r.recipients,Status:r.status},"table")),await new Promise(d=>process.stdout.write("",()=>d())),process.exit(0);}catch(o){l(o instanceof Error?o.message:"Failed to forward email"),process.exit(1);}}),i}function De(i,t){return i.length<=t?i:i.slice(0,t-1)+"\u2026"}function re(i){return new Date(i).toLocaleString()}function Nt(i){return i<1024?i+" B":i<1024*1024?(i/1024).toFixed(1)+" KB":(i/(1024*1024)).toFixed(1)+" MB"}var S=new Command;S.name("emailr").description(`Emailr CLI - Send emails and manage your email infrastructure
|
|
3010
3193
|
|
|
3011
3194
|
USAGE
|
|
3012
3195
|
emailr <command> [subcommand] [options]
|
|
@@ -3018,6 +3201,7 @@ DESCRIPTION
|
|
|
3018
3201
|
|
|
3019
3202
|
COMMANDS
|
|
3020
3203
|
send Send individual emails with HTML/text content or templates
|
|
3204
|
+
inbox View and manage received (inbound) emails
|
|
3021
3205
|
templates Create, edit, preview, and publish email templates
|
|
3022
3206
|
contacts Manage email contacts and their metadata
|
|
3023
3207
|
segments Create and manage contact segments with conditions
|
|
@@ -3055,6 +3239,21 @@ EXAMPLES
|
|
|
3055
3239
|
emailr send --to user@example.com --template tpl_abc123 \\
|
|
3056
3240
|
--template-data '{"name": "John"}'
|
|
3057
3241
|
|
|
3242
|
+
# List received emails in inbox
|
|
3243
|
+
emailr inbox list
|
|
3244
|
+
|
|
3245
|
+
# View a received email
|
|
3246
|
+
emailr inbox get <email-id>
|
|
3247
|
+
|
|
3248
|
+
# View conversation thread
|
|
3249
|
+
emailr inbox thread <email-id>
|
|
3250
|
+
|
|
3251
|
+
# Reply to a received email
|
|
3252
|
+
emailr inbox reply <email-id> --html "<p>Thanks!</p>"
|
|
3253
|
+
|
|
3254
|
+
# Forward a received email
|
|
3255
|
+
emailr inbox forward <email-id> --to colleague@example.com
|
|
3256
|
+
|
|
3058
3257
|
# List all templates
|
|
3059
3258
|
emailr templates list
|
|
3060
3259
|
|
|
@@ -3092,4 +3291,4 @@ AGENTIC WORKFLOW
|
|
|
3092
3291
|
|
|
3093
3292
|
MORE INFORMATION
|
|
3094
3293
|
Run 'emailr <command> --help' for detailed help on any command.
|
|
3095
|
-
Run 'emailr <command> <subcommand> --help' for subcommand details.`).version("1.
|
|
3294
|
+
Run 'emailr <command> <subcommand> --help' for subcommand details.`).version("1.8.0");S.addCommand(de());S.addCommand(Fe());S.addCommand(pe());S.addCommand(_e());S.addCommand(je());S.addCommand(Ne());S.addCommand(Ie());S.addCommand(Ce());S.addCommand(xe());S.addCommand(Ae());S.addCommand(Me());S.parse();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "emailr-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"description": "Command-line interface for the Emailr email API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"chalk": "^5.3.0",
|
|
24
24
|
"cli-table3": "^0.6.3",
|
|
25
25
|
"commander": "^12.0.0",
|
|
26
|
-
"emailr": "^1.3.
|
|
26
|
+
"emailr": "^1.3.4",
|
|
27
27
|
"open": "^11.0.0"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|