emailr-cli 1.8.0 → 1.9.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 +263 -79
- 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 O,{readFileSync}from'fs';import
|
|
2
|
+
import {Command}from'commander';import {Emailr}from'emailr';import O,{readFileSync}from'fs';import X from'os';import E from'path';import ce from'cli-table3';import T from'chalk';import tt from'http';import {URL}from'url';import St from'crypto';import {spawn,execSync,exec}from'child_process';var Be=[E.join(X.homedir(),".emailrrc"),E.join(X.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 Be)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 I(){let i=E.join(X.homedir(),".config","emailr");return E.join(i,"config.json")}function G(i){let t=I(),e=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 r={...o,...i};O.writeFileSync(t,JSON.stringify(r,null,2)+`
|
|
11
|
+
`);}function me(i){try{return c()[i]?.toString()}catch{return}}function m(i,t="table"){t==="json"?console.log(JSON.stringify(i,null,2)):Ve(i);}function Ve(i){Array.isArray(i)?Xe(i):typeof i=="object"&&i!==null?We(i):console.log(i);}function Xe(i){if(i.length===0){console.log(T.gray("No results"));return}let t=i[0];if(typeof t!="object"||t===null){i.forEach(r=>console.log(r));return}let e=Object.keys(t),o=new ce({head:e.map(r=>T.cyan(r)),style:{head:[],border:[]}});for(let r of i){let a=e.map(n=>{let s=r[n];return de(s)});o.push(a);}console.log(o.toString());}function We(i){let t=new ce({style:{head:[],border:[]}});for(let[e,o]of Object.entries(i))t.push([T.cyan(e),de(o)]);console.log(t.toString());}function de(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 N(i){console.warn(T.yellow("\u26A0"),i);}function u(i){console.log(T.blue("\u2139"),i);}function ue(){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=c(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),
|
|
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}),r=t.to.split(",").map(s=>s.trim()),a={to:r.length===1?r[0]:r};if(t.from&&(a.from=t.from),t.subject&&(a.subject=t.subject),t.htmlFile)try{a.html=readFileSync(t.htmlFile,"utf-8");}catch{l(`Failed to read HTML file: ${t.htmlFile}`),process.exit(1);}else t.html&&(a.html=t.html);if(t.textFile)try{a.text=readFileSync(t.textFile,"utf-8");}catch{l(`Failed to read text file: ${t.textFile}`),process.exit(1);}else t.text&&(a.text=t.text);if(t.template&&(a.template_id=t.template),t.templateData)try{a.template_data=JSON.parse(t.templateData);}catch{l("Invalid JSON for --template-data"),process.exit(1);}if(t.cc){let s=t.cc.split(",").map(d=>d.trim());a.cc=s.length===1?s[0]:s;}if(t.bcc){let s=t.bcc.split(",").map(d=>d.trim());a.bcc=s.length===1?s[0]:s;}t.replyTo&&(a.reply_to_email=t.replyTo),t.schedule&&(a.scheduled_at=t.schedule);let n=await o.emails.send(a);t.format==="json"?m(n,"json"):(p("Email sent successfully!"),m({"Message ID":n.message_id,Recipients:n.recipients,Status:n.status,...n.scheduled_at&&{"Scheduled At":n.scheduled_at}},"table"));}catch(e){l(e instanceof Error?e.message:"Failed to send email"),process.exit(1);}})}function fe(){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=c(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),
|
|
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}),r={limit:parseInt(t.limit,10),offset:parseInt(t.offset,10)};if(t.subscribed&&(r.subscribed=!0),t.unsubscribed&&(r.subscribed=!1),t.search&&(r.search=t.search),t.tags){let n=t.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean);n.length>0&&(r.tags=n.join(","));}let a=await o.contacts.list(r);if(t.format==="json")m(a,"json");else {let n=a.contacts.map(s=>({ID:s.id,Email:s.email,Name:[s.first_name,s.last_name].filter(Boolean).join(" ")||"-",Subscribed:s.subscribed,Tags:s.tags?.join(", ")||"-",Created:s.created_at}));m(n,"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
|
|
@@ -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=c(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),
|
|
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}),r={email:t.email};if(t.firstName&&(r.first_name=t.firstName),t.lastName&&(r.last_name=t.lastName),t.subscribed!==void 0&&(r.subscribed=t.subscribed),t.metadata)try{r.metadata=JSON.parse(t.metadata);}catch{l("Invalid JSON for --metadata"),process.exit(1);}t.tags&&(r.tags=t.tags.split(",").map(n=>n.trim().toLowerCase()).filter(Boolean));let a=await o.contacts.create(r);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=c(),
|
|
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(),r=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(s=>s.trim().toLowerCase()).filter(Boolean));let n=await r.contacts.update(t,a);e.format==="json"?m(n,"json"):(p(`Contact updated: ${n.id}`),m(n,"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=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
|
|
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 he(){return E.join(X.homedir(),".config","emailr","templates")}function et(){let i=he();O.existsSync(i)||O.mkdirSync(i,{recursive:true});}function W(i){return E.join(he(),`${i}.html`)}function z(i,t){et();let e=W(i);O.writeFileSync(e,t,"utf-8");}function ge(i){let t=W(i);return O.existsSync(t)?O.readFileSync(t,"utf-8"):null}function we(i){let t=W(i);return O.existsSync(t)}var v=null,P=null,q=false;function Se(i){return i.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function at(i){return i===null||i.trim()===""}function ot(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">${Se(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 ye(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">${Se(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 it(i){let t=i.match(/^\/preview\/([^/]+)$/);return t?t[1]:null}function nt(){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=it(e);if(!o){t.writeHead(404,{"Content-Type":"text/plain"}),t.end("Not Found");return}if(!we(o)){t.writeHead(404,{"Content-Type":"text/html; charset=utf-8"}),t.end(ye(o));return}let r=ge(o);if(r===null){t.writeHead(404,{"Content-Type":"text/html; charset=utf-8"}),t.end(ye(o));return}if(at(r)){t.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),t.end(ot(o));return}t.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),t.end(r);}}var ve={async start(){return q&&P!==null?P:new Promise((i,t)=>{v=tt.createServer(nt()),v.listen(0,"127.0.0.1",()=>{let e=v.address();e&&typeof e=="object"?(P=e.port,q=true,v.unref(),i(P)):t(new Error("Failed to get server address"));}),v.on("error",e=>{q=false,P=null,v=null,t(new Error(`Failed to start preview server: ${e.message}`));});})},getPort(){return P},isRunning(){return q},async stop(){if(v)return new Promise(i=>{v.close(()=>{v=null,P=null,q=false,i();});})}};function Te(){return ve}async function Y(i){try{return `http://127.0.0.1:${await ve.start()}/preview/${i}`}catch{return null}}function Oe(){v&&v.ref();}var A=null,Z=null,B=null,M=[],Ee=`
|
|
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 lt(i){return i.includes("</body>")?i.replace("</body>",`${Ee}</body>`):i+Ee}function mt(){M.forEach(i=>{try{i.write(`data: reload
|
|
570
570
|
|
|
571
|
-
`);}catch{}});}async function
|
|
571
|
+
`);}catch{}});}async function Q(i,t){let e=E.resolve(i);return new Promise((o,r)=>{A=tt.createServer((a,n)=>{if(a.url==="/__live-reload"){n.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive","Access-Control-Allow-Origin":"*"}),n.write(`data: connected
|
|
572
572
|
|
|
573
|
-
`),M.push(
|
|
573
|
+
`),M.push(n),a.on("close",()=>{M=M.filter(s=>s!==n);});return}if(a.method==="GET"){try{let s=O.readFileSync(e,"utf-8"),d=lt(s);n.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),n.end(d);}catch(s){n.writeHead(500,{"Content-Type":"text/plain"}),n.end(`Error reading file: ${s instanceof Error?s.message:String(s)}`);}return}n.writeHead(405,{"Content-Type":"text/plain"}),n.end("Method Not Allowed");}),A.listen(0,"127.0.0.1",()=>{let a=A.address();if(a&&typeof a=="object"){Z=a.port;let n=null;B=O.watch(e,s=>{s==="change"&&(n&&clearTimeout(n),n=setTimeout(()=>{mt(),t?.();},100));}),o(Z);}else r(new Error("Failed to get server address"));}),A.on("error",a=>{r(new Error(`Failed to start server: ${a.message}`));});})}async function ee(){if(B&&(B.close(),B=null),M.forEach(i=>{try{i.end();}catch{}}),M=[],A)return new Promise(i=>{A.close(()=>{A=null,Z=null,i();});})}async function _e(i){try{let t=i.html_content??"";z(i.id,t);}catch(t){return N(`Could not save template for preview: ${t instanceof Error?t.message:String(t)}`),null}try{let t=await Y(i.id);return t===null?(N("Could not start preview server"),null):t}catch(t){return N(`Could not generate preview URL: ${t instanceof Error?t.message:String(t)}`),null}}function je(){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=c(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),
|
|
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}),r={limit:parseInt(t.limit,10),page:parseInt(t.page,10)};if(t.tags){let n=t.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean);n.length>0&&(r.tags=n.join(","));}let a=await o.templates.list(r);if(t.format==="json")m(a,"json");else {let n=a.map(s=>({ID:s.id,Name:s.name,Subject:s.subject,Variables:s.variables?.join(", ")||"-",Tags:s.tags?.join(", ")||"-",Created:s.created_at}));m(n,"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=c(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).templates.get(t),
|
|
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),n=await _e({id:a.id,html_content:a.html_content??void 0}),s=a.preview_html?`${o.baseUrl}/preview/${a.id}`:null;if(e.format==="json")m({...a,preview_url:s??n},"json");else {let d={ID:a.id,Name:a.name,Subject:a.subject,Variables:a.variables?.join(", ")||"-",Created:a.created_at};s?d["Preview URL"]=s:n&&(d["Local Preview"]=n),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]
|
|
@@ -735,7 +735,7 @@ AGENTIC WORKFLOW
|
|
|
735
735
|
1. Fetch: emailr templates fetch <id> --output template.html
|
|
736
736
|
2. Edit locally or with AI assistance
|
|
737
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
|
|
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 n=E.resolve(e.output);O.writeFileSync(n,a,"utf-8"),p(`HTML saved to: ${n}`);}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=c(),
|
|
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(),r=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),a;if(e.htmlFile){let d=E.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 n=await r.templates.pushPreview(t,a),s="updated";e.format==="json"?m({template_id:t,preview_url:n.preview_url,status:s},"json"):(p("Preview uploaded successfully"),m({"Template ID":t,"Preview URL":n.preview_url,Status:s},"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
|
|
@@ -801,6 +801,7 @@ OPTIONS
|
|
|
801
801
|
--from-name <name> Sender display name (e.g. "Acme Inc")
|
|
802
802
|
--reply-to <email_address> Default reply-to email address
|
|
803
803
|
--preview-text <text> Preview text shown in email clients
|
|
804
|
+
--inbox-id <inbox_id> Inbox ID for sender identity defaults
|
|
804
805
|
--tags <tags> Comma-separated tags
|
|
805
806
|
--format <format> Output format: json | table (default: table)
|
|
806
807
|
|
|
@@ -827,7 +828,7 @@ EXAMPLES
|
|
|
827
828
|
|
|
828
829
|
TIP
|
|
829
830
|
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=c(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),
|
|
831
|
+
It creates a local file with hot-reload preview, then use this command to save.`).requiredOption("--name <template_name>","Template name").requiredOption("--subject <subject_line>","Email subject line").option("--html <html_content>","Inline HTML content").option("--text <text_content>","Plain text content").option("--html-file <file_path>","Read HTML content from file").option("--text-file <file_path>","Read text content from file").option("--from <email_address>","Default from email address").option("--from-name <name>","Sender display name").option("--reply-to <email_address>","Default reply-to email address").option("--preview-text <text>","Preview text shown in email clients").option("--inbox-id <inbox_id>","Inbox ID for sender identity defaults").option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format: json | table","table").action(async t=>{try{let e=c(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),r={name:t.name,subject:t.subject};if(t.htmlFile){let s=await import('fs');r.html_content=s.readFileSync(t.htmlFile,"utf-8");}else t.html&&(r.html_content=t.html);if(t.textFile){let s=await import('fs');r.text_content=s.readFileSync(t.textFile,"utf-8");}else t.text&&(r.text_content=t.text);t.from&&(r.from_email=t.from),t.fromName&&(r.from_name=t.fromName),t.replyTo&&(r.reply_to=t.replyTo),t.previewText&&(r.preview_text=t.previewText),t.inboxId&&(r.inbox_id=t.inboxId),t.tags&&(r.tags=t.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean));let a=await o.templates.create(r),n=await _e({id:a.id,html_content:a.html_content??void 0});if(t.format==="json")m({...a,preview_url:n},"json");else {p(`Template created: ${a.id}`);let s={ID:a.id,Name:a.name,Subject:a.subject,Variables:a.variables?.join(", ")||"-",Tags:a.tags?.join(", ")||"-"};n&&(s["Preview URL"]=n),m(s,"table"),n&&console.log(`
|
|
831
832
|
Open the Preview URL in your browser to view the rendered template.`);}}catch(e){l(e instanceof Error?e.message:"Failed to create template"),process.exit(1);}}),i.command("update <template_id>").description(`Update an existing email template
|
|
832
833
|
|
|
833
834
|
USAGE
|
|
@@ -852,6 +853,7 @@ OPTIONS
|
|
|
852
853
|
--from-name <name> New sender display name
|
|
853
854
|
--reply-to <email_address> New default reply-to email address
|
|
854
855
|
--preview-text <text> New preview text
|
|
856
|
+
--inbox-id <inbox_id> Inbox ID for sender identity defaults (use "none" to clear)
|
|
855
857
|
--tags <tags> Comma-separated tags (replaces existing)
|
|
856
858
|
--format <format> Output format: json | table (default: table)
|
|
857
859
|
|
|
@@ -882,7 +884,7 @@ AGENTIC WORKFLOW
|
|
|
882
884
|
2. Edit locally or with AI assistance
|
|
883
885
|
3. Push preview: emailr templates push-preview <id> --html-file template.html
|
|
884
886
|
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=c(),
|
|
887
|
+
5. Publish: emailr templates update <id> --html-file template.html`).option("--name <template_name>","New template name").option("--subject <subject_line>","New email subject line").option("--html <html_content>","New inline HTML content").option("--text <text_content>","New plain text content").option("--html-file <file_path>","Read new HTML content from file").option("--text-file <file_path>","Read new text content from file").option("--from <email_address>","New default from email address").option("--from-name <name>","New sender display name").option("--reply-to <email_address>","New default reply-to email address").option("--preview-text <text>","New preview text").option("--inbox-id <inbox_id>",'Inbox ID for sender identity (use "none" to clear)').option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format: json | table","table").action(async(t,e)=>{try{let o=c(),r=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 s=await import('fs');a.html_content=s.readFileSync(e.htmlFile,"utf-8");}else e.html&&(a.html_content=e.html);if(e.textFile){let s=await import('fs');a.text_content=s.readFileSync(e.textFile,"utf-8");}else e.text&&(a.text_content=e.text);e.from&&(a.from_email=e.from),e.fromName&&(a.from_name=e.fromName),e.replyTo&&(a.reply_to=e.replyTo),e.previewText&&(a.preview_text=e.previewText),e.inboxId&&(a.inbox_id=e.inboxId==="none"?null:e.inboxId),e.tags&&(a.tags=e.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean));let n=await r.templates.update(t,a);if(e.format==="json")m(n,"json");else {p(`Template updated: ${n.id}`);let s={ID:n.id,Name:n.name,Subject:n.subject,Variables:n.variables?.join(", ")||"-",Tags:n.tags?.join(", ")||"-",Updated:n.updated_at};m(s,"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
888
|
|
|
887
889
|
USAGE
|
|
888
890
|
emailr templates delete <template_id>
|
|
@@ -928,17 +930,17 @@ EXAMPLES
|
|
|
928
930
|
|
|
929
931
|
SEE ALSO
|
|
930
932
|
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=c(),
|
|
933
|
+
emailr templates stop-preview Stop background preview server`).option("--no-open","Do not automatically open browser").option("--foreground","Keep process running in foreground (blocks terminal)").action(async(t,e)=>{try{let o=c(),r=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl});console.log(`Fetching template ${t}...`);let a=await r.templates.get(t),n=a.html_content??"";if(z(a.id,n),e.foreground){let g=await Y(a.id);if(g||(l("Failed to start preview server"),process.exit(1)),Oe(),console.log(`
|
|
932
934
|
Template: ${a.name}`),console.log(`Preview URL: ${g}`),e.open!==!1)try{await(await import('open')).default(g),console.log(`
|
|
933
935
|
Browser opened.`);}catch{console.log(`
|
|
934
936
|
Could not open browser automatically. Open the URL above manually.`);}process.on("SIGINT",async()=>{console.log(`
|
|
935
937
|
|
|
936
|
-
Stopping preview server...`),await
|
|
938
|
+
Stopping preview server...`),await Te().stop(),console.log("Done."),process.exit(0);});return}let s=E.join(process.cwd(),`.template-preview-${a.id}.html`);O.writeFileSync(s,n,"utf-8");let{spawn:d}=await import('child_process'),b=await import('os'),S=E.join(b.tmpdir(),"emailr-preview.pid");try{let g=O.readFileSync(S,"utf-8").trim();process.kill(parseInt(g,10),"SIGTERM");}catch{}let f=`
|
|
937
939
|
const http = require('http');
|
|
938
940
|
const fs = require('fs');
|
|
939
941
|
const path = require('path');
|
|
940
942
|
const os = require('os');
|
|
941
|
-
const filePath = ${JSON.stringify(
|
|
943
|
+
const filePath = ${JSON.stringify(s)};
|
|
942
944
|
const pidFile = path.join(os.tmpdir(), 'emailr-preview.pid');
|
|
943
945
|
const portFile = path.join(os.tmpdir(), 'emailr-preview.port');
|
|
944
946
|
const server = http.createServer((req, res) => {
|
|
@@ -958,9 +960,9 @@ Stopping preview server...`),await Se().stop(),console.log("Done."),process.exit
|
|
|
958
960
|
console.log('PORT:' + port);
|
|
959
961
|
});
|
|
960
962
|
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(
|
|
963
|
+
`,h=d("node",["-e",f],{detached:!0,stdio:["ignore","pipe","ignore"]}),w="";await new Promise(g=>{h.stdout?.on("data",j=>{let $=j.toString().match(/PORT:(\d+)/);$&&(w=$[1],g());}),setTimeout(g,3e3);}),h.unref();let _=`http://127.0.0.1:${w}/`;if(console.log(`
|
|
964
|
+
Template: ${a.name}`),console.log(`Preview URL: ${_}`),console.log(`
|
|
965
|
+
To stop: emailr templates stop-preview`),e.open!==!1)try{await(await import('open')).default(_);}catch{}process.exit(0);}catch(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
966
|
|
|
965
967
|
USAGE
|
|
966
968
|
emailr templates edit <template_id> [options]
|
|
@@ -1000,12 +1002,12 @@ EXAMPLES
|
|
|
1000
1002
|
SEE ALSO
|
|
1001
1003
|
emailr templates draft Draft a new template with live preview
|
|
1002
1004
|
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=c(),
|
|
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(
|
|
1005
|
+
emailr templates stop-preview Stop the background preview server`).option("--file <file_path>","Path to save the HTML file for editing","./template.html").option("--no-open","Do not automatically open browser").option("--foreground","Keep process running in foreground (blocks terminal)").action(async(t,e)=>{try{let o=c(),r=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),a=E.resolve(e.file);console.log(`Fetching template ${t}...`);let n=await r.templates.get(t),s=n.html_content??"";if(O.writeFileSync(a,s,"utf-8"),console.log(`Template saved to: ${a}`),e.foreground){let j=`http://127.0.0.1:${await Q(a,()=>{console.log("File changed - browser refreshed");})}/`;if(console.log(`
|
|
1006
|
+
Template: ${n.name}`),console.log(`Template ID: ${n.id}`),console.log(`Live Preview: ${j}`),console.log(`File: ${a}`),console.log(`
|
|
1007
|
+
Watching for changes... Edit the file and see live updates.`),console.log(`When done, run: emailr templates update ${t} --html-file ${e.file}`),e.open!==!1)try{await(await import('open')).default(j);}catch{}process.on("SIGINT",async()=>{console.log(`
|
|
1006
1008
|
|
|
1007
|
-
Stopping live preview server...`),await
|
|
1008
|
-
To save changes: emailr templates update ${t} --html-file ${e.file}`),process.exit(0);});return}let{spawn:d}=await import('child_process'),
|
|
1009
|
+
Stopping live preview server...`),await ee(),console.log("Done."),console.log(`
|
|
1010
|
+
To save changes: emailr templates update ${t} --html-file ${e.file}`),process.exit(0);});return}let{spawn:d}=await import('child_process'),b=await import('os'),S=E.join(b.tmpdir(),"emailr-preview.pid");try{let g=O.readFileSync(S,"utf-8").trim();process.kill(parseInt(g,10),"SIGTERM");}catch{}let f=`
|
|
1009
1011
|
const http = require('http');
|
|
1010
1012
|
const fs = require('fs');
|
|
1011
1013
|
const path = require('path');
|
|
@@ -1045,10 +1047,10 @@ To save changes: emailr templates update ${t} --html-file ${e.file}`),process.ex
|
|
|
1045
1047
|
});
|
|
1046
1048
|
});
|
|
1047
1049
|
process.on('SIGTERM', () => { try { fs.unlinkSync(pidFile); fs.unlinkSync(portFile); } catch {} process.exit(0); });
|
|
1048
|
-
`,
|
|
1049
|
-
Template: ${
|
|
1050
|
+
`,h=d("node",["-e",f],{detached:!0,stdio:["ignore","pipe","ignore"]}),w="";await new Promise(g=>{h.stdout?.on("data",j=>{let le=j.toString().match(/PORT:(\d+)/);le&&(w=le[1],g());}),setTimeout(g,3e3);}),h.unref();let _=`http://127.0.0.1:${w}/`;if(console.log(`
|
|
1051
|
+
Template: ${n.name}`),console.log(`Template ID: ${n.id}`),console.log(`Live Preview: ${_}`),console.log(`File: ${a}`),console.log(`
|
|
1050
1052
|
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(
|
|
1053
|
+
When done:`),console.log(` emailr templates update ${t} --html-file ${e.file}`),console.log(" emailr templates stop-preview"),e.open!==!1)try{await(await import('open')).default(_);}catch{}process.exit(0);}catch(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
1054
|
|
|
1053
1055
|
USAGE
|
|
1054
1056
|
emailr templates draft [options]
|
|
@@ -1090,7 +1092,7 @@ EXAMPLES
|
|
|
1090
1092
|
SEE ALSO
|
|
1091
1093
|
emailr templates edit Edit an existing template with live preview
|
|
1092
1094
|
emailr templates create Create the template from your draft
|
|
1093
|
-
emailr templates stop-preview Stop the background preview server`).option("--file <file_path>","Path to save the HTML file for drafting","./new-template.html").option("--no-open","Do not automatically open browser").option("--blank","Start with a blank file instead of starter template").option("--foreground","Keep process running in foreground (blocks terminal)").action(async t=>{try{let e=
|
|
1095
|
+
emailr templates stop-preview Stop the background preview server`).option("--file <file_path>","Path to save the HTML file for drafting","./new-template.html").option("--no-open","Do not automatically open browser").option("--blank","Start with a blank file instead of starter template").option("--foreground","Keep process running in foreground (blocks terminal)").action(async t=>{try{let e=E.resolve(t.file),o;if(t.blank?o="":o=`<!DOCTYPE html>
|
|
1094
1096
|
<html>
|
|
1095
1097
|
<head>
|
|
1096
1098
|
<meta charset="UTF-8">
|
|
@@ -1125,13 +1127,13 @@ SEE ALSO
|
|
|
1125
1127
|
<p><a href="{{unsubscribe_link}}">Unsubscribe</a></p>
|
|
1126
1128
|
</div>
|
|
1127
1129
|
</body>
|
|
1128
|
-
</html>`,O.writeFileSync(e,o,"utf-8"),console.log(`Template draft created: ${e}`),t.foreground){let
|
|
1129
|
-
Live Preview: ${
|
|
1130
|
+
</html>`,O.writeFileSync(e,o,"utf-8"),console.log(`Template draft created: ${e}`),t.foreground){let h=`http://127.0.0.1:${await Q(e,()=>{console.log("File changed - browser refreshed");})}/`;if(console.log(`
|
|
1131
|
+
Live Preview: ${h}`),console.log(`File: ${e}`),console.log(`
|
|
1130
1132
|
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(
|
|
1133
|
+
When done, create the template:`),console.log(` emailr templates create --name "Template Name" --subject "Email Subject" --html-file ${t.file}`),t.open!==!1)try{await(await import('open')).default(h);}catch{}process.on("SIGINT",async()=>{console.log(`
|
|
1132
1134
|
|
|
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:
|
|
1135
|
+
Stopping live preview server...`),await ee(),console.log("Done."),console.log(`
|
|
1136
|
+
To create template: emailr templates create --name "Template Name" --subject "Email Subject" --html-file ${t.file}`),process.exit(0);});return}let{spawn:r}=await import('child_process'),a=await import('os'),n=E.join(a.tmpdir(),"emailr-preview.pid");try{let f=O.readFileSync(n,"utf-8").trim();process.kill(parseInt(f,10),"SIGTERM");}catch{}let s=`
|
|
1135
1137
|
const http = require('http');
|
|
1136
1138
|
const fs = require('fs');
|
|
1137
1139
|
const path = require('path');
|
|
@@ -1171,10 +1173,10 @@ To create template: emailr templates create --name "Template Name" --subject "Em
|
|
|
1171
1173
|
});
|
|
1172
1174
|
});
|
|
1173
1175
|
process.on('SIGTERM', () => { try { fs.unlinkSync(pidFile); fs.unlinkSync(portFile); } catch {} process.exit(0); });
|
|
1174
|
-
`,d=
|
|
1175
|
-
Live Preview: ${
|
|
1176
|
+
`,d=r("node",["-e",s],{detached:!0,stdio:["ignore","pipe","ignore"]}),b="";await new Promise(f=>{d.stdout?.on("data",h=>{let w=h.toString().match(/PORT:(\d+)/);w&&(b=w[1],f());}),setTimeout(f,3e3);}),d.unref();let S=`http://127.0.0.1:${b}/`;if(console.log(`
|
|
1177
|
+
Live Preview: ${S}`),console.log(`File: ${e}`),console.log(`
|
|
1176
1178
|
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(
|
|
1179
|
+
When done:`),console.log(` emailr templates create --name "Template Name" --subject "Email Subject" --html-file ${t.file}`),console.log(" emailr templates stop-preview"),t.open!==!1)try{await(await import('open')).default(S);}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
1180
|
|
|
1179
1181
|
USAGE
|
|
1180
1182
|
emailr templates stop-preview
|
|
@@ -1191,7 +1193,7 @@ EXAMPLES
|
|
|
1191
1193
|
SEE ALSO
|
|
1192
1194
|
emailr templates edit Start live editing session
|
|
1193
1195
|
emailr templates draft Start live drafting session
|
|
1194
|
-
emailr templates preview Preview a template in browser`).action(async()=>{let t=await import('os'),e=
|
|
1196
|
+
emailr templates preview Preview a template in browser`).action(async()=>{let t=await import('os'),e=E.join(t.tmpdir(),"emailr-preview.pid");try{let 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 Ie(){let i=new Command("domains").description(`Manage sending domains
|
|
1195
1197
|
|
|
1196
1198
|
USAGE
|
|
1197
1199
|
emailr domains <subcommand> [options]
|
|
@@ -1299,7 +1301,7 @@ EXAMPLES
|
|
|
1299
1301
|
emailr domains list --format json | jq '.[] | select(.status == "verified")'
|
|
1300
1302
|
|
|
1301
1303
|
# Count domains
|
|
1302
|
-
emailr domains list --format json | jq 'length'`).option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=c(),
|
|
1304
|
+
emailr domains list --format json | jq 'length'`).option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=c(),r=await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).domains.list();if(t.format==="json")m(r,"json");else {let a=r.map(n=>({ID:n.id,Domain:n.domain,Status:n.status,DKIM:n.dkim_verified,SPF:n.spf_verified,DMARC:n.dmarc_verified,Created:n.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
1305
|
|
|
1304
1306
|
USAGE
|
|
1305
1307
|
emailr domains get <domain_id> [options]
|
|
@@ -1379,7 +1381,7 @@ NEXT STEPS
|
|
|
1379
1381
|
1. Copy the DNS records shown in the output
|
|
1380
1382
|
2. Add them to your DNS provider (Cloudflare, Route53, etc.)
|
|
1381
1383
|
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=c(),
|
|
1384
|
+
4. Run: emailr domains verify <domain_id>`).option("--receiving-subdomain <subdomain>","Subdomain for receiving emails").option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=c(),r=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),a={domain:t};e.receivingSubdomain&&(a.receivingSubdomain=e.receivingSubdomain);let n=await r.domains.add(a);if(e.format==="json")m(n,"json");else {if(p(`Domain added: ${n.domain}`),u("Add the following DNS records to verify your domain:"),console.log(""),n.dns_records){let s=[{Type:"DKIM",...te(n.dns_records.dkim)},{Type:"SPF",...te(n.dns_records.spf)},{Type:"DMARC",...te(n.dns_records.dmarc)}];m(s,"table");}console.log(""),u(`Run 'emailr domains verify ${n.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
1385
|
|
|
1384
1386
|
USAGE
|
|
1385
1387
|
emailr domains verify <domain_id> [options]
|
|
@@ -1417,7 +1419,7 @@ TROUBLESHOOTING
|
|
|
1417
1419
|
1. Run 'check-dns' to see which records are missing
|
|
1418
1420
|
2. Verify records are correctly configured with your DNS provider
|
|
1419
1421
|
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=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!"):(
|
|
1422
|
+
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!"):(u(`Domain status: ${a.status}`),a.dkim_status&&u(`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
1423
|
|
|
1422
1424
|
USAGE
|
|
1423
1425
|
emailr domains check-dns <domain_id> [options]
|
|
@@ -1464,7 +1466,7 @@ COMMON ISSUES
|
|
|
1464
1466
|
|
|
1465
1467
|
Multiple records found:
|
|
1466
1468
|
- 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=c(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).domains.checkDns(t);if(e.format==="json")m(a,"json");else {let
|
|
1469
|
+
- 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 n=Object.entries(a).map(([s,d])=>({Record:s,Verified:d.verified,Expected:d.expected||"-",Found:d.found?.join(", ")||"-"}));m(n,"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
1470
|
|
|
1469
1471
|
USAGE
|
|
1470
1472
|
emailr domains delete <domain_id> [options]
|
|
@@ -1494,7 +1496,7 @@ WARNING
|
|
|
1494
1496
|
This action is permanent and cannot be undone.
|
|
1495
1497
|
- Emails from this domain will fail to send
|
|
1496
1498
|
- 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=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
|
|
1499
|
+
- Re-add the domain if you need to restore functionality`).option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=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 te(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 Ne(){let i=new Command("config").description(`Manage CLI configuration
|
|
1498
1500
|
|
|
1499
1501
|
USAGE
|
|
1500
1502
|
emailr config <subcommand> [options]
|
|
@@ -1587,7 +1589,7 @@ EXAMPLES
|
|
|
1587
1589
|
|
|
1588
1590
|
NOTE
|
|
1589
1591
|
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"],
|
|
1592
|
+
over config file values at runtime.`).action(async(t,e)=>{try{let o=["api-key","base-url","format"],r=t.toLowerCase();o.includes(r)||(l(`Invalid config key: ${t}`),u(`Valid keys: ${o.join(", ")}`),process.exit(1));let n={"api-key":"apiKey","base-url":"baseUrl",format:"format"}[r];r==="format"&&!["json","table"].includes(e)&&(l(`Invalid format value: ${e}`),u("Valid formats: json, table"),process.exit(1)),G({[n]:e}),p(`Configuration saved: ${t} = ${r==="api-key"?"***":e}`),u(`Config file: ${I()}`);}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
1593
|
|
|
1592
1594
|
USAGE
|
|
1593
1595
|
emailr config get <key>
|
|
@@ -1615,7 +1617,7 @@ EXAMPLES
|
|
|
1615
1617
|
emailr config get format
|
|
1616
1618
|
|
|
1617
1619
|
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}`),
|
|
1620
|
+
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}`),u(`Valid keys: ${e.join(", ")}`),process.exit(1));let a={"api-key":"apiKey","base-url":"baseUrl",format:"format"}[o],n=me(a);n?console.log(o==="api-key"?n.substring(0,8)+"..."+n.substring(n.length-4):n):u(`${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
1621
|
|
|
1620
1622
|
USAGE
|
|
1621
1623
|
emailr config list [options]
|
|
@@ -1643,7 +1645,7 @@ EXAMPLES
|
|
|
1643
1645
|
|
|
1644
1646
|
SEE ALSO
|
|
1645
1647
|
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=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
|
|
1648
|
+
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 r=Object.entries(o).map(([a,n])=>({Key:a,Value:n}));m(r,"table");}console.log(""),u(`Config file: ${I()}`);}catch(e){e instanceof Error&&e.message.includes("No API key configured")?(u("No configuration found."),u("Run 'emailr config set api-key <your-api-key>' to get started.")):(l(e instanceof Error?e.message:"Failed to list configuration"),process.exit(1));}}),i.command("path").description(`Show the configuration file path
|
|
1647
1649
|
|
|
1648
1650
|
USAGE
|
|
1649
1651
|
emailr config path
|
|
@@ -1670,7 +1672,7 @@ EXAMPLES
|
|
|
1670
1672
|
open $(emailr config path)
|
|
1671
1673
|
|
|
1672
1674
|
# View config file contents
|
|
1673
|
-
cat $(emailr config path)`).action(()=>{console.log(
|
|
1675
|
+
cat $(emailr config path)`).action(()=>{console.log(I());}),i.command("init").description(`Initialize configuration interactively
|
|
1674
1676
|
|
|
1675
1677
|
USAGE
|
|
1676
1678
|
emailr config init [options]
|
|
@@ -1703,7 +1705,7 @@ ALTERNATIVE: ENVIRONMENT VARIABLES
|
|
|
1703
1705
|
|
|
1704
1706
|
SEE ALSO
|
|
1705
1707
|
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}),p("Configuration initialized!"),
|
|
1708
|
+
emailr config list View current configuration`).option("--api-key <key>","API key to use").option("--base-url <url>","Base URL for API").action(async t=>{try{t.apiKey?(G({apiKey:t.apiKey,baseUrl:t.baseUrl}),p("Configuration initialized!"),u(`Config file: ${I()}`)):(u("Initialize your Emailr CLI configuration:"),console.log(""),u("Run with --api-key flag:"),console.log(" emailr config init --api-key <your-api-key>"),console.log(""),u("Or set environment variable:"),console.log(" export EMAILR_API_KEY=<your-api-key>"));}catch(e){l(e instanceof Error?e.message:"Failed to initialize configuration"),process.exit(1);}}),i}function Ce(){let i=new Command("broadcasts").description(`Manage broadcast campaigns
|
|
1707
1709
|
|
|
1708
1710
|
USAGE
|
|
1709
1711
|
emailr broadcasts <subcommand> [options]
|
|
@@ -1853,7 +1855,7 @@ EXAMPLES
|
|
|
1853
1855
|
emailr broadcasts list --format json
|
|
1854
1856
|
|
|
1855
1857
|
# 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=c(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),
|
|
1858
|
+
emailr broadcasts list --format json | jq '.[] | select(.status == "scheduled")'`).option("--status <status>","Filter by status (draft, scheduled, sending, sent)").option("--limit <number>","Number of broadcasts to return","20").option("--tags <tags>","Filter by tags (comma-separated)").option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=c(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),r={status:t.status,limit:parseInt(t.limit)};if(t.tags){let n=t.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean);n.length>0&&(r.tags=n.join(","));}let a=await o.broadcasts.list(r);if(t.format==="json")m(a,"json");else {if(a.length===0){console.log("No broadcasts found.");return}let n=a.map(s=>({ID:s.id,Name:s.name,Subject:s.subject.substring(0,30)+(s.subject.length>30?"...":""),Status:s.status,Tags:s.tags?.join(", ")||"-",Recipients:s.total_recipients||0,Sent:s.sent_count||0,Created:new Date(s.created_at).toLocaleDateString()}));m(n,"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
1859
|
|
|
1858
1860
|
USAGE
|
|
1859
1861
|
emailr broadcasts get <broadcast_id> [options]
|
|
@@ -1904,6 +1906,7 @@ OPTIONS
|
|
|
1904
1906
|
--from-name <name> Sender display name (e.g. "Acme Inc")
|
|
1905
1907
|
--reply-to <email> Reply-To email address
|
|
1906
1908
|
--preview-text <text> Preview text (preheader) shown in email clients
|
|
1909
|
+
--inbox-id <inbox_id> Inbox ID for sender identity defaults
|
|
1907
1910
|
--template <template_id> Template ID to use for content
|
|
1908
1911
|
--segment <segment_id> Segment ID to target recipients
|
|
1909
1912
|
--html <html_content> Inline HTML content (alternative to --template)
|
|
@@ -1968,7 +1971,7 @@ EXAMPLES
|
|
|
1968
1971
|
|
|
1969
1972
|
SEE ALSO
|
|
1970
1973
|
emailr templates Create and manage email templates
|
|
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}),
|
|
1974
|
+
emailr segments Create and manage contact segments`).requiredOption("--name <name>","Broadcast name").requiredOption("--subject <subject>","Email subject").requiredOption("--from <email>","Sender email address").option("--from-name <name>","Sender display name").option("--reply-to <email>","Reply-To email address").option("--preview-text <text>","Preview text (preheader)").option("--inbox-id <inbox_id>","Inbox ID for sender identity defaults").option("--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}),r={name:t.name,subject:t.subject,from_email:t.from,from_name:t.fromName,reply_to:t.replyTo,preview_text:t.previewText,inbox_id:t.inboxId,template_id:t.template,segment_id:t.segment,html_content:t.html,text_content:t.text,scheduled_at:t.schedule};t.tags&&(r.tags=t.tags.split(",").map(n=>n.trim().toLowerCase()).filter(Boolean));let a=await o.broadcasts.create(r);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
|
|
1972
1975
|
|
|
1973
1976
|
USAGE
|
|
1974
1977
|
emailr broadcasts send <broadcast_id> [options]
|
|
@@ -2098,6 +2101,7 @@ OPTIONS
|
|
|
2098
2101
|
--from-name <name> Update sender display name
|
|
2099
2102
|
--reply-to <email> Update Reply-To email address
|
|
2100
2103
|
--preview-text <text> Update preview text (preheader)
|
|
2104
|
+
--inbox-id <inbox_id> Update inbox ID for sender identity defaults (use "none" to clear)
|
|
2101
2105
|
--template <id> Update template ID (use "none" to clear)
|
|
2102
2106
|
--segment <id> Update segment ID (use "none" to clear)
|
|
2103
2107
|
--topic <id> Update topic ID (use "none" to clear)
|
|
@@ -2131,7 +2135,7 @@ EXAMPLES
|
|
|
2131
2135
|
emailr broadcasts update brd_abc123 --name "Updated" --format json
|
|
2132
2136
|
|
|
2133
2137
|
NOTE
|
|
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(),
|
|
2138
|
+
Only broadcasts in 'draft' or 'scheduled' status can be updated.`).option("--name <name>","Broadcast name").option("--subject <subject>","Email subject").option("--from <email>","Sender email address").option("--from-name <name>","Sender display name").option("--reply-to <email>","Reply-To email address").option("--preview-text <text>","Preview text (preheader)").option("--inbox-id <inbox_id>",'Inbox ID for sender identity (use "none" to clear)').option("--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(),r=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.inboxId&&(a.inbox_id=e.inboxId==="none"?null:e.inboxId),e.template&&(a.template_id=e.template==="none"?null:e.template),e.segment&&(a.segment_id=e.segment==="none"?null:e.segment),e.topic&&(a.topic_id=e.topic==="none"?null:e.topic),e.schedule&&(a.scheduled_at=e.schedule==="none"?null:e.schedule),e.tags&&(a.tags=e.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean)),Object.keys(a).length===0&&(l("No update fields specified. Use --help to see available options."),process.exit(1));let n=await r.broadcasts.update(t,a);e.format==="json"?m(n,"json"):(p("Broadcast updated successfully!"),m({ID:n.id,Name:n.name,Subject:n.subject,Status:n.status,Tags:n.tags?.join(", ")||"-","Scheduled At":n.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
|
|
2135
2139
|
|
|
2136
2140
|
USAGE
|
|
2137
2141
|
emailr broadcasts delete <broadcast_id> [options]
|
|
@@ -2159,7 +2163,7 @@ EXAMPLES
|
|
|
2159
2163
|
|
|
2160
2164
|
WARNING
|
|
2161
2165
|
This action is permanent and cannot be undone.
|
|
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
|
|
2166
|
+
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 Ue(){let i=new Command("webhooks").description(`Manage webhooks
|
|
2163
2167
|
|
|
2164
2168
|
USAGE
|
|
2165
2169
|
emailr webhooks <subcommand> [options]
|
|
@@ -2312,7 +2316,7 @@ EXAMPLES
|
|
|
2312
2316
|
emailr webhooks list --format json | jq '.[] | select(.active == true)'
|
|
2313
2317
|
|
|
2314
2318
|
# Count webhooks
|
|
2315
|
-
emailr webhooks list --format json | jq 'length'`).option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=c(),
|
|
2319
|
+
emailr webhooks list --format json | jq 'length'`).option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=c(),r=await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).webhooks.list();if(t.format==="json")m(r,"json");else {if(r.data.length===0){console.log("No webhooks found.");return}let a=r.data.map(n=>({ID:n.id,Name:n.name,URL:n.url.substring(0,40)+(n.url.length>40?"...":""),Events:n.events.join(", "),Active:n.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
|
|
2316
2320
|
|
|
2317
2321
|
USAGE
|
|
2318
2322
|
emailr webhooks get <webhook_id> [options]
|
|
@@ -2417,7 +2421,7 @@ EXAMPLES
|
|
|
2417
2421
|
|
|
2418
2422
|
NOTE
|
|
2419
2423
|
Save the webhook secret returned by this command. You'll need it
|
|
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}),
|
|
2424
|
+
to verify webhook signatures in your endpoint.`).requiredOption("--name <name>","Webhook name").requiredOption("--url <url>","Webhook URL").requiredOption("--events <events>","Events to subscribe to (comma-separated)").option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=c(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),r=t.events.split(",").map(n=>n.trim()),a=await o.webhooks.create({name:t.name,url:t.url,events:r});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
|
|
2421
2425
|
|
|
2422
2426
|
USAGE
|
|
2423
2427
|
emailr webhooks update <webhook_id> [options]
|
|
@@ -2462,7 +2466,7 @@ EXAMPLES
|
|
|
2462
2466
|
--events "email.delivered,email.bounced"
|
|
2463
2467
|
|
|
2464
2468
|
# Get JSON output
|
|
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(),
|
|
2469
|
+
emailr webhooks update whk_abc123 --name "New Name" --format json`).option("--name <name>","New webhook name").option("--url <url>","New webhook URL").option("--events <events>","New events (comma-separated)").option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=c(),r=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(s=>s.trim()));let n=await r.webhooks.update(t,a);e.format==="json"?m(n,"json"):(p("Webhook updated successfully!"),m({ID:n.id,Name:n.name,URL:n.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
|
|
2466
2470
|
|
|
2467
2471
|
USAGE
|
|
2468
2472
|
emailr webhooks enable <webhook_id> [options]
|
|
@@ -2543,7 +2547,7 @@ EXAMPLES
|
|
|
2543
2547
|
|
|
2544
2548
|
WARNING
|
|
2545
2549
|
This action is permanent and cannot be undone.
|
|
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
|
|
2550
|
+
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 Pe(){let i=new Command("segments").description(`Manage contact segments
|
|
2547
2551
|
|
|
2548
2552
|
USAGE
|
|
2549
2553
|
emailr segments <subcommand> [options]
|
|
@@ -2683,7 +2687,7 @@ EXAMPLES
|
|
|
2683
2687
|
emailr segments list --format json
|
|
2684
2688
|
|
|
2685
2689
|
# Pipe JSON to jq for processing
|
|
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}),
|
|
2690
|
+
emailr segments list --format json | jq '.[].name'`).option("--tags <tags>","Filter by tags (comma-separated)").option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=c(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),r={};if(t.tags){let n=t.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean);n.length>0&&(r.tags=n.join(","));}let a=await o.segments.list(r);if(t.format==="json")m(a,"json");else {if(a.length===0){console.log("No segments found.");return}let n=a.map(s=>({ID:s.id,Name:s.name,Description:(s.description||"").substring(0,30)+((s.description?.length||0)>30?"...":""),Tags:s.tags?.join(", ")||"-","Created At":new Date(s.created_at).toLocaleDateString()}));m(n,"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
|
|
2687
2691
|
|
|
2688
2692
|
USAGE
|
|
2689
2693
|
emailr segments get <segment_id> [options]
|
|
@@ -2760,7 +2764,7 @@ EXAMPLES
|
|
|
2760
2764
|
# Get JSON output for scripting
|
|
2761
2765
|
emailr segments create --name "Test" \\
|
|
2762
2766
|
--conditions '[{"field": "subscribed", "operator": "equals", "value": true}]' \\
|
|
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}),
|
|
2767
|
+
--format json`).requiredOption("--name <name>","Segment name").requiredOption("--conditions <json>","Segment conditions as JSON").option("--description <description>","Segment description").option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=c(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),r;try{r=JSON.parse(t.conditions);}catch{l("Invalid JSON for --conditions"),process.exit(1);}let a={name:t.name,description:t.description,conditions:r};t.tags&&(a.tags=t.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean));let n=await o.segments.create(a);t.format==="json"?m(n,"json"):(p("Segment created successfully!"),m({ID:n.id,Name:n.name,Tags:n.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
|
|
2764
2768
|
|
|
2765
2769
|
USAGE
|
|
2766
2770
|
emailr segments update <segment_id> [options]
|
|
@@ -2806,7 +2810,7 @@ EXAMPLES
|
|
|
2806
2810
|
--conditions '[{"field": "metadata.plan", "operator": "equals", "value": "enterprise"}]'
|
|
2807
2811
|
|
|
2808
2812
|
# Get JSON output
|
|
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(),
|
|
2813
|
+
emailr segments update seg_abc123 --name "Updated" --format json`).option("--name <name>","New segment name").option("--description <description>","New description").option("--conditions <json>","New conditions as JSON").option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=c(),r=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(s=>s.trim().toLowerCase()).filter(Boolean));let n=await r.segments.update(t,a);e.format==="json"?m(n,"json"):(p("Segment updated successfully!"),m({ID:n.id,Name:n.name,Tags:n.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
|
|
2810
2814
|
|
|
2811
2815
|
USAGE
|
|
2812
2816
|
emailr segments delete <segment_id>
|
|
@@ -2862,7 +2866,7 @@ EXAMPLES
|
|
|
2862
2866
|
|
|
2863
2867
|
TIP
|
|
2864
2868
|
Use this before sending broadcasts to verify your segment
|
|
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
|
|
2869
|
+
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 wt(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 yt(){return `<!DOCTYPE html>
|
|
2866
2870
|
<html lang="en">
|
|
2867
2871
|
<head>
|
|
2868
2872
|
<meta charset="UTF-8">
|
|
@@ -2908,7 +2912,7 @@ TIP
|
|
|
2908
2912
|
<p>You can close this window and return to your terminal.</p>
|
|
2909
2913
|
</div>
|
|
2910
2914
|
</body>
|
|
2911
|
-
</html>`}function
|
|
2915
|
+
</html>`}function ae(i){return `<!DOCTYPE html>
|
|
2912
2916
|
<html lang="en">
|
|
2913
2917
|
<head>
|
|
2914
2918
|
<meta charset="UTF-8">
|
|
@@ -2963,7 +2967,7 @@ TIP
|
|
|
2963
2967
|
<p style="margin-top: 1rem;">Please close this window and try again.</p>
|
|
2964
2968
|
</div>
|
|
2965
2969
|
</body>
|
|
2966
|
-
</html>`}function
|
|
2970
|
+
</html>`}function Ae(){let i=null,t=0,e=null,o=null,r=null;return {async start(){return new Promise((a,n)=>{i=tt.createServer((s,d)=>{if(s.method!=="GET"||!s.url?.startsWith("/callback")){d.writeHead(404,{"Content-Type":"text/plain"}),d.end("Not Found");return}let b=wt(s.url);if(r&&b.state!==r){d.writeHead(400,{"Content-Type":"text/html"}),d.end(ae("Security verification failed. State parameter mismatch.")),e&&e({success:false,error:"State parameter mismatch"});return}if(b.error){let f=b.message||b.error;d.writeHead(200,{"Content-Type":"text/html"}),d.end(ae(f)),e&&e({success:false,error:f});return}let S=b.key||b.code;if(S){d.writeHead(200,{"Content-Type":"text/html"}),d.end(yt()),e&&e({success:true,apiKey:S});return}d.writeHead(400,{"Content-Type":"text/html"}),d.end(ae("Invalid callback: missing required parameters.")),e&&e({success:false,error:"Invalid callback: missing required parameters"});}),i.listen(0,"127.0.0.1",()=>{let s=i.address();s&&typeof s=="object"?(t=s.port,a({port:t,url:`http://127.0.0.1:${t}/callback`})):n(new Error("Failed to get server address"));}),i.on("error",s=>{n(new Error(`Failed to start callback server: ${s.message}`));});})},async waitForCallback(a,n){return r=a,new Promise(s=>{e=s,o=setTimeout(()=>{e&&e({success:false,error:"Login timed out. Please try again."});},n);})},async stop(){if(o&&(clearTimeout(o),o=null),i)return new Promise(a=>{i.close(()=>{i=null,a();});})}}}function ke(){return St.randomBytes(32).toString("hex")}function Re(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,r=>{t(!r);});})}var V=120,Ot=process.env.EMAILR_WEB_URL||"https://app.emailr.dev";function xt(i,t){let e=`http://127.0.0.1:${t}/callback`,o=new URLSearchParams({state:i,callback_url:e});return `${Ot}/consent/authorize?${o.toString()}`}function Me(){return new Command("login").description("Log in to Emailr via browser authentication").option("-t, --timeout <seconds>","Timeout in seconds",String(V)).option("--no-browser","Don't automatically open the browser").action(async t=>{await Et({timeout:parseInt(t.timeout,10)||V,noBrowser:t.browser===false});})}async function Et(i){let t=Ae(),e=(i.timeout||V)*1e3;try{u("Starting authentication server...");let{port:o,url:r}=await t.start(),a=ke(),n=xt(a,o);console.log(""),u("Authorization URL:"),console.log(` ${n}`),console.log(""),i.noBrowser?u("Please open the URL above in your browser to continue."):await Re(n)?u("Browser opened. Please complete authentication in your browser."):(N("Could not open browser automatically."),u("Please open the URL above in your browser to continue.")),console.log(""),u(`Waiting for authentication (timeout: ${i.timeout||V}s)...`);let s=await t.waitForCallback(a,e);s.success&&s.apiKey?(G({apiKey:s.apiKey}),console.log(""),p("Login successful!"),u(`API key saved to: ${I()}`),u("You can now use the Emailr CLI.")):(console.log(""),l(s.error||"Authentication failed."),u("Please try again or use manual configuration:"),console.log(" emailr config set api-key <your-api-key>"),process.exit(1));}catch(o){console.log(""),l(o instanceof Error?o.message:"An unexpected error occurred."),u("Please try again or use manual configuration:"),console.log(" emailr config set api-key <your-api-key>"),process.exit(1);}finally{await t.stop();}}var ie=E.join(X.homedir(),".config","opencode","skills","emailr-cli"),Nt=`---
|
|
2967
2971
|
name: emailr-cli
|
|
2968
2972
|
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.
|
|
2969
2973
|
---
|
|
@@ -3003,7 +3007,7 @@ IMPORTANT: Always use \`--background\` flag so the command returns immediately a
|
|
|
3003
3007
|
- Create: \`emailr templates create --name "Name" --subject "Subject" --html-file ./template.html\`
|
|
3004
3008
|
- Update: \`emailr templates update <id> --html-file ./template.html\`
|
|
3005
3009
|
- Delete: \`emailr templates delete <id>\`
|
|
3006
|
-
`;function
|
|
3010
|
+
`;function Ct(){try{return execSync("which opencode",{stdio:"ignore"}),!0}catch{return false}}function Ut(){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 Pt(){O.existsSync(ie)||O.mkdirSync(ie,{recursive:true});let i=E.join(ie,"SKILL.md");O.writeFileSync(i,Nt,"utf-8");}function Le(){return new Command("agent").description(`Launch an AI agent with Emailr CLI expertise
|
|
3007
3011
|
|
|
3008
3012
|
This opens OpenCode (opencode.ai), an AI coding agent that knows how to use all Emailr CLI commands.
|
|
3009
3013
|
The agent can help you:
|
|
@@ -3011,10 +3015,10 @@ The agent can help you:
|
|
|
3011
3015
|
- Manage contacts, broadcasts, and segments
|
|
3012
3016
|
- Configure domains and webhooks
|
|
3013
3017
|
|
|
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=>{
|
|
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{
|
|
3018
|
+
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=>{Ct()||(t.install?Ut()||(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(`
|
|
3019
|
+
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{Pt(),p("Emailr CLI skill loaded");}catch(r){N(`Could not install skill: ${r instanceof Error?r.message:String(r)}`);}let e=[];t.model&&e.push("--model",t.model),console.log(`
|
|
3016
3020
|
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.
|
|
3017
|
-
`);let o=spawn("opencode",e,{stdio:"inherit",env:process.env});o.on("error",
|
|
3021
|
+
`);let o=spawn("opencode",e,{stdio:"inherit",env:process.env});o.on("error",r=>{l(`Failed to start agent: ${r.message}`),process.exit(1);}),o.on("exit",r=>{process.exit(r??0);});})}function Ke(){let i=new Command("inbox").description(`Manage inbound emails (inbox)
|
|
3018
3022
|
|
|
3019
3023
|
USAGE
|
|
3020
3024
|
emailr inbox <subcommand> [options]
|
|
@@ -3043,6 +3047,9 @@ EXAMPLES
|
|
|
3043
3047
|
# Search by sender email
|
|
3044
3048
|
emailr inbox list --email sender@example.com
|
|
3045
3049
|
|
|
3050
|
+
# Filter by inbox
|
|
3051
|
+
emailr inbox list --inbox-id <inbox-uuid>
|
|
3052
|
+
|
|
3046
3053
|
# View a specific email
|
|
3047
3054
|
emailr inbox get <email-id>
|
|
3048
3055
|
|
|
@@ -3076,6 +3083,7 @@ OPTIONS
|
|
|
3076
3083
|
--page <number> Page number (default: 1)
|
|
3077
3084
|
--email <address> Filter by sender email (partial match)
|
|
3078
3085
|
--domain <domain> Filter by sender domain
|
|
3086
|
+
--inbox-id <id> Filter by inbox ID
|
|
3079
3087
|
--format <format> Output format: json | table (default: table)
|
|
3080
3088
|
|
|
3081
3089
|
EXAMPLES
|
|
@@ -3085,9 +3093,12 @@ EXAMPLES
|
|
|
3085
3093
|
emailr inbox list --domain example.com
|
|
3086
3094
|
emailr inbox list --format json
|
|
3087
3095
|
|
|
3096
|
+
# Filter by inbox
|
|
3097
|
+
emailr inbox list --inbox-id <inbox-uuid>
|
|
3098
|
+
|
|
3088
3099
|
OUTPUT FORMATS
|
|
3089
3100
|
--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(),
|
|
3101
|
+
--format table Human-readable table with ID, From, Subject, To, Date (default)`).option("--limit <count>","Number of emails to return","20").option("--page <number>","Page number","1").option("--email <address>","Filter by sender email (partial match)").option("--domain <domain>","Filter by sender domain").option("--inbox-id <inbox_id>","Filter by inbox ID").option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=c(),o=new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}),r={status:"received",page:parseInt(t.page),limit:Math.min(parseInt(t.limit),100),email:t.email,domain:t.domain};t.inboxId&&(r.inbox_id=t.inboxId);let a=await o.emails.list(r);if(t.format==="json")m(a,"json");else {if(!a.data||a.data.length===0){u("No emails in inbox");return}let s=a.data.map(d=>({ID:d.id,From:d.from_email,Subject:Ge(d.subject||"(no subject)",40),To:d.to_email,Date:re(d.created_at),Attachments:d.attachments?.length||0}));m(s,"table"),u(`Page ${a.pagination.page} of ${a.pagination.pages} (${a.pagination.total} total)`);}}catch(e){l(e instanceof Error?e.message:"Failed to list inbox"),process.exit(1);}}),i.command("get <id>").description(`View a received email
|
|
3091
3102
|
|
|
3092
3103
|
USAGE
|
|
3093
3104
|
emailr inbox get <email-id> [options]
|
|
@@ -3108,7 +3119,7 @@ EXAMPLES
|
|
|
3108
3119
|
|
|
3109
3120
|
OUTPUT FORMATS
|
|
3110
3121
|
--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
|
|
3122
|
+
--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 s=a.text_content||a.html_content?.replace(/<[^>]*>/g,"")||"(no content)";console.log(s);}if(a.attachments&&a.attachments.length>0){console.log(""),u("Attachments:");let s=a.attachments.map(d=>({Filename:d.filename,Type:d.contentType||d.content_type||"-",Size:kt(d.size||0)}));m(s,"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
3123
|
|
|
3113
3124
|
USAGE
|
|
3114
3125
|
emailr inbox thread <email-id> [options]
|
|
@@ -3127,7 +3138,7 @@ EXAMPLES
|
|
|
3127
3138
|
|
|
3128
3139
|
OUTPUT FORMATS
|
|
3129
3140
|
--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(),
|
|
3141
|
+
--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(),r=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),a=await r.emails.get(t),n=a.thread_id||a.id,s=[],d=new Set;if(s.push(a),d.add(a.id),a.thread_id&&a.thread_id!==a.id)try{let f=await r.emails.get(a.thread_id);d.has(f.id)||(s.push(f),d.add(f.id));}catch{}let b=await r.emails.list({limit:100});if(b.data)for(let f of b.data)d.has(f.id)||(f.thread_id===n||f.parent_email_id===a.id||f.id===a.parent_email_id)&&(s.push(f),d.add(f.id));if(s.sort((f,h)=>new Date(f.created_at).getTime()-new Date(h.created_at).getTime()),e.format==="json")m(s,"json");else {s.length<=1&&u("No other emails in this conversation"),u(`Conversation (${s.length} email${s.length!==1?"s":""}):`),console.log("");for(let f of s){let h=f.status==="received"?"\u2190 IN ":"\u2192 OUT",w=f.id===t?" \u25C0 (selected)":"";console.log(`${h} ${re(f.created_at)}${w}`),console.log(` From: ${f.from_email}`),console.log(` To: ${f.to_email}`),console.log(` Subject: ${f.subject||"(no subject)"}`);let _=f.text_content||f.html_content?.replace(/<[^>]*>/g,"")||"";_&&console.log(` ${Ge(_.trim(),120)}`),console.log("");}}await new Promise(f=>process.stdout.write("",()=>f())),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
3142
|
|
|
3132
3143
|
USAGE
|
|
3133
3144
|
emailr inbox reply <email-id> [options]
|
|
@@ -3163,7 +3174,7 @@ EXAMPLES
|
|
|
3163
3174
|
|
|
3164
3175
|
OUTPUT FORMATS
|
|
3165
3176
|
--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(),
|
|
3177
|
+
--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(),r=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),a=await r.emails.get(t),n=e.html,s=e.text;if(e.htmlFile)try{n=readFileSync(e.htmlFile,"utf-8");}catch{l(`Failed to read HTML file: ${e.htmlFile}`),process.exit(1);}if(e.textFile)try{s=readFileSync(e.textFile,"utf-8");}catch{l(`Failed to read text file: ${e.textFile}`),process.exit(1);}!n&&!s&&(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||""}`),b={to:a.from_email,from:e.from||a.to_email,subject:d,html:n||void 0,text:s||n?.replace(/<[^>]*>/g,"")||void 0,replyTo:{in_reply_to:a.message_id||a.ses_message_id,thread_id:a.thread_id||a.id,parent_email_id:a.id}};if(e.cc){let h=e.cc.split(",").map(w=>w.trim());b.cc=h.length===1?h[0]:h;}if(e.bcc){let h=e.bcc.split(",").map(w=>w.trim());b.bcc=h.length===1?h[0]:h;}let S=await r.emails.send(b);e.format==="json"?m(S,"json"):(p("Reply sent successfully!"),m({"Message ID":S.message_id,To:a.from_email,Subject:d,Status:S.status},"table")),await new Promise(h=>process.stdout.write("",()=>h())),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
3178
|
|
|
3168
3179
|
USAGE
|
|
3169
3180
|
emailr inbox forward <email-id> --to <recipients> [options]
|
|
@@ -3189,7 +3200,178 @@ EXAMPLES
|
|
|
3189
3200
|
|
|
3190
3201
|
OUTPUT FORMATS
|
|
3191
3202
|
--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(),
|
|
3203
|
+
--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(),r=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),a=e.to.split(",").map(d=>d.trim()).filter(Boolean),n=await r.emails.forward({email_id:t,to:a.length===1?a[0]:a,message:e.message});e.format==="json"?m(n,"json"):(p("Email forwarded successfully!"),m({"Message ID":n.message_id,To:a.join(", "),Recipients:n.recipients,Status:n.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 Ge(i,t){return i.length<=t?i:i.slice(0,t-1)+"\u2026"}function re(i){return new Date(i).toLocaleString()}function kt(i){return i<1024?i+" B":i<1024*1024?(i/1024).toFixed(1)+" KB":(i/(1024*1024)).toFixed(1)+" MB"}function qe(){let i=new Command("inboxes").description(`Manage inboxes
|
|
3204
|
+
|
|
3205
|
+
USAGE
|
|
3206
|
+
emailr inboxes <subcommand> [options]
|
|
3207
|
+
|
|
3208
|
+
DESCRIPTION
|
|
3209
|
+
Create, list, get, update, and delete inboxes. Each inbox represents
|
|
3210
|
+
a distinct email identity with a name, username, and domain.
|
|
3211
|
+
|
|
3212
|
+
SUBCOMMANDS
|
|
3213
|
+
create Create a new inbox
|
|
3214
|
+
list List all inboxes
|
|
3215
|
+
get <id> Get an inbox by ID
|
|
3216
|
+
update <id> Update an inbox
|
|
3217
|
+
delete <id> Delete an inbox
|
|
3218
|
+
|
|
3219
|
+
EXAMPLES
|
|
3220
|
+
# Create an inbox
|
|
3221
|
+
emailr inboxes create --name "Support" --username support --domain example.com
|
|
3222
|
+
|
|
3223
|
+
# List all inboxes
|
|
3224
|
+
emailr inboxes list
|
|
3225
|
+
|
|
3226
|
+
# Get inbox details
|
|
3227
|
+
emailr inboxes get inb_abc123
|
|
3228
|
+
|
|
3229
|
+
# Update inbox name
|
|
3230
|
+
emailr inboxes update inb_abc123 --name "Customer Support"
|
|
3231
|
+
|
|
3232
|
+
# Delete an inbox
|
|
3233
|
+
emailr inboxes delete inb_abc123`);return i.command("create").description(`Create a new inbox
|
|
3234
|
+
|
|
3235
|
+
USAGE
|
|
3236
|
+
emailr inboxes create --name <name> --username <username> --domain <domain> [options]
|
|
3237
|
+
|
|
3238
|
+
DESCRIPTION
|
|
3239
|
+
Creates a new inbox with the specified name, username, and domain.
|
|
3240
|
+
The domain must be verified for your organization.
|
|
3241
|
+
|
|
3242
|
+
OPTIONS
|
|
3243
|
+
--name <name> Display name for the inbox (required)
|
|
3244
|
+
--username <username> Username part of the email address (required)
|
|
3245
|
+
--domain <domain> Domain for the email address (required)
|
|
3246
|
+
--format <format> Output format: json | table (default: table)
|
|
3247
|
+
|
|
3248
|
+
EXAMPLES
|
|
3249
|
+
# Create a support inbox
|
|
3250
|
+
emailr inboxes create --name "Support" --username support --domain example.com
|
|
3251
|
+
|
|
3252
|
+
# Create and get JSON output
|
|
3253
|
+
emailr inboxes create --name "Sales" --username sales --domain example.com --format json`).requiredOption("--name <name>","Inbox display name").requiredOption("--username <username>","Username for the email address").requiredOption("--domain <domain>","Domain for the email address").option("--format <format>","Output format: json | table","table").action(async t=>{try{let e=c(),r=await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).inboxes.create({name:t.name,username:t.username,domain:t.domain});t.format==="json"?m(r,"json"):(p(`Inbox created: ${r.id}`),m({ID:r.id,Name:r.name,"From Address":r.from_address,"Inbound Address":r.inbound_address,Created:r.created_at},"table"));}catch(e){l(e instanceof Error?e.message:"Failed to create inbox"),process.exit(1);}}),i.command("list").description(`List all inboxes
|
|
3254
|
+
|
|
3255
|
+
USAGE
|
|
3256
|
+
emailr inboxes list [options]
|
|
3257
|
+
|
|
3258
|
+
DESCRIPTION
|
|
3259
|
+
Retrieves all inboxes for your organization.
|
|
3260
|
+
|
|
3261
|
+
OPTIONS
|
|
3262
|
+
--format <format> Output format: json | table (default: table)
|
|
3263
|
+
|
|
3264
|
+
EXAMPLES
|
|
3265
|
+
# List all inboxes
|
|
3266
|
+
emailr inboxes list
|
|
3267
|
+
|
|
3268
|
+
# Get JSON output
|
|
3269
|
+
emailr inboxes list --format json`).option("--format <format>","Output format: json | table","table").action(async t=>{try{let e=c(),r=await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).inboxes.list();if(t.format==="json")m(r,"json");else {if(r.length===0){console.log("No inboxes found.");return}let a=r.map(n=>({ID:n.id,Name:n.name,"From Address":n.from_address,"Inbound Address":n.inbound_address,Created:new Date(n.created_at).toLocaleDateString()}));m(a,"table"),console.log(`
|
|
3270
|
+
Total: ${r.length}`);}}catch(e){l(e instanceof Error?e.message:"Failed to list inboxes"),process.exit(1);}}),i.command("get <inbox_id>").description(`Get an inbox by ID
|
|
3271
|
+
|
|
3272
|
+
USAGE
|
|
3273
|
+
emailr inboxes get <inbox_id> [options]
|
|
3274
|
+
|
|
3275
|
+
DESCRIPTION
|
|
3276
|
+
Retrieves detailed information about a specific inbox.
|
|
3277
|
+
|
|
3278
|
+
ARGUMENTS
|
|
3279
|
+
<inbox_id> The unique inbox identifier
|
|
3280
|
+
|
|
3281
|
+
OPTIONS
|
|
3282
|
+
--format <format> Output format: json | table (default: table)
|
|
3283
|
+
|
|
3284
|
+
EXAMPLES
|
|
3285
|
+
# Get inbox details
|
|
3286
|
+
emailr inboxes get inb_abc123
|
|
3287
|
+
|
|
3288
|
+
# Get JSON output
|
|
3289
|
+
emailr inboxes get inb_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}).inboxes.get(t);e.format==="json"?m(a,"json"):m({ID:a.id,Name:a.name,Username:a.username,Domain:a.domain,"From Address":a.from_address,"Inbound Address":a.inbound_address,Created:a.created_at,Updated:a.updated_at},"table");}catch(o){l(o instanceof Error?o.message:"Failed to get inbox"),process.exit(1);}}),i.command("update <inbox_id>").description(`Update an inbox
|
|
3290
|
+
|
|
3291
|
+
USAGE
|
|
3292
|
+
emailr inboxes update <inbox_id> --name <name> [options]
|
|
3293
|
+
|
|
3294
|
+
DESCRIPTION
|
|
3295
|
+
Updates an inbox's display name. Username and domain are immutable
|
|
3296
|
+
after creation.
|
|
3297
|
+
|
|
3298
|
+
ARGUMENTS
|
|
3299
|
+
<inbox_id> The unique inbox identifier
|
|
3300
|
+
|
|
3301
|
+
OPTIONS
|
|
3302
|
+
--name <name> New display name for the inbox
|
|
3303
|
+
--format <format> Output format: json | table (default: table)
|
|
3304
|
+
|
|
3305
|
+
EXAMPLES
|
|
3306
|
+
# Update inbox name
|
|
3307
|
+
emailr inboxes update inb_abc123 --name "Customer Support"
|
|
3308
|
+
|
|
3309
|
+
# Get JSON output
|
|
3310
|
+
emailr inboxes update inb_abc123 --name "New Name" --format json`).option("--name <name>","New inbox display name").option("--format <format>","Output format: json | table","table").action(async(t,e)=>{try{e.name||(l("No update fields specified. Use --name to update the inbox name."),process.exit(1));let o=c(),r=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),a={};e.name&&(a.name=e.name);let n=await r.inboxes.update(t,a);e.format==="json"?m(n,"json"):(p(`Inbox updated: ${n.id}`),m({ID:n.id,Name:n.name,"From Address":n.from_address,"Inbound Address":n.inbound_address,Updated:n.updated_at},"table"));}catch(o){l(o instanceof Error?o.message:"Failed to update inbox"),process.exit(1);}}),i.command("delete <inbox_id>").description(`Delete an inbox
|
|
3311
|
+
|
|
3312
|
+
USAGE
|
|
3313
|
+
emailr inboxes delete <inbox_id> [options]
|
|
3314
|
+
|
|
3315
|
+
DESCRIPTION
|
|
3316
|
+
Permanently deletes an inbox. Existing emails associated with this
|
|
3317
|
+
inbox will have their inbox reference cleared but are preserved.
|
|
3318
|
+
|
|
3319
|
+
ARGUMENTS
|
|
3320
|
+
<inbox_id> The unique inbox identifier
|
|
3321
|
+
|
|
3322
|
+
OPTIONS
|
|
3323
|
+
--format <format> Output format: json | table (default: table)
|
|
3324
|
+
|
|
3325
|
+
EXAMPLES
|
|
3326
|
+
# Delete an inbox
|
|
3327
|
+
emailr inboxes delete inb_abc123
|
|
3328
|
+
|
|
3329
|
+
# Get JSON output
|
|
3330
|
+
emailr inboxes delete inb_abc123 --format json
|
|
3331
|
+
|
|
3332
|
+
WARNING
|
|
3333
|
+
This action is permanent and cannot be undone.`).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}).inboxes.delete(t);e.format==="json"?m(a,"json"):p(`Inbox deleted: ${t}`);}catch(o){l(o instanceof Error?o.message:"Failed to delete inbox"),process.exit(1);}}),i}function $e(){let i=new Command("threads").description(`Manage email threads and labels
|
|
3334
|
+
|
|
3335
|
+
USAGE
|
|
3336
|
+
emailr threads <subcommand> [options]
|
|
3337
|
+
|
|
3338
|
+
DESCRIPTION
|
|
3339
|
+
List, view, and manage email threads. Threads group related emails
|
|
3340
|
+
into conversations. Use labels to organize threads (inbox, starred,
|
|
3341
|
+
archived, spam, trash, etc).
|
|
3342
|
+
|
|
3343
|
+
SUBCOMMANDS
|
|
3344
|
+
list List threads filtered by label
|
|
3345
|
+
get <id> View a thread with all messages
|
|
3346
|
+
label <id> Add or remove labels from a thread
|
|
3347
|
+
|
|
3348
|
+
EXAMPLES
|
|
3349
|
+
# List inbox threads
|
|
3350
|
+
emailr threads list
|
|
3351
|
+
|
|
3352
|
+
# List sent threads
|
|
3353
|
+
emailr threads list --label sent
|
|
3354
|
+
|
|
3355
|
+
# List starred threads for a specific inbox
|
|
3356
|
+
emailr threads list --label starred --inbox-id <uuid>
|
|
3357
|
+
|
|
3358
|
+
# Search threads
|
|
3359
|
+
emailr threads list --search "invoice"
|
|
3360
|
+
|
|
3361
|
+
# View a thread
|
|
3362
|
+
emailr threads get <thread-id>
|
|
3363
|
+
|
|
3364
|
+
# Star a thread
|
|
3365
|
+
emailr threads label <thread-id> --add starred
|
|
3366
|
+
|
|
3367
|
+
# Archive a thread (remove from inbox)
|
|
3368
|
+
emailr threads label <thread-id> --add archived --remove inbox
|
|
3369
|
+
|
|
3370
|
+
# Move to trash
|
|
3371
|
+
emailr threads label <thread-id> --add trash --remove inbox
|
|
3372
|
+
|
|
3373
|
+
# Mark as spam
|
|
3374
|
+
emailr threads label <thread-id> --add spam --remove inbox`);return i.command("list").description("List threads filtered by label").option("--label <label>","Filter by label (inbox, sent, starred, spam, trash, archived, all)","inbox").option("--limit <count>","Number of threads to return","20").option("--page <number>","Page number","1").option("--search <query>","Search by subject or sender").option("--inbox-id <id>","Filter by inbox ID").option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=c(),r=await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).threads.list({label:t.label,page:parseInt(t.page),limit:Math.min(parseInt(t.limit),100),search:t.search,inbox_id:t.inboxId});if(t.format==="json")m(r,"json");else {if(!r.data||r.data.length===0){u(`No threads in ${t.label}`);return}let n=r.data.map(s=>({"Thread ID":s.thread_id.slice(0,8)+"\u2026",Subject:He(s.subject||"(no subject)",40),From:s.from_email,Messages:s.message_count,Labels:(s.labels||[]).join(", "),Updated:Je(s.updated_at)}));m(n,"table"),u(`Page ${r.pagination.page} of ${r.pagination.pages} (${r.pagination.total} total)`);}}catch(e){l(e instanceof Error?e.message:"Failed to list threads"),process.exit(1);}}),i.command("get <id>").description("View a thread with all messages").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}).threads.get(t);if(e.format==="json")m(a,"json");else {u(`Thread: ${a.subject||"(no subject)"}`),u(`Labels: ${a.labels.join(", ")||"none"}`),u(`Messages: ${a.messages.length}`),console.log("");for(let s of a.messages){let d=s.status==="received"?"\u2190 IN ":"\u2192 OUT";console.log(`${d} ${Je(s.created_at)}`),console.log(` From: ${s.from_email}`),console.log(` To: ${s.to_email}`),s.cc_emails?.length&&console.log(` Cc: ${s.cc_emails.join(", ")}`),console.log(` Labels: ${s.labels.join(", ")||"none"}`);let b=s.text_content||s.html_content?.replace(/<[^>]*>/g,"")||"";b&&console.log(` ${He(b.trim(),120)}`),console.log("");}}await new Promise(s=>process.stdout.write("",()=>s())),process.exit(0);}catch(o){l(o instanceof Error?o.message:"Failed to get thread"),process.exit(1);}}),i.command("label <id>").description("Add or remove labels from a thread").option("--add <labels>","Labels to add (comma-separated)").option("--remove <labels>","Labels to remove (comma-separated)").option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{!e.add&&!e.remove&&(l("Specify --add and/or --remove labels"),process.exit(1));let o=c(),r=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),a=e.add?e.add.split(",").map(b=>b.trim()):void 0,n=e.remove?e.remove.split(",").map(b=>b.trim()):void 0,s=await r.threads.updateLabels(t,{add:a,remove:n});e.format==="json"?m(s,"json"):(p(`Updated ${s.updated} email(s) in thread`),a&&u(`Added: ${a.join(", ")}`),n&&u(`Removed: ${n.join(", ")}`)),await new Promise(b=>process.stdout.write("",()=>b())),process.exit(0);}catch(o){l(o instanceof Error?o.message:"Failed to update labels"),process.exit(1);}}),i}function He(i,t){return i.length<=t?i:i.slice(0,t-1)+"\u2026"}function Je(i){return new Date(i).toLocaleString()}var y=new Command;y.name("emailr").description(`Emailr CLI - Send emails and manage your email infrastructure
|
|
3193
3375
|
|
|
3194
3376
|
USAGE
|
|
3195
3377
|
emailr <command> [subcommand] [options]
|
|
@@ -3202,6 +3384,8 @@ DESCRIPTION
|
|
|
3202
3384
|
COMMANDS
|
|
3203
3385
|
send Send individual emails with HTML/text content or templates
|
|
3204
3386
|
inbox View and manage received (inbound) emails
|
|
3387
|
+
inboxes Create and manage email inboxes
|
|
3388
|
+
threads List, view, and manage email threads and labels
|
|
3205
3389
|
templates Create, edit, preview, and publish email templates
|
|
3206
3390
|
contacts Manage email contacts and their metadata
|
|
3207
3391
|
segments Create and manage contact segments with conditions
|
|
@@ -3291,4 +3475,4 @@ AGENTIC WORKFLOW
|
|
|
3291
3475
|
|
|
3292
3476
|
MORE INFORMATION
|
|
3293
3477
|
Run 'emailr <command> --help' for detailed help on any command.
|
|
3294
|
-
Run 'emailr <command> <subcommand> --help' for subcommand details.`).version("1.
|
|
3478
|
+
Run 'emailr <command> <subcommand> --help' for subcommand details.`).version("1.9.0");y.addCommand(ue());y.addCommand(Ke());y.addCommand(qe());y.addCommand($e());y.addCommand(fe());y.addCommand(je());y.addCommand(Ie());y.addCommand(Ce());y.addCommand(Ue());y.addCommand(Pe());y.addCommand(Ne());y.addCommand(Me());y.addCommand(Le());y.parse();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "emailr-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.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.
|
|
26
|
+
"emailr": "^1.4.0",
|
|
27
27
|
"open": "^11.0.0"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|