use clap::{Args, Parser, Subcommand};
use std::path::PathBuf;
fn parse_resend_limit(raw: &str) -> Result<usize, String> {
let value: usize = raw
.parse()
.map_err(|err: std::num::ParseIntError| err.to_string())?;
if !(1..=100).contains(&value) {
return Err(format!("must be a number between 1 and 100, got {}", value));
}
Ok(value)
}
#[derive(Parser)]
#[command(
name = "email-cli",
version,
about = "Agent-friendly email CLI for Resend"
)]
pub struct Cli {
#[arg(long, global = true)]
pub db: Option<PathBuf>,
#[arg(long, global = true)]
pub json: bool,
#[command(subcommand)]
pub command: Command,
}
#[derive(Subcommand)]
pub enum Command {
Profile {
#[command(subcommand)]
command: ProfileCommand,
},
Account {
#[command(subcommand)]
command: AccountCommand,
},
Signature {
#[command(subcommand)]
command: SignatureCommand,
},
Send(SendArgs),
Reply(ReplyArgs),
Forward(ForwardArgs),
Daemon(DaemonArgs),
Draft {
#[command(subcommand)]
command: DraftCommand,
},
Sync(SyncArgs),
Inbox {
#[command(subcommand)]
command: InboxCommand,
},
Attachments {
#[command(subcommand)]
command: AttachmentsCommand,
},
Domain {
#[command(subcommand)]
command: DomainCommand,
},
Contact {
#[command(subcommand)]
command: ContactCommand,
},
Batch {
#[command(subcommand)]
command: BatchCommand,
},
ApiKey {
#[command(subcommand)]
command: ApiKeyCommand,
},
Outbox {
#[command(subcommand)]
command: OutboxCommand,
},
Webhook {
#[command(subcommand)]
command: WebhookCommand,
},
Events {
#[command(subcommand)]
command: EventsCommand,
},
Email {
#[command(subcommand)]
command: EmailCommand,
},
Broadcast {
#[command(subcommand)]
command: BroadcastCommand,
},
#[command(name = "contact-property")]
ContactProperty {
#[command(subcommand)]
command: ContactPropertyCommand,
},
Topic {
#[command(subcommand)]
command: TopicCommand,
},
Segment {
#[command(subcommand)]
command: SegmentCommand,
},
Update {
#[arg(long)]
check: bool,
},
Log(LogArgs),
AgentInfo,
Skill {
#[command(subcommand)]
action: SkillAction,
},
Completions {
shell: clap_complete::Shell,
},
}
#[derive(Subcommand)]
pub enum ProfileCommand {
Add(ProfileAddArgs),
#[command(visible_alias = "ls")]
List,
Test(ProfileTestArgs),
}
#[derive(Args)]
pub struct ProfileAddArgs {
pub name: String,
#[arg(long)]
pub api_key: Option<String>,
#[arg(long)]
pub api_key_env: Option<String>,
#[arg(long)]
pub api_key_file: Option<PathBuf>,
#[arg(long, default_value = "RESEND_API_KEY")]
pub api_key_name: String,
}
#[derive(Args)]
pub struct ProfileTestArgs {
pub name: String,
}
#[derive(Subcommand)]
pub enum AccountCommand {
Add(AccountAddArgs),
#[command(visible_alias = "ls")]
List,
Use(AccountUseArgs),
}
#[derive(Args)]
pub struct AccountAddArgs {
pub email: String,
#[arg(long)]
pub profile: String,
#[arg(long)]
pub name: Option<String>,
#[arg(long)]
pub signature: Option<String>,
#[arg(long)]
pub default: bool,
}
#[derive(Args)]
pub struct AccountUseArgs {
pub email: String,
}
#[derive(Subcommand)]
pub enum SignatureCommand {
Set(SignatureSetArgs),
Show(SignatureShowArgs),
}
#[derive(Args)]
pub struct SignatureSetArgs {
pub account: String,
#[arg(long)]
pub text: String,
}
#[derive(Args)]
pub struct SignatureShowArgs {
pub account: String,
}
#[derive(Args, Clone)]
pub struct ComposeArgs {
#[arg(long, visible_alias = "from")]
pub account: Option<String>,
#[arg(long, required_unless_present = "reply_to_msg")]
pub to: Vec<String>,
#[arg(long)]
pub cc: Vec<String>,
#[arg(long)]
pub bcc: Vec<String>,
#[arg(long, default_value = "")]
pub subject: String,
#[arg(long)]
pub reply_to_msg: Option<i64>,
#[arg(long)]
pub text: Option<String>,
#[arg(long)]
pub text_file: Option<PathBuf>,
#[arg(long)]
pub html: Option<String>,
#[arg(long)]
pub html_file: Option<PathBuf>,
#[arg(long = "attach")]
pub attachments: Vec<PathBuf>,
}
#[derive(Args)]
pub struct SendArgs {
#[command(flatten)]
pub compose: ComposeArgs,
}
#[derive(Args)]
pub struct ReplyArgs {
pub message_id: i64,
#[arg(long, visible_alias = "from")]
pub account: Option<String>,
#[arg(long)]
pub all: bool,
#[arg(long)]
pub text: Option<String>,
#[arg(long)]
pub text_file: Option<PathBuf>,
#[arg(long)]
pub html: Option<String>,
#[arg(long)]
pub html_file: Option<PathBuf>,
#[arg(long = "attach")]
pub attachments: Vec<PathBuf>,
}
#[derive(Args)]
pub struct LogArgs {
#[arg(long, default_value = "25")]
pub limit: usize,
}
#[derive(Args)]
pub struct DaemonArgs {
#[arg(long)]
pub account: Option<String>,
#[arg(long, default_value = "60")]
pub interval: u64,
}
#[derive(Args)]
pub struct ForwardArgs {
pub message_id: i64,
#[arg(long, visible_alias = "from")]
pub account: Option<String>,
#[arg(long, required = true)]
pub to: Vec<String>,
#[arg(long)]
pub cc: Vec<String>,
#[arg(long)]
pub bcc: Vec<String>,
#[arg(long)]
pub text: Option<String>,
}
#[derive(Subcommand)]
pub enum DraftCommand {
#[command(visible_alias = "new")]
Create(DraftCreateArgs),
#[command(visible_alias = "ls")]
List(DraftListArgs),
Show(DraftShowArgs),
Send(DraftSendArgs),
Edit(DraftEditArgs),
#[command(visible_alias = "rm")]
Delete(DraftDeleteArgs),
}
#[derive(Args)]
pub struct DraftEditArgs {
pub id: String,
#[arg(long)]
pub subject: Option<String>,
#[arg(long)]
pub text: Option<String>,
#[arg(long)]
pub html: Option<String>,
#[arg(long)]
pub to: Option<Vec<String>>,
#[arg(long)]
pub cc: Option<Vec<String>>,
#[arg(long)]
pub bcc: Option<Vec<String>>,
}
#[derive(Args)]
pub struct DraftDeleteArgs {
pub id: String,
}
#[derive(Args)]
pub struct DraftCreateArgs {
#[command(flatten)]
pub compose: ComposeArgs,
#[arg(long)]
pub reply_to: Option<i64>,
}
#[derive(Args)]
pub struct DraftListArgs {
#[arg(long)]
pub account: Option<String>,
}
#[derive(Args)]
pub struct DraftShowArgs {
pub id: String,
}
#[derive(Args)]
pub struct DraftSendArgs {
pub id: String,
}
#[derive(Args)]
pub struct SyncArgs {
#[arg(long)]
pub account: Option<String>,
#[arg(long, default_value = "25")]
pub limit: usize,
#[arg(long)]
pub watch: bool,
#[arg(long, default_value = "60")]
pub interval: Option<u64>,
#[arg(long)]
pub notify: bool,
}
#[derive(Subcommand)]
pub enum InboxCommand {
#[command(visible_alias = "ls")]
List(InboxListArgs),
Sync(InboxSyncArgs),
Read(InboxReadArgs),
Mark(InboxMarkArgs),
#[command(visible_alias = "rm")]
Delete(InboxDeleteArgs),
Archive(InboxArchiveArgs),
Unarchive(InboxUnarchiveArgs),
Thread(InboxThreadArgs),
Search(InboxSearchArgs),
Purge(InboxPurgeArgs),
Stats(InboxStatsArgs),
}
#[derive(Args)]
pub struct InboxSyncArgs {
#[arg(long)]
pub account: Option<String>,
#[arg(long, default_value = "25")]
pub limit: usize,
}
#[derive(Args)]
pub struct InboxListArgs {
#[arg(long)]
pub account: Option<String>,
#[arg(long, default_value = "25")]
pub limit: usize,
#[arg(long)]
pub unread: bool,
#[arg(long)]
pub archived: bool,
#[arg(long)]
pub after: Option<i64>,
}
#[derive(Args)]
pub struct InboxReadArgs {
pub id: i64,
#[arg(long, default_value = "true", action = clap::ArgAction::Set)]
pub mark_read: bool,
#[arg(long)]
pub raw: bool,
}
#[derive(Args)]
pub struct InboxMarkArgs {
pub ids: Vec<i64>,
#[arg(long, group = "state")]
pub read: bool,
#[arg(long, group = "state")]
pub unread: bool,
}
#[derive(Args)]
pub struct InboxDeleteArgs {
pub ids: Vec<i64>,
}
#[derive(Args)]
pub struct InboxArchiveArgs {
pub ids: Vec<i64>,
}
#[derive(Args)]
pub struct InboxUnarchiveArgs {
pub ids: Vec<i64>,
}
#[derive(Args)]
pub struct InboxThreadArgs {
pub id: i64,
}
#[derive(Args)]
pub struct InboxSearchArgs {
pub query: String,
#[arg(long)]
pub account: Option<String>,
#[arg(long, default_value = "25")]
pub limit: usize,
}
#[derive(Args)]
pub struct InboxStatsArgs {
#[arg(long)]
pub account: Option<String>,
}
#[derive(Args)]
pub struct InboxPurgeArgs {
#[arg(long)]
pub before: String,
#[arg(long)]
pub account: Option<String>,
}
#[derive(Subcommand)]
pub enum AttachmentsCommand {
#[command(visible_alias = "ls")]
List(AttachmentListArgs),
#[command(visible_alias = "show")]
Get(AttachmentGetArgs),
}
#[derive(Args)]
pub struct AttachmentListArgs {
pub message_id: i64,
}
#[derive(Args)]
pub struct AttachmentGetArgs {
pub message_id: i64,
pub attachment_id: String,
#[arg(long)]
pub output: Option<PathBuf>,
}
#[derive(Subcommand)]
pub enum SkillAction {
Install,
Status,
}
#[derive(Subcommand)]
pub enum DomainCommand {
#[command(visible_alias = "ls")]
List,
#[command(visible_alias = "show")]
Get(DomainGetArgs),
#[command(visible_alias = "new")]
Create(DomainCreateArgs),
Verify(DomainVerifyArgs),
#[command(visible_alias = "rm")]
Delete(DomainDeleteArgs),
Update(DomainUpdateArgs),
}
#[derive(Args)]
pub struct DomainGetArgs {
pub id: String,
}
#[derive(Args)]
pub struct DomainCreateArgs {
#[arg(long)]
pub name: String,
#[arg(long)]
pub region: Option<String>,
}
#[derive(Args)]
pub struct DomainVerifyArgs {
pub id: String,
}
#[derive(Args)]
pub struct DomainDeleteArgs {
pub id: String,
}
#[derive(Args)]
pub struct DomainUpdateArgs {
pub id: String,
#[arg(long)]
pub open_tracking: Option<bool>,
#[arg(long)]
pub click_tracking: Option<bool>,
}
#[derive(Subcommand)]
pub enum ContactCommand {
#[command(visible_alias = "ls")]
List(ContactListArgs),
#[command(visible_alias = "show")]
Get(ContactGetArgs),
#[command(visible_alias = "new")]
Create(ContactCreateArgs),
Update(ContactUpdateArgs),
#[command(visible_alias = "rm")]
Delete(ContactDeleteArgs),
}
#[derive(Args)]
pub struct ContactListArgs {
#[arg(long, default_value = "50", value_parser = parse_resend_limit)]
pub limit: usize,
#[arg(long)]
pub after: Option<String>,
}
#[derive(Args)]
pub struct ContactGetArgs {
pub id_or_email: String,
}
#[derive(Args)]
pub struct ContactCreateArgs {
#[arg(long)]
pub email: String,
#[arg(long)]
pub first_name: Option<String>,
#[arg(long)]
pub last_name: Option<String>,
#[arg(long)]
pub unsubscribed: Option<bool>,
#[arg(long, value_name = "JSON")]
pub properties: Option<String>,
#[arg(long, value_name = "ID,ID,...")]
pub segments: Option<String>,
#[arg(long, value_name = "TOPIC:STATE,...")]
pub topics: Option<String>,
}
#[derive(Args)]
pub struct ContactUpdateArgs {
pub id_or_email: String,
#[arg(long)]
pub first_name: Option<String>,
#[arg(long)]
pub last_name: Option<String>,
#[arg(long)]
pub unsubscribed: Option<bool>,
#[arg(long, value_name = "JSON")]
pub properties: Option<String>,
}
#[derive(Args)]
pub struct ContactDeleteArgs {
pub id_or_email: String,
}
#[derive(Subcommand)]
pub enum BatchCommand {
Send(BatchSendArgs),
}
#[derive(Args)]
pub struct BatchSendArgs {
#[arg(long)]
pub file: std::path::PathBuf,
}
#[derive(Subcommand)]
pub enum ApiKeyCommand {
#[command(visible_alias = "ls")]
List,
#[command(visible_alias = "new")]
Create(ApiKeyCreateArgs),
#[command(visible_alias = "rm")]
Delete(ApiKeyDeleteArgs),
}
#[derive(Args)]
pub struct ApiKeyCreateArgs {
#[arg(long)]
pub name: String,
#[arg(long, default_value = "full-access")]
pub permission: String,
}
#[derive(Args)]
pub struct ApiKeyDeleteArgs {
pub id: String,
}
#[derive(Subcommand)]
pub enum OutboxCommand {
#[command(visible_alias = "ls")]
List,
Retry(OutboxRetryArgs),
Flush,
}
#[derive(Args)]
pub struct OutboxRetryArgs {
pub id: String,
}
#[derive(Subcommand)]
pub enum WebhookCommand {
Listen(WebhookListenArgs),
}
#[derive(Args)]
pub struct WebhookListenArgs {
#[arg(long, default_value = "8080")]
pub port: u16,
#[arg(long)]
pub notify: bool,
}
#[derive(Subcommand)]
pub enum EventsCommand {
#[command(visible_alias = "ls")]
List(EventsListArgs),
}
#[derive(Args)]
pub struct EventsListArgs {
#[arg(long)]
pub message: Option<i64>,
#[arg(long, default_value = "50")]
pub limit: usize,
}
#[derive(Subcommand)]
pub enum EmailCommand {
#[command(visible_alias = "ls")]
List(EmailListArgs),
}
#[derive(Args)]
pub struct EmailListArgs {
#[arg(long, default_value = "20", value_parser = parse_resend_limit)]
pub limit: usize,
#[arg(long)]
pub after: Option<String>,
}
#[derive(Subcommand)]
pub enum BroadcastCommand {
#[command(visible_alias = "ls")]
List,
#[command(visible_alias = "show")]
Get(BroadcastGetArgs),
#[command(visible_alias = "new")]
Create(BroadcastCreateArgs),
Update(BroadcastUpdateArgs),
Send(BroadcastSendArgs),
#[command(visible_alias = "rm")]
Delete(BroadcastDeleteArgs),
}
#[derive(Args)]
pub struct BroadcastUpdateArgs {
pub id: String,
#[arg(long)]
pub segment_id: Option<String>,
#[arg(long)]
pub from: Option<String>,
#[arg(long)]
pub subject: Option<String>,
#[arg(long)]
pub html: Option<String>,
#[arg(long)]
pub text: Option<String>,
#[arg(long)]
pub name: Option<String>,
#[arg(long)]
pub reply_to: Option<String>,
#[arg(long)]
pub topic_id: Option<String>,
}
#[derive(Args)]
pub struct BroadcastGetArgs {
pub id: String,
}
#[derive(Args)]
pub struct BroadcastCreateArgs {
#[arg(long, visible_alias = "audience-id")]
pub segment_id: String,
#[arg(long)]
pub from: String,
#[arg(long)]
pub subject: String,
#[arg(long)]
pub html: Option<String>,
#[arg(long)]
pub text: Option<String>,
#[arg(long)]
pub name: Option<String>,
#[arg(long)]
pub reply_to: Option<String>,
#[arg(long)]
pub topic_id: Option<String>,
#[arg(long)]
pub scheduled_at: Option<String>,
#[arg(long)]
pub send: bool,
}
#[derive(Args)]
pub struct BroadcastSendArgs {
pub id: String,
#[arg(long)]
pub scheduled_at: Option<String>,
}
#[derive(Args)]
pub struct BroadcastDeleteArgs {
pub id: String,
}
#[derive(Subcommand)]
pub enum ContactPropertyCommand {
#[command(visible_alias = "ls")]
List,
#[command(visible_alias = "show")]
Get(ContactPropertyGetArgs),
#[command(visible_alias = "new")]
Create(ContactPropertyCreateArgs),
Update(ContactPropertyUpdateArgs),
#[command(visible_alias = "rm")]
Delete(ContactPropertyDeleteArgs),
}
#[derive(Args)]
pub struct ContactPropertyUpdateArgs {
pub id: String,
#[arg(long)]
pub fallback: Option<String>,
#[arg(long)]
pub as_number: bool,
}
#[derive(Args)]
pub struct ContactPropertyGetArgs {
pub id: String,
}
#[derive(Args)]
pub struct ContactPropertyCreateArgs {
#[arg(long)]
pub key: String,
#[arg(long, default_value = "string")]
pub property_type: String,
#[arg(long)]
pub fallback: Option<String>,
}
#[derive(Args)]
pub struct ContactPropertyDeleteArgs {
pub id: String,
}
#[derive(Subcommand)]
pub enum TopicCommand {
#[command(visible_alias = "ls")]
List,
#[command(visible_alias = "show")]
Get(TopicGetArgs),
#[command(visible_alias = "new")]
Create(TopicCreateArgs),
Update(TopicUpdateArgs),
#[command(visible_alias = "rm")]
Delete(TopicDeleteArgs),
ContactSet(TopicContactSetArgs),
ContactList(TopicContactListArgs),
}
#[derive(Args)]
pub struct TopicUpdateArgs {
pub id: String,
#[arg(long)]
pub name: Option<String>,
#[arg(long)]
pub description: Option<String>,
#[arg(long)]
pub default_subscription: Option<String>,
#[arg(long)]
pub visibility: Option<String>,
}
#[derive(Args)]
pub struct TopicContactListArgs {
#[arg(long)]
pub contact: String,
}
#[derive(Args)]
pub struct TopicGetArgs {
pub id: String,
}
#[derive(Args)]
pub struct TopicCreateArgs {
#[arg(long)]
pub name: String,
#[arg(long)]
pub description: Option<String>,
#[arg(long)]
pub default_subscription: Option<String>,
#[arg(long)]
pub visibility: Option<String>,
}
#[derive(Args)]
pub struct TopicDeleteArgs {
pub id: String,
}
#[derive(Args)]
pub struct TopicContactSetArgs {
#[arg(long)]
pub contact: String,
#[arg(long)]
pub topic: String,
#[arg(long)]
pub subscription: String,
}
#[derive(Subcommand)]
pub enum SegmentCommand {
#[command(visible_alias = "ls")]
List,
#[command(visible_alias = "show")]
Get(SegmentGetArgs),
#[command(visible_alias = "new")]
Create(SegmentCreateArgs),
#[command(visible_alias = "rm")]
Delete(SegmentDeleteArgs),
ContactAdd(SegmentContactArgs),
ContactRemove(SegmentContactArgs),
ContactList(SegmentContactListArgs),
Contacts(SegmentContactsArgs),
}
#[derive(Args)]
pub struct SegmentContactsArgs {
pub id: String,
}
#[derive(Args)]
pub struct SegmentGetArgs {
pub id: String,
}
#[derive(Args)]
pub struct SegmentCreateArgs {
#[arg(long)]
pub name: String,
}
#[derive(Args)]
pub struct SegmentDeleteArgs {
pub id: String,
}
#[derive(Args)]
pub struct SegmentContactArgs {
#[arg(long)]
pub contact: String,
#[arg(long)]
pub segment: String,
}
#[derive(Args)]
pub struct SegmentContactListArgs {
#[arg(long)]
pub contact: String,
}