emailr-cli 1.7.8 → 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.
Files changed (2) hide show
  1. package/dist/index.js +466 -87
  2. 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 v,{readFileSync}from'fs';import B from'os';import _ from'path';import re from'cli-table3';import S from'chalk';import Je from'http';import {URL}from'url';import ct from'crypto';import {spawn,execSync,exec}from'child_process';var Re=[_.join(B.homedir(),".emailrrc"),_.join(B.homedir(),".config","emailr","config.json")];function m(){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 Re)if(v.existsSync(i))try{let t=v.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.
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 j(){let i=_.join(B.homedir(),".config","emailr");return _.join(i,"config.json")}function G(i){let t=j(),e=_.dirname(t);v.existsSync(e)||v.mkdirSync(e,{recursive:true});let o={};if(v.existsSync(t))try{o=JSON.parse(v.readFileSync(t,"utf-8"));}catch{}let r={...o,...i};v.writeFileSync(t,JSON.stringify(r,null,2)+`
11
- `);}function ne(i){try{return m()[i]?.toString()}catch{return}}function c(i,t="table"){t==="json"?console.log(JSON.stringify(i,null,2)):Me(i);}function Me(i){Array.isArray(i)?Le(i):typeof i=="object"&&i!==null?De(i):console.log(i);}function Le(i){if(i.length===0){console.log(S.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 re({head:e.map(r=>S.cyan(r)),style:{head:[],border:[]}});for(let r of i){let a=e.map(n=>{let s=r[n];return se(s)});o.push(a);}console.log(o.toString());}function De(i){let t=new re({style:{head:[],border:[]}});for(let[e,o]of Object.entries(i))t.push([S.cyan(e),se(o)]);console.log(t.toString());}function se(i){return i==null?S.gray("-"):typeof i=="boolean"?i?S.green("\u2713"):S.red("\u2717"):typeof i=="object"?JSON.stringify(i):String(i)}function d(i){console.log(S.green("\u2713"),i);}function l(i){console.error(S.red("\u2717"),i);}function I(i){console.warn(S.yellow("\u26A0"),i);}function u(i){console.log(S.blue("\u2139"),i);}function ce(){return new Command("send").description(`Send an email
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=m(),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(p=>p.trim());a.cc=s.length===1?s[0]:s;}if(t.bcc){let s=t.bcc.split(",").map(p=>p.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"?c(n,"json"):(d("Email sent successfully!"),c({"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 me(){let i=new Command("contacts").description(`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}),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=m(),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")c(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}));c(n,"table"),console.log(`
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
@@ -314,7 +314,7 @@ EXAMPLES
314
314
  emailr contacts get con_abc123 --format json
315
315
 
316
316
  # Pipe JSON to jq for processing
317
- emailr contacts get con_abc123 --format json | jq '.metadata'`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).contacts.get(t);c(a,e.format);}catch(o){l(o instanceof Error?o.message:"Failed to get contact"),process.exit(1);}}),i.command("create").description(`Create a new contact
317
+ emailr contacts get con_abc123 --format json | jq '.metadata'`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=c(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).contacts.get(t);m(a,e.format);}catch(o){l(o instanceof Error?o.message:"Failed to get contact"),process.exit(1);}}),i.command("create").description(`Create a new contact
318
318
 
319
319
  USAGE
320
320
  emailr contacts create --email <email_address> [options]
@@ -357,7 +357,7 @@ EXAMPLES
357
357
  emailr contacts create --email "user@example.com" --subscribed false
358
358
 
359
359
  # Get JSON output for scripting
360
- emailr contacts create --email "user@example.com" --format json`).requiredOption("--email <email>","Contact email address").option("--first-name <name>","First name").option("--last-name <name>","Last name").option("--subscribed","Mark as subscribed (default: true)").option("--metadata <json>","Metadata as JSON").option("--tags <tags>","Comma-separated tags").option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=m(),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"?c(a,"json"):(d(`Contact created: ${a.id}`),c(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
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=m(),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"?c(n,"json"):(d(`Contact updated: ${n.id}`),c(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
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=m();await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).contacts.delete(t),d(`Contact deleted: ${t}`);}catch(e){l(e instanceof Error?e.message:"Failed to delete contact"),process.exit(1);}}),i}function pe(){return _.join(B.homedir(),".config","emailr","templates")}function qe(){let i=pe();v.existsSync(i)||v.mkdirSync(i,{recursive:true});}function W(i){return _.join(pe(),`${i}.html`)}function X(i,t){qe();let e=W(i);v.writeFileSync(e,t,"utf-8");}function ue(i){let t=W(i);return v.existsSync(t)?v.readFileSync(t,"utf-8"):null}function fe(i){let t=W(i);return v.existsSync(t)}var w=null,U=null,H=false;function he(i){return i.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;")}function $e(i){return i===null||i.trim()===""}function Be(i){return `<!DOCTYPE html>
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,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#039;")}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">${he(i)}</div>
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 be(i){return `<!DOCTYPE html>
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">${he(i)}</div>
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 We(i){let t=i.match(/^\/preview\/([^/]+)$/);return t?t[1]:null}function Xe(){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=We(e);if(!o){t.writeHead(404,{"Content-Type":"text/plain"}),t.end("Not Found");return}if(!fe(o)){t.writeHead(404,{"Content-Type":"text/html; charset=utf-8"}),t.end(be(o));return}let r=ue(o);if(r===null){t.writeHead(404,{"Content-Type":"text/html; charset=utf-8"}),t.end(be(o));return}if($e(r)){t.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),t.end(Be(o));return}t.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),t.end(r);}}var ge={async start(){return H&&U!==null?U:new Promise((i,t)=>{w=Je.createServer(Xe()),w.listen(0,"127.0.0.1",()=>{let e=w.address();e&&typeof e=="object"?(U=e.port,H=true,w.unref(),i(U)):t(new Error("Failed to get server address"));}),w.on("error",e=>{H=false,U=null,w=null,t(new Error(`Failed to start preview server: ${e.message}`));});})},getPort(){return U},isRunning(){return H},async stop(){if(w)return new Promise(i=>{w.close(()=>{w=null,U=null,H=false,i();});})}};function we(){return ge}async function V(i){try{return `http://127.0.0.1:${await ge.start()}/preview/${i}`}catch{return null}}function ye(){w&&w.ref();}var P=null,z=null,J=null,R=[],ve=`
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 Ye(i){return i.includes("</body>")?i.replace("</body>",`${ve}</body>`):i+ve}function Ze(){R.forEach(i=>{try{i.write(`data: reload
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 Y(i,t){let e=_.resolve(i);return new Promise((o,r)=>{P=Je.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
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
- `),R.push(n),a.on("close",()=>{R=R.filter(s=>s!==n);});return}if(a.method==="GET"){try{let s=v.readFileSync(e,"utf-8"),p=Ye(s);n.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),n.end(p);}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");}),P.listen(0,"127.0.0.1",()=>{let a=P.address();if(a&&typeof a=="object"){z=a.port;let n=null;J=v.watch(e,s=>{s==="change"&&(n&&clearTimeout(n),n=setTimeout(()=>{Ze(),t?.();},100));}),o(z);}else r(new Error("Failed to get server address"));}),P.on("error",a=>{r(new Error(`Failed to start server: ${a.message}`));});})}async function Z(){if(J&&(J.close(),J=null),R.forEach(i=>{try{i.end();}catch{}}),R=[],P)return new Promise(i=>{P.close(()=>{P=null,z=null,i();});})}async function Te(i){try{let t=i.html_content??"";X(i.id,t);}catch(t){return I(`Could not save template for preview: ${t instanceof Error?t.message:String(t)}`),null}try{let t=await V(i.id);return t===null?(I("Could not start preview server"),null):t}catch(t){return I(`Could not generate preview URL: ${t instanceof Error?t.message:String(t)}`),null}}function Oe(){let i=new Command("templates").description(`Manage email templates
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=m(),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")c(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}));c(n,"table"),console.log(`
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=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).templates.get(t),n=await Te({id:a.id,html_content:a.html_content??void 0}),s=a.preview_html?`${o.baseUrl}/preview/${a.id}`:null;if(e.format==="json")c({...a,preview_url:s??n},"json");else {let p={ID:a.id,Name:a.name,Subject:a.subject,Variables:a.variables?.join(", ")||"-",Created:a.created_at};s?p["Preview URL"]=s:n&&(p["Local Preview"]=n),c(p,"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
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]
@@ -734,8 +734,8 @@ AGENTIC WORKFLOW
734
734
  This is step 1 of the agentic workflow:
735
735
  1. Fetch: emailr templates fetch <id> --output template.html
736
736
  2. Edit locally or with AI assistance
737
- 3. Push preview: emailr templates push-preview <id> --html-file template.html`).option("--output <file_path>","Write HTML to file (default: stdout)").option("--preview","Fetch preview HTML instead of published HTML").action(async(t,e)=>{try{let o=m(),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 n=_.resolve(e.output);v.writeFileSync(n,a,"utf-8"),d(`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
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 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=m(),r=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),a;if(e.htmlFile){let p=_.resolve(e.htmlFile);try{a=v.readFileSync(p,"utf-8");}catch{l(`Failed to read file: ${p}`),process.exit(1);}}else a=e.html;let n=await r.templates.pushPreview(t,a),s="updated";e.format==="json"?c({template_id:t,preview_url:n.preview_url,status:s},"json"):(d("Preview uploaded successfully"),c({"Template ID":t,"Preview URL":n.preview_url,Status:s},"table"),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(),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=m(),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.tags&&(r.tags=t.tags.split(",").map(s=>s.trim().toLowerCase()).filter(Boolean));let a=await o.templates.create(r),n=await Te({id:a.id,html_content:a.html_content??void 0});if(t.format==="json")c({...a,preview_url:n},"json");else {d(`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),c(s,"table"),n&&console.log(`
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=m(),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.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")c(n,"json");else {d(`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};c(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
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>
@@ -899,7 +901,7 @@ EXAMPLES
899
901
  emailr templates delete tpl_abc123
900
902
 
901
903
  WARNING
902
- This action is permanent and cannot be undone.`).action(async t=>{try{let e=m();await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).templates.delete(t),d(`Template deleted: ${t}`);}catch(e){l(e instanceof Error?e.message:"Failed to delete template"),process.exit(1);}}),i.command("preview <template_id>").description(`Preview a template in the browser
904
+ This action is permanent and cannot be undone.`).action(async t=>{try{let e=c();await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).templates.delete(t),p(`Template deleted: ${t}`);}catch(e){l(e instanceof Error?e.message:"Failed to delete template"),process.exit(1);}}),i.command("preview <template_id>").description(`Preview a template in the browser
903
905
 
904
906
  USAGE
905
907
  emailr templates preview <template_id> [options]
@@ -928,12 +930,12 @@ 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=m(),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(X(a.id,n),e.foreground){let f=await V(a.id);if(f||(l("Failed to start preview server"),process.exit(1)),ye(),console.log(`
932
- Template: ${a.name}`),console.log(`Preview URL: ${f}`),e.open!==!1)try{await(await import('open')).default(f),console.log(`
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(`
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 we().stop(),console.log("Done."),process.exit(0);});return}let s=_.join(process.cwd(),`.template-preview-${a.id}.html`);v.writeFileSync(s,n,"utf-8");let{spawn:p}=await import('child_process'),b=await import('os'),T=_.join(b.tmpdir(),"emailr-preview.pid");try{let f=v.readFileSync(T,"utf-8").trim();process.kill(parseInt(f,10),"SIGTERM");}catch{}let h=`
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');
@@ -958,9 +960,9 @@ Stopping preview server...`),await we().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
- `,y=p("node",["-e",h],{detached:!0,stdio:["ignore","pipe","ignore"]}),O="";await new Promise(f=>{y.stdout?.on("data",N=>{let q=N.toString().match(/PORT:(\d+)/);q&&(O=q[1],f());}),setTimeout(f,3e3);}),y.unref();let D=`http://127.0.0.1:${O}/`;if(console.log(`
962
- Template: ${a.name}`),console.log(`Preview URL: ${D}`),console.log(`
963
- To stop: emailr templates stop-preview`),e.open!==!1)try{await(await import('open')).default(D);}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
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=m(),r=new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}),a=_.resolve(e.file);console.log(`Fetching template ${t}...`);let n=await r.templates.get(t),s=n.html_content??"";if(v.writeFileSync(a,s,"utf-8"),console.log(`Template saved to: ${a}`),e.foreground){let N=`http://127.0.0.1:${await Y(a,()=>{console.log("File changed - browser refreshed");})}/`;if(console.log(`
1004
- Template: ${n.name}`),console.log(`Template ID: ${n.id}`),console.log(`Live Preview: ${N}`),console.log(`File: ${a}`),console.log(`
1005
- Watching for changes... Edit the file and see live updates.`),console.log(`When done, run: emailr templates update ${t} --html-file ${e.file}`),e.open!==!1)try{await(await import('open')).default(N);}catch{}process.on("SIGINT",async()=>{console.log(`
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 Z(),console.log("Done."),console.log(`
1008
- To save changes: emailr templates update ${t} --html-file ${e.file}`),process.exit(0);});return}let{spawn:p}=await import('child_process'),b=await import('os'),T=_.join(b.tmpdir(),"emailr-preview.pid");try{let f=v.readFileSync(T,"utf-8").trim();process.kill(parseInt(f,10),"SIGTERM");}catch{}let h=`
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
- `,y=p("node",["-e",h],{detached:!0,stdio:["ignore","pipe","ignore"]}),O="";await new Promise(f=>{y.stdout?.on("data",N=>{let ie=N.toString().match(/PORT:(\d+)/);ie&&(O=ie[1],f());}),setTimeout(f,3e3);}),y.unref();let D=`http://127.0.0.1:${O}/`;if(console.log(`
1049
- Template: ${n.name}`),console.log(`Template ID: ${n.id}`),console.log(`Live Preview: ${D}`),console.log(`File: ${a}`),console.log(`
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(D);}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
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=_.resolve(t.file),o;if(t.blank?o="":o=`<!DOCTYPE html>
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>`,v.writeFileSync(e,o,"utf-8"),console.log(`Template draft created: ${e}`),t.foreground){let y=`http://127.0.0.1:${await Y(e,()=>{console.log("File changed - browser refreshed");})}/`;if(console.log(`
1129
- Live Preview: ${y}`),console.log(`File: ${e}`),console.log(`
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(y);}catch{}process.on("SIGINT",async()=>{console.log(`
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 Z(),console.log("Done."),console.log(`
1134
- To create template: emailr templates create --name "Template Name" --subject "Email Subject" --html-file ${t.file}`),process.exit(0);});return}let{spawn:r}=await import('child_process'),a=await import('os'),n=_.join(a.tmpdir(),"emailr-preview.pid");try{let h=v.readFileSync(n,"utf-8").trim();process.kill(parseInt(h,10),"SIGTERM");}catch{}let s=`
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
- `,p=r("node",["-e",s],{detached:!0,stdio:["ignore","pipe","ignore"]}),b="";await new Promise(h=>{p.stdout?.on("data",y=>{let O=y.toString().match(/PORT:(\d+)/);O&&(b=O[1],h());}),setTimeout(h,3e3);}),p.unref();let T=`http://127.0.0.1:${b}/`;if(console.log(`
1175
- Live Preview: ${T}`),console.log(`File: ${e}`),console.log(`
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(T);}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
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=_.join(t.tmpdir(),"emailr-preview.pid");try{let o=v.readFileSync(e,"utf-8").trim();process.kill(parseInt(o,10),"SIGTERM"),v.unlinkSync(e),d("Preview server stopped");}catch{d("No preview server running");}}),i}function Ee(){let i=new Command("domains").description(`Manage sending domains
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=m(),r=await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).domains.list();if(t.format==="json")c(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}));c(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
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]
@@ -1326,7 +1328,7 @@ EXAMPLES
1326
1328
  emailr domains get dom_abc123 --format json
1327
1329
 
1328
1330
  # Extract DNS records
1329
- emailr domains get dom_abc123 --format json | jq '.dns_records'`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).domains.get(t);c(a,e.format);}catch(o){l(o instanceof Error?o.message:"Failed to get domain"),process.exit(1);}}),i.command("add <domain_name>").description(`Add a new domain
1331
+ emailr domains get dom_abc123 --format json | jq '.dns_records'`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=c(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).domains.get(t);m(a,e.format);}catch(o){l(o instanceof Error?o.message:"Failed to get domain"),process.exit(1);}}),i.command("add <domain_name>").description(`Add a new domain
1330
1332
 
1331
1333
  USAGE
1332
1334
  emailr domains add <domain_name> [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=m(),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")c(n,"json");else {if(d(`Domain added: ${n.domain}`),u("Add the following DNS records to verify your domain:"),console.log(""),n.dns_records){let s=[{Type:"DKIM",...Q(n.dns_records.dkim)},{Type:"SPF",...Q(n.dns_records.spf)},{Type:"DMARC",...Q(n.dns_records.dmarc)}];c(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
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=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).domains.verify(t);e.format==="json"?c(a,"json"):a.verified?d("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
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=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).domains.checkDns(t);if(e.format==="json")c(a,"json");else {let n=Object.entries(a).map(([s,p])=>({Record:s,Verified:p.verified,Expected:p.expected||"-",Found:p.found?.join(", ")||"-"}));c(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
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=m();await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).domains.delete(t),d(`Domain deleted: ${t}`);}catch(e){l(e instanceof Error?e.message:"Failed to delete domain"),process.exit(1);}}),i}function Q(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 _e(){let i=new Command("config").description(`Manage CLI configuration
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"],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}),d(`Configuration saved: ${t} = ${r==="api-key"?"***":e}`),u(`Config file: ${j()}`);}catch(o){l(o instanceof Error?o.message:"Failed to save configuration"),process.exit(1);}}),i.command("get <key>").description(`Get a configuration value
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}`),u(`Valid keys: ${e.join(", ")}`),process.exit(1));let a={"api-key":"apiKey","base-url":"baseUrl",format:"format"}[o],n=ne(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
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=m(),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")c(o,"json");else {let r=Object.entries(o).map(([a,n])=>({Key:a,Value:n}));c(r,"table");}console.log(""),u(`Config file: ${j()}`);}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
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(j());}),i.command("init").description(`Initialize configuration interactively
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}),d("Configuration initialized!"),u(`Config file: ${j()}`)):(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 Ne(){let i=new Command("broadcasts").description(`Manage broadcast campaigns
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=m(),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")c(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()}));c(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
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]
@@ -1888,7 +1890,7 @@ EXAMPLES
1888
1890
  emailr broadcasts get brd_abc123 --format json
1889
1891
 
1890
1892
  # Pipe JSON to jq for processing
1891
- emailr broadcasts get brd_abc123 --format json | jq '{sent: .sent_count, opened: .opened_count}'`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).broadcasts.get(t);e.format==="json"?c(a,"json"):c({ID:a.id,Name:a.name,Subject:a.subject,"From Email":a.from_email,"From Name":a.from_name||"-",Status:a.status,Tags:a.tags?.join(", ")||"-","Total Recipients":a.total_recipients||0,"Sent Count":a.sent_count||0,Delivered:a.delivered_count||0,Opened:a.opened_count||0,Clicked:a.clicked_count||0,Bounced:a.bounced_count||0,"Scheduled At":a.scheduled_at||"N/A","Started At":a.started_at||"N/A","Completed At":a.completed_at||"N/A","Created At":a.created_at},"table");}catch(o){l(o instanceof Error?o.message:"Failed to get broadcast"),process.exit(1);}}),i.command("create").description(`Create a new broadcast
1893
+ emailr broadcasts get brd_abc123 --format json | jq '{sent: .sent_count, opened: .opened_count}'`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=c(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).broadcasts.get(t);e.format==="json"?m(a,"json"):m({ID:a.id,Name:a.name,Subject:a.subject,"From Email":a.from_email,"From Name":a.from_name||"-",Status:a.status,Tags:a.tags?.join(", ")||"-","Total Recipients":a.total_recipients||0,"Sent Count":a.sent_count||0,Delivered:a.delivered_count||0,Opened:a.opened_count||0,Clicked:a.clicked_count||0,Bounced:a.bounced_count||0,"Scheduled At":a.scheduled_at||"N/A","Started At":a.started_at||"N/A","Completed At":a.completed_at||"N/A","Created At":a.created_at},"table");}catch(o){l(o instanceof Error?o.message:"Failed to get broadcast"),process.exit(1);}}),i.command("create").description(`Create a new broadcast
1892
1894
 
1893
1895
  USAGE
1894
1896
  emailr broadcasts create --name <name> --subject <subject> --from <email> [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=m(),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,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"?c(a,"json"):(d("Broadcast created successfully!"),c({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
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]
@@ -2001,7 +2004,7 @@ EXAMPLES
2001
2004
  NOTE
2002
2005
  Sending is asynchronous. The command returns when sending starts,
2003
2006
  not when all emails are delivered. Use 'emailr broadcasts get' to
2004
- check delivery progress.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).broadcasts.send(t);e.format==="json"?c(a,"json"):(d("Broadcast sent successfully!"),c({Success:a.success,Sent:a.sent,Total:a.total},"table"));}catch(o){l(o instanceof Error?o.message:"Failed to send broadcast"),process.exit(1);}}),i.command("schedule <broadcast_id>").description(`Schedule a broadcast for future delivery
2007
+ check delivery progress.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=c(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).broadcasts.send(t);e.format==="json"?m(a,"json"):(p("Broadcast sent successfully!"),m({Success:a.success,Sent:a.sent,Total:a.total},"table"));}catch(o){l(o instanceof Error?o.message:"Failed to send broadcast"),process.exit(1);}}),i.command("schedule <broadcast_id>").description(`Schedule a broadcast for future delivery
2005
2008
 
2006
2009
  USAGE
2007
2010
  emailr broadcasts schedule <broadcast_id> --at <datetime> [options]
@@ -2051,7 +2054,7 @@ EXAMPLES
2051
2054
  emailr broadcasts schedule brd_abc123 --at "2024-12-25T10:00:00Z" --format json
2052
2055
 
2053
2056
  SEE ALSO
2054
- emailr broadcasts cancel Cancel a scheduled broadcast`).requiredOption("--at <datetime>","Schedule time (ISO 8601)").option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).broadcasts.schedule(t,e.at);e.format==="json"?c(a,"json"):(d("Broadcast scheduled successfully!"),c({ID:a.id,Name:a.name,Status:a.status,"Scheduled At":a.scheduled_at},"table"));}catch(o){l(o instanceof Error?o.message:"Failed to schedule broadcast"),process.exit(1);}}),i.command("cancel <broadcast_id>").description(`Cancel a scheduled broadcast
2057
+ emailr broadcasts cancel Cancel a scheduled broadcast`).requiredOption("--at <datetime>","Schedule time (ISO 8601)").option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=c(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).broadcasts.schedule(t,e.at);e.format==="json"?m(a,"json"):(p("Broadcast scheduled successfully!"),m({ID:a.id,Name:a.name,Status:a.status,"Scheduled At":a.scheduled_at},"table"));}catch(o){l(o instanceof Error?o.message:"Failed to schedule broadcast"),process.exit(1);}}),i.command("cancel <broadcast_id>").description(`Cancel a scheduled broadcast
2055
2058
 
2056
2059
  USAGE
2057
2060
  emailr broadcasts cancel <broadcast_id> [options]
@@ -2079,7 +2082,7 @@ EXAMPLES
2079
2082
  emailr broadcasts cancel brd_abc123 --format json
2080
2083
 
2081
2084
  NOTE
2082
- Broadcasts that are already 'sending' or 'sent' cannot be cancelled.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).broadcasts.cancel(t);e.format==="json"?c(a,"json"):d("Broadcast cancelled successfully!");}catch(o){l(o instanceof Error?o.message:"Failed to cancel broadcast"),process.exit(1);}}),i.command("update <broadcast_id>").description(`Update a broadcast
2085
+ Broadcasts that are already 'sending' or 'sent' cannot be cancelled.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=c(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).broadcasts.cancel(t);e.format==="json"?m(a,"json"):p("Broadcast cancelled successfully!");}catch(o){l(o instanceof Error?o.message:"Failed to cancel broadcast"),process.exit(1);}}),i.command("update <broadcast_id>").description(`Update a broadcast
2083
2086
 
2084
2087
  USAGE
2085
2088
  emailr broadcasts update <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)
@@ -2107,6 +2111,10 @@ OPTIONS
2107
2111
  --tags <tags> Update tags (comma-separated, replaces existing)
2108
2112
  --format <format> Output format: json | table (default: table)
2109
2113
 
2114
+ OUTPUT FORMATS
2115
+ --format json Full updated broadcast object with all fields
2116
+ --format table Summary table with ID, Name, Subject, Status, Tags, Scheduled At
2117
+
2110
2118
  EXAMPLES
2111
2119
  # Update broadcast name and subject
2112
2120
  emailr broadcasts update brd_abc123 --name "New Name" --subject "New Subject"
@@ -2127,7 +2135,7 @@ EXAMPLES
2127
2135
  emailr broadcasts update brd_abc123 --name "Updated" --format json
2128
2136
 
2129
2137
  NOTE
2130
- 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=m(),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.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"?c(n,"json"):(d("Broadcast updated successfully!"),c({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
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
2131
2139
 
2132
2140
  USAGE
2133
2141
  emailr broadcasts delete <broadcast_id> [options]
@@ -2155,7 +2163,7 @@ EXAMPLES
2155
2163
 
2156
2164
  WARNING
2157
2165
  This action is permanent and cannot be undone.
2158
- All delivery statistics will be lost.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).broadcasts.delete(t);e.format==="json"?c(a,"json"):d("Broadcast deleted successfully!");}catch(o){l(o instanceof Error?o.message:"Failed to delete broadcast"),process.exit(1);}}),i}function je(){let i=new Command("webhooks").description(`Manage webhooks
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
2159
2167
 
2160
2168
  USAGE
2161
2169
  emailr webhooks <subcommand> [options]
@@ -2308,7 +2316,7 @@ EXAMPLES
2308
2316
  emailr webhooks list --format json | jq '.[] | select(.active == true)'
2309
2317
 
2310
2318
  # Count webhooks
2311
- emailr webhooks list --format json | jq 'length'`).option("--format <format>","Output format (json|table)","table").action(async t=>{try{let e=m(),r=await new Emailr({apiKey:e.apiKey,baseUrl:e.baseUrl}).webhooks.list();if(t.format==="json")c(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"}));c(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
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
2312
2320
 
2313
2321
  USAGE
2314
2322
  emailr webhooks get <webhook_id> [options]
@@ -2339,7 +2347,7 @@ EXAMPLES
2339
2347
  emailr webhooks get whk_abc123 --format json
2340
2348
 
2341
2349
  # Extract just the secret
2342
- emailr webhooks get whk_abc123 --format json | jq -r '.secret'`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).webhooks.get(t);e.format==="json"?c(a,"json"):c({ID:a.id,Name:a.name,URL:a.url,Events:a.events.join(", "),Active:a.active?"Yes":"No",Secret:a.secret,"Created At":a.created_at},"table");}catch(o){l(o instanceof Error?o.message:"Failed to get webhook"),process.exit(1);}}),i.command("create").description(`Create a new webhook
2350
+ emailr webhooks get whk_abc123 --format json | jq -r '.secret'`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=c(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).webhooks.get(t);e.format==="json"?m(a,"json"):m({ID:a.id,Name:a.name,URL:a.url,Events:a.events.join(", "),Active:a.active?"Yes":"No",Secret:a.secret,"Created At":a.created_at},"table");}catch(o){l(o instanceof Error?o.message:"Failed to get webhook"),process.exit(1);}}),i.command("create").description(`Create a new webhook
2343
2351
 
2344
2352
  USAGE
2345
2353
  emailr webhooks create --name <name> --url <url> --events <events> [options]
@@ -2413,7 +2421,7 @@ EXAMPLES
2413
2421
 
2414
2422
  NOTE
2415
2423
  Save the webhook secret returned by this command. You'll need it
2416
- 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=m(),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"?c(a,"json"):(d("Webhook created successfully!"),c({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
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
2417
2425
 
2418
2426
  USAGE
2419
2427
  emailr webhooks update <webhook_id> [options]
@@ -2458,7 +2466,7 @@ EXAMPLES
2458
2466
  --events "email.delivered,email.bounced"
2459
2467
 
2460
2468
  # Get JSON output
2461
- 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=m(),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"?c(n,"json"):(d("Webhook updated successfully!"),c({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
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
2462
2470
 
2463
2471
  USAGE
2464
2472
  emailr webhooks enable <webhook_id> [options]
@@ -2482,7 +2490,7 @@ EXAMPLES
2482
2490
  emailr webhooks enable whk_abc123
2483
2491
 
2484
2492
  # Get JSON output
2485
- emailr webhooks enable whk_abc123 --format json`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).webhooks.enable(t);e.format==="json"?c(a,"json"):d("Webhook enabled successfully!");}catch(o){l(o instanceof Error?o.message:"Failed to enable webhook"),process.exit(1);}}),i.command("disable <webhook_id>").description(`Disable a webhook
2493
+ emailr webhooks enable whk_abc123 --format json`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=c(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).webhooks.enable(t);e.format==="json"?m(a,"json"):p("Webhook enabled successfully!");}catch(o){l(o instanceof Error?o.message:"Failed to enable webhook"),process.exit(1);}}),i.command("disable <webhook_id>").description(`Disable a webhook
2486
2494
 
2487
2495
  USAGE
2488
2496
  emailr webhooks disable <webhook_id> [options]
@@ -2511,7 +2519,7 @@ EXAMPLES
2511
2519
 
2512
2520
  NOTE
2513
2521
  Events are not queued while webhook is disabled. If you need to
2514
- temporarily stop processing, consider handling this in your endpoint.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).webhooks.disable(t);e.format==="json"?c(a,"json"):d("Webhook disabled successfully!");}catch(o){l(o instanceof Error?o.message:"Failed to disable webhook"),process.exit(1);}}),i.command("delete <webhook_id>").description(`Delete a webhook
2522
+ temporarily stop processing, consider handling this in your endpoint.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=c(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).webhooks.disable(t);e.format==="json"?m(a,"json"):p("Webhook disabled successfully!");}catch(o){l(o instanceof Error?o.message:"Failed to disable webhook"),process.exit(1);}}),i.command("delete <webhook_id>").description(`Delete a webhook
2515
2523
 
2516
2524
  USAGE
2517
2525
  emailr webhooks delete <webhook_id> [options]
@@ -2539,7 +2547,7 @@ EXAMPLES
2539
2547
 
2540
2548
  WARNING
2541
2549
  This action is permanent and cannot be undone.
2542
- 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=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).webhooks.delete(t);e.format==="json"?c(a,"json"):d("Webhook deleted successfully!");}catch(o){l(o instanceof Error?o.message:"Failed to delete webhook"),process.exit(1);}}),i}function Ie(){let i=new Command("segments").description(`Manage contact segments
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
2543
2551
 
2544
2552
  USAGE
2545
2553
  emailr segments <subcommand> [options]
@@ -2679,7 +2687,7 @@ EXAMPLES
2679
2687
  emailr segments list --format json
2680
2688
 
2681
2689
  # Pipe JSON to jq for processing
2682
- 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=m(),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")c(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()}));c(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
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
2683
2691
 
2684
2692
  USAGE
2685
2693
  emailr segments get <segment_id> [options]
@@ -2706,7 +2714,7 @@ EXAMPLES
2706
2714
  emailr segments get seg_abc123 --format json
2707
2715
 
2708
2716
  # Pipe JSON to jq to view conditions
2709
- emailr segments get seg_abc123 --format json | jq '.conditions'`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).segments.get(t);e.format==="json"?c(a,"json"):c({ID:a.id,Name:a.name,Description:a.description||"N/A",Conditions:JSON.stringify(a.conditions),Tags:a.tags?.join(", ")||"-","Created At":a.created_at,"Updated At":a.updated_at},"table");}catch(o){l(o instanceof Error?o.message:"Failed to get segment"),process.exit(1);}}),i.command("create").description(`Create a new segment
2717
+ emailr segments get seg_abc123 --format json | jq '.conditions'`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=c(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).segments.get(t);e.format==="json"?m(a,"json"):m({ID:a.id,Name:a.name,Description:a.description||"N/A",Conditions:JSON.stringify(a.conditions),Tags:a.tags?.join(", ")||"-","Created At":a.created_at,"Updated At":a.updated_at},"table");}catch(o){l(o instanceof Error?o.message:"Failed to get segment"),process.exit(1);}}),i.command("create").description(`Create a new segment
2710
2718
 
2711
2719
  USAGE
2712
2720
  emailr segments create --name <segment_name> --conditions <json> [options]
@@ -2756,7 +2764,7 @@ EXAMPLES
2756
2764
  # Get JSON output for scripting
2757
2765
  emailr segments create --name "Test" \\
2758
2766
  --conditions '[{"field": "subscribed", "operator": "equals", "value": true}]' \\
2759
- --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=m(),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"?c(n,"json"):(d("Segment created successfully!"),c({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
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
2760
2768
 
2761
2769
  USAGE
2762
2770
  emailr segments update <segment_id> [options]
@@ -2802,7 +2810,7 @@ EXAMPLES
2802
2810
  --conditions '[{"field": "metadata.plan", "operator": "equals", "value": "enterprise"}]'
2803
2811
 
2804
2812
  # Get JSON output
2805
- 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=m(),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"?c(n,"json"):(d("Segment updated successfully!"),c({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
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
2806
2814
 
2807
2815
  USAGE
2808
2816
  emailr segments delete <segment_id>
@@ -2827,7 +2835,7 @@ EXAMPLES
2827
2835
 
2828
2836
  WARNING
2829
2837
  This action is permanent and cannot be undone.
2830
- Any broadcasts targeting this segment will need to be updated.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).segments.delete(t);e.format==="json"?c(a,"json"):d("Segment deleted successfully!");}catch(o){l(o instanceof Error?o.message:"Failed to delete segment"),process.exit(1);}}),i.command("count <segment_id>").description(`Get the number of contacts in a segment
2838
+ Any broadcasts targeting this segment will need to be updated.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=c(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).segments.delete(t);e.format==="json"?m(a,"json"):p("Segment deleted successfully!");}catch(o){l(o instanceof Error?o.message:"Failed to delete segment"),process.exit(1);}}),i.command("count <segment_id>").description(`Get the number of contacts in a segment
2831
2839
 
2832
2840
  USAGE
2833
2841
  emailr segments count <segment_id> [options]
@@ -2858,7 +2866,7 @@ EXAMPLES
2858
2866
 
2859
2867
  TIP
2860
2868
  Use this before sending broadcasts to verify your segment
2861
- targets the expected number of contacts.`).option("--format <format>","Output format (json|table)","table").action(async(t,e)=>{try{let o=m(),a=await new Emailr({apiKey:o.apiKey,baseUrl:o.baseUrl}).segments.getContactsCount(t);e.format==="json"?c(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 st(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 lt(){return `<!DOCTYPE html>
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>
2862
2870
  <html lang="en">
2863
2871
  <head>
2864
2872
  <meta charset="UTF-8">
@@ -2904,7 +2912,7 @@ TIP
2904
2912
  <p>You can close this window and return to your terminal.</p>
2905
2913
  </div>
2906
2914
  </body>
2907
- </html>`}function ee(i){return `<!DOCTYPE html>
2915
+ </html>`}function ae(i){return `<!DOCTYPE html>
2908
2916
  <html lang="en">
2909
2917
  <head>
2910
2918
  <meta charset="UTF-8">
@@ -2959,7 +2967,7 @@ TIP
2959
2967
  <p style="margin-top: 1rem;">Please close this window and try again.</p>
2960
2968
  </div>
2961
2969
  </body>
2962
- </html>`}function Ce(){let i=null,t=0,e=null,o=null,r=null;return {async start(){return new Promise((a,n)=>{i=Je.createServer((s,p)=>{if(s.method!=="GET"||!s.url?.startsWith("/callback")){p.writeHead(404,{"Content-Type":"text/plain"}),p.end("Not Found");return}let b=st(s.url);if(r&&b.state!==r){p.writeHead(400,{"Content-Type":"text/html"}),p.end(ee("Security verification failed. State parameter mismatch.")),e&&e({success:false,error:"State parameter mismatch"});return}if(b.error){let h=b.message||b.error;p.writeHead(200,{"Content-Type":"text/html"}),p.end(ee(h)),e&&e({success:false,error:h});return}let T=b.key||b.code;if(T){p.writeHead(200,{"Content-Type":"text/html"}),p.end(lt()),e&&e({success:true,apiKey:T});return}p.writeHead(400,{"Content-Type":"text/html"}),p.end(ee("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 ct.randomBytes(32).toString("hex")}function Ue(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 $=120,pt=process.env.EMAILR_WEB_URL||"https://app.emailr.dev";function ut(i,t){let e=`http://127.0.0.1:${t}/callback`,o=new URLSearchParams({state:i,callback_url:e});return `${pt}/consent/authorize?${o.toString()}`}function Pe(){return new Command("login").description("Log in to Emailr via browser authentication").option("-t, --timeout <seconds>","Timeout in seconds",String($)).option("--no-browser","Don't automatically open the browser").action(async t=>{await ft({timeout:parseInt(t.timeout,10)||$,noBrowser:t.browser===false});})}async function ft(i){let t=Ce(),e=(i.timeout||$)*1e3;try{u("Starting authentication server...");let{port:o,url:r}=await t.start(),a=ke(),n=ut(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 Ue(n)?u("Browser opened. Please complete authentication in your browser."):(I("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||$}s)...`);let s=await t.waitForCallback(a,e);s.success&&s.apiKey?(G({apiKey:s.apiKey}),console.log(""),d("Login successful!"),u(`API key saved to: ${j()}`),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 ae=_.join(B.homedir(),".config","opencode","skills","emailr-cli"),wt=`---
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=`---
2963
2971
  name: emailr-cli
2964
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.
2965
2973
  ---
@@ -2999,7 +3007,7 @@ IMPORTANT: Always use \`--background\` flag so the command returns immediately a
2999
3007
  - Create: \`emailr templates create --name "Name" --subject "Subject" --html-file ./template.html\`
3000
3008
  - Update: \`emailr templates update <id> --html-file ./template.html\`
3001
3009
  - Delete: \`emailr templates delete <id>\`
3002
- `;function yt(){try{return execSync("which opencode",{stdio:"ignore"}),!0}catch{return false}}function St(){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 vt(){v.existsSync(ae)||v.mkdirSync(ae,{recursive:true});let i=_.join(ae,"SKILL.md");v.writeFileSync(i,wt,"utf-8");}function xe(){return new Command("agent").description(`Launch an AI agent with Emailr CLI expertise
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
3003
3011
 
3004
3012
  This opens OpenCode (opencode.ai), an AI coding agent that knows how to use all Emailr CLI commands.
3005
3013
  The agent can help you:
@@ -3007,10 +3015,363 @@ The agent can help you:
3007
3015
  - Manage contacts, broadcasts, and segments
3008
3016
  - Configure domains and webhooks
3009
3017
 
3010
- 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=>{yt()||(t.install?St()||(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(`
3011
- 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{vt(),d("Emailr CLI skill loaded");}catch(r){I(`Could not install skill: ${r instanceof Error?r.message:String(r)}`);}let e=[];t.model&&e.push("--model",t.model),console.log(`
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(`
3012
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.
3013
- `);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);});})}var g=new Command;g.name("emailr").description(`Emailr CLI - Send emails and manage your email infrastructure
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)
3022
+
3023
+ USAGE
3024
+ emailr inbox <subcommand> [options]
3025
+
3026
+ DESCRIPTION
3027
+ View and manage received (inbound) emails. List your inbox, read individual
3028
+ emails, view conversation threads, reply to emails, and forward them.
3029
+
3030
+ SUBCOMMANDS
3031
+ list List received emails with pagination and search
3032
+ get <id> View a specific received email in detail
3033
+ thread <id> View the full conversation thread for an email
3034
+ reply <id> Reply to a received email
3035
+ forward <id> Forward a received email to other recipients
3036
+
3037
+ OPTIONS
3038
+ --format <format> Output format: json | table (default: table)
3039
+
3040
+ EXAMPLES
3041
+ # List all received emails
3042
+ emailr inbox list
3043
+
3044
+ # List with pagination
3045
+ emailr inbox list --limit 10 --page 2
3046
+
3047
+ # Search by sender email
3048
+ emailr inbox list --email sender@example.com
3049
+
3050
+ # Filter by inbox
3051
+ emailr inbox list --inbox-id <inbox-uuid>
3052
+
3053
+ # View a specific email
3054
+ emailr inbox get <email-id>
3055
+
3056
+ # View conversation thread
3057
+ emailr inbox thread <email-id>
3058
+
3059
+ # Reply to an email
3060
+ emailr inbox reply <email-id> --html "<p>Thanks for your message!</p>"
3061
+
3062
+ # Reply from a file
3063
+ emailr inbox reply <email-id> --html-file ./reply.html
3064
+
3065
+ # Forward an email
3066
+ emailr inbox forward <email-id> --to recipient@example.com
3067
+
3068
+ # Forward with a message
3069
+ emailr inbox forward <email-id> --to recipient@example.com --message "FYI"
3070
+
3071
+ SEE ALSO
3072
+ emailr send Send individual emails
3073
+ emailr emails View all emails (sent and received)`);return i.command("list").description(`List received emails
3074
+
3075
+ USAGE
3076
+ emailr inbox list [options]
3077
+
3078
+ DESCRIPTION
3079
+ List all received (inbound) emails with optional search and pagination.
3080
+
3081
+ OPTIONS
3082
+ --limit <count> Number of emails to return (default: 20, max: 100)
3083
+ --page <number> Page number (default: 1)
3084
+ --email <address> Filter by sender email (partial match)
3085
+ --domain <domain> Filter by sender domain
3086
+ --inbox-id <id> Filter by inbox ID
3087
+ --format <format> Output format: json | table (default: table)
3088
+
3089
+ EXAMPLES
3090
+ emailr inbox list
3091
+ emailr inbox list --limit 50 --page 2
3092
+ emailr inbox list --email john@example.com
3093
+ emailr inbox list --domain example.com
3094
+ emailr inbox list --format json
3095
+
3096
+ # Filter by inbox
3097
+ emailr inbox list --inbox-id <inbox-uuid>
3098
+
3099
+ OUTPUT FORMATS
3100
+ --format json Machine-readable JSON with data array and pagination
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
3102
+
3103
+ USAGE
3104
+ emailr inbox get <email-id> [options]
3105
+
3106
+ DESCRIPTION
3107
+ View the full details of a received email including headers, content,
3108
+ and attachment information.
3109
+
3110
+ OPTIONS
3111
+ --content <type> Content to display: preview | text | html (default: preview)
3112
+ --format <format> Output format: json | table (default: table)
3113
+
3114
+ EXAMPLES
3115
+ emailr inbox get abc-123-def
3116
+ emailr inbox get abc-123-def --content html
3117
+ emailr inbox get abc-123-def --content text
3118
+ emailr inbox get abc-123-def --format json
3119
+
3120
+ OUTPUT FORMATS
3121
+ --format json Full email object with all fields as JSON
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
3123
+
3124
+ USAGE
3125
+ emailr inbox thread <email-id> [options]
3126
+
3127
+ DESCRIPTION
3128
+ View the full conversation thread for a given email. Shows all emails
3129
+ in the thread ordered chronologically, including both sent and received
3130
+ messages.
3131
+
3132
+ OPTIONS
3133
+ --format <format> Output format: json | table (default: table)
3134
+
3135
+ EXAMPLES
3136
+ emailr inbox thread abc-123-def
3137
+ emailr inbox thread abc-123-def --format json
3138
+
3139
+ OUTPUT FORMATS
3140
+ --format json JSON array of all emails in the thread
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
3142
+
3143
+ USAGE
3144
+ emailr inbox reply <email-id> [options]
3145
+
3146
+ DESCRIPTION
3147
+ Send a reply to a received email. The reply is automatically threaded
3148
+ with the original conversation. The To, From, and Subject fields are
3149
+ pre-filled from the original email.
3150
+
3151
+ OPTIONS
3152
+ --html <content> HTML content for the reply body
3153
+ --text <content> Plain text content for the reply body
3154
+ --html-file <path> Read HTML content from a file
3155
+ --text-file <path> Read plain text content from a file
3156
+ --from <email> Override the sender address
3157
+ --cc <emails> CC recipients (comma-separated)
3158
+ --bcc <emails> BCC recipients (comma-separated)
3159
+ --subject <subject> Override the reply subject
3160
+ --format <format> Output format: json | table (default: table)
3161
+
3162
+ EXAMPLES
3163
+ # Reply with inline HTML
3164
+ emailr inbox reply abc-123 --html "<p>Thanks for reaching out!</p>"
3165
+
3166
+ # Reply with plain text
3167
+ emailr inbox reply abc-123 --text "Thanks for reaching out!"
3168
+
3169
+ # Reply from a file
3170
+ emailr inbox reply abc-123 --html-file ./reply.html
3171
+
3172
+ # Reply with CC
3173
+ emailr inbox reply abc-123 --html "<p>See reply</p>" --cc manager@example.com
3174
+
3175
+ OUTPUT FORMATS
3176
+ --format json Machine-readable JSON with message_id and status
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
3178
+
3179
+ USAGE
3180
+ emailr inbox forward <email-id> --to <recipients> [options]
3181
+
3182
+ DESCRIPTION
3183
+ Forward a received email to one or more recipients. The original email
3184
+ content is included in the forwarded message.
3185
+
3186
+ OPTIONS
3187
+ --to <emails> Recipient email addresses (comma-separated, required)
3188
+ --message <text> Optional message to include above the forwarded content
3189
+ --format <format> Output format: json | table (default: table)
3190
+
3191
+ EXAMPLES
3192
+ # Forward to a single recipient
3193
+ emailr inbox forward abc-123 --to colleague@example.com
3194
+
3195
+ # Forward to multiple recipients
3196
+ emailr inbox forward abc-123 --to "a@example.com,b@example.com"
3197
+
3198
+ # Forward with a note
3199
+ emailr inbox forward abc-123 --to colleague@example.com --message "FYI - see below"
3200
+
3201
+ OUTPUT FORMATS
3202
+ --format json Machine-readable JSON with message_id and status
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
3014
3375
 
3015
3376
  USAGE
3016
3377
  emailr <command> [subcommand] [options]
@@ -3022,6 +3383,9 @@ DESCRIPTION
3022
3383
 
3023
3384
  COMMANDS
3024
3385
  send Send individual emails with HTML/text content or templates
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
3025
3389
  templates Create, edit, preview, and publish email templates
3026
3390
  contacts Manage email contacts and their metadata
3027
3391
  segments Create and manage contact segments with conditions
@@ -3059,6 +3423,21 @@ EXAMPLES
3059
3423
  emailr send --to user@example.com --template tpl_abc123 \\
3060
3424
  --template-data '{"name": "John"}'
3061
3425
 
3426
+ # List received emails in inbox
3427
+ emailr inbox list
3428
+
3429
+ # View a received email
3430
+ emailr inbox get <email-id>
3431
+
3432
+ # View conversation thread
3433
+ emailr inbox thread <email-id>
3434
+
3435
+ # Reply to a received email
3436
+ emailr inbox reply <email-id> --html "<p>Thanks!</p>"
3437
+
3438
+ # Forward a received email
3439
+ emailr inbox forward <email-id> --to colleague@example.com
3440
+
3062
3441
  # List all templates
3063
3442
  emailr templates list
3064
3443
 
@@ -3096,4 +3475,4 @@ AGENTIC WORKFLOW
3096
3475
 
3097
3476
  MORE INFORMATION
3098
3477
  Run 'emailr <command> --help' for detailed help on any command.
3099
- Run 'emailr <command> <subcommand> --help' for subcommand details.`).version("1.7.7");g.addCommand(ce());g.addCommand(me());g.addCommand(Oe());g.addCommand(Ee());g.addCommand(Ne());g.addCommand(je());g.addCommand(Ie());g.addCommand(_e());g.addCommand(Pe());g.addCommand(xe());g.parse();
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();