Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .agents/skills/custom-commands/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ with the following sub-clients:
| Field | Type | Description |
|-------|------|-------------|
| `client.inboxes` | `agentmail_sdk::api::InboxesClient` | inboxes operations |
| `client.accounts` | `agentmail_sdk::api::AccountsClient2` | accounts operations |
| `client.api_keys` | `agentmail_sdk::api::ApiKeysClient2` | api_keys operations |
| `client.drafts` | `agentmail_sdk::api::DraftsClient2` | drafts operations |
| `client.events` | `agentmail_sdk::api::EventsClient` | events operations |
Expand All @@ -75,6 +76,7 @@ with the following sub-clients:
| `client.threads` | `agentmail_sdk::api::ThreadsClient2` | threads operations |
| `client.webhooks` | `agentmail_sdk::api::WebhooksClient2` | webhooks operations |
| `client.pods` | `agentmail_sdk::api::PodsClient` | pods operations |
| `client.accounts` | `agentmail_sdk::api::AccountsClient3` | accounts operations |
| `client.api_keys` | `agentmail_sdk::api::ApiKeysClient3` | api_keys operations |
| `client.domains` | `agentmail_sdk::api::DomainsClient2` | domains operations |
| `client.drafts` | `agentmail_sdk::api::DraftsClient3` | drafts operations |
Expand Down
8 changes: 7 additions & 1 deletion .fern/replay.lock
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,13 @@ generations:
cli_version: unknown
generator_versions:
fernapi/fern-cli-generator: 0.38.10
current_generation: b2a6b08f26e2b126570ae386315f506079313666
- commit_sha: aa8950f5e5516cde201a90cd7a2913b95d7953c9
tree_hash: b8329dde47746bde6cedc58d88ecb7c887919c1f
timestamp: 2026-09-25T23:21:57.989Z
cli_version: unknown
generator_versions:
fernapi/fern-cli-generator: 0.38.10
current_generation: aa8950f5e5516cde201a90cd7a2913b95d7953c9
patches:
- id: patch-bf63549e
content_hash: sha256:a660ef1be2e6211b2d9aee152022a339ffd879d56f0e8b0b557ce0fb5e4d9b5c
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "agentmail-cli"
version = "1.5.0"
version = "1.6.0"
edition = "2021"
description = "Command-line interface for the AgentMail API. Send, receive, reply, and manage threaded email conversations from your terminal."
license = "MIT"
Expand Down
82 changes: 81 additions & 1 deletion agentmail-sdk/src/api/resources/accounts/accounts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ impl AccountsClient {
})
}

/// Lists accounts across all providers.
/// Lists accounts across all providers, scoped to the API key: an
/// organization key sees every account, a pod key its pod's, an inbox key
/// its inbox's. Requires `inbox_read`.
///
/// # Arguments
///
Expand Down Expand Up @@ -66,6 +68,17 @@ impl AccountsClient {
.await
}

/// Returns one account by ID. An account outside the key's scope is a 404.
/// Requires `inbox_read`.
///
/// # Arguments
///
/// * `options` - Additional request options such as headers, timeout, etc.
///
/// # Returns
///
/// JSON response from the API
///
/// # Examples
///
/// ```no_run
Expand Down Expand Up @@ -99,4 +112,71 @@ impl AccountsClient {
)
.await
}

/// Updates one account. Set `status` to `disabled` to stop the inbox from
/// signing in at the provider again, or to `enabled` to re-enable it.
/// Idempotent: disabling an already disabled account keeps its original
/// `disabled_at`, and enabling an enabled account is a no-op.
///
/// Find the `account_id` with List Accounts. An account exists only after an
/// inbox's first sign-in at a provider, so it cannot be disabled in advance.
/// A disable applies to that inbox at that provider whichever sign-in key is
/// used: the provider's next authorization ends in `access_denied`, and a code
/// issued earlier is refused with `invalid_grant`. Access tokens already
/// issued stay valid until they expire, and the provider's own session is
/// unaffected.
///
/// Requires `account_update`, which sign-in keys (`type: public_key`) cannot
/// hold, so call this with a bearer API key. An account outside the key's
/// scope is a 404. A 409 means the account changed during the write; read it
/// again and retry.
///
/// # Arguments
///
/// * `options` - Additional request options such as headers, timeout, etc.
///
/// # Returns
///
/// JSON response from the API
///
/// # Examples
///
/// ```no_run
/// use agentmail_sdk::prelude::*;
///
/// #[tokio::main]
/// async fn main() {
/// let config = ClientConfig {
/// token: Some("<token>".to_string()),
/// ..Default::default()
/// };
/// let client = AgentmailClient::new(config).expect("Failed to build client");
/// client
/// .accounts
/// .update(
/// &AccountID("account_id".to_string()),
/// &UpdateAccountRequest {
/// ..Default::default()
/// },
/// None,
/// )
/// .await;
/// }
/// ```
pub async fn update(
&self,
account_id: &AccountId,
request: &UpdateAccountRequest,
options: Option<RequestOptions>,
) -> Result<Account, ApiError> {
self.http_client
.execute_request(
Method::PATCH,
&format!("v0/accounts/{}/update", account_id.0),
Some(serde_json::to_value(request).map_err(ApiError::Serialization)?),
None,
options,
)
.await
}
}
122 changes: 122 additions & 0 deletions agentmail-sdk/src/api/resources/inboxes/accounts/inboxes_accounts.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
use crate::api::*;
use crate::{ApiError, ClientConfig, HttpClient, QueryBuilder, RequestOptions};
use reqwest::Method;

pub struct AccountsClient2 {
pub http_client: HttpClient,
}

impl AccountsClient2 {
pub fn new(config: ClientConfig) -> Result<Self, ApiError> {
Ok(Self {
http_client: HttpClient::new(config.clone())?,
})
}

/// Lists accounts held by the inbox, across all providers. Requires `inbox_read`.
///
/// # Arguments
///
/// * `options` - Additional request options such as headers, timeout, etc.
///
/// # Returns
///
/// JSON response from the API
///
/// # Examples
///
/// ```no_run
/// use agentmail_sdk::prelude::*;
///
/// #[tokio::main]
/// async fn main() {
/// let config = ClientConfig {
/// token: Some("<token>".to_string()),
/// ..Default::default()
/// };
/// let client = AgentmailClient::new(config).expect("Failed to build client");
/// client
/// .inboxes
/// .accounts
/// .list(
/// &InboxesInboxID("inbox_id".to_string()),
/// &InboxesAccountsListQueryRequest {
/// ..Default::default()
/// },
/// None,
/// )
/// .await;
/// }
/// ```
pub async fn list(
&self,
inbox_id: &InboxesInboxId,
request: &InboxesAccountsListQueryRequest,
options: Option<RequestOptions>,
) -> Result<ListAccountsResponse, ApiError> {
self.http_client
.execute_request(
Method::GET,
&format!("v0/inboxes/{}/accounts", inbox_id.0),
None,
QueryBuilder::new()
.serialize("limit", request.limit.clone())
.serialize("page_token", request.page_token.clone())
.serialize("ascending", request.ascending.clone())
.build(),
options,
)
.await
}

/// Returns one account held by the inbox. An account elsewhere is a 404. Requires
/// `inbox_read`.
///
/// # Arguments
///
/// * `options` - Additional request options such as headers, timeout, etc.
///
/// # Returns
///
/// JSON response from the API
///
/// # Examples
///
/// ```no_run
/// use agentmail_sdk::prelude::*;
///
/// #[tokio::main]
/// async fn main() {
/// let config = ClientConfig {
/// token: Some("<token>".to_string()),
/// ..Default::default()
/// };
/// let client = AgentmailClient::new(config).expect("Failed to build client");
/// client
/// .inboxes
/// .accounts
/// .get(
/// &InboxesInboxID("inbox_id".to_string()),
/// &AccountID("account_id".to_string()),
/// None,
/// )
/// .await;
/// }
/// ```
pub async fn get(
&self,
inbox_id: &InboxesInboxId,
account_id: &AccountId,
options: Option<RequestOptions>,
) -> Result<Account, ApiError> {
self.http_client
.execute_request(
Method::GET,
&format!("v0/inboxes/{}/accounts/{}", inbox_id.0, account_id.0),
None,
None,
options,
)
.await
}
}
2 changes: 2 additions & 0 deletions agentmail-sdk/src/api/resources/inboxes/accounts/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod inboxes_accounts;
pub use inboxes_accounts::AccountsClient2;
80 changes: 80 additions & 0 deletions agentmail-sdk/src/api/resources/inboxes/metrics/inboxes_metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,4 +155,84 @@ impl MetricsClient2 {
)
.await
}

/// Rolling bounce and complaint rates for the inbox. At each `period`
/// grid point, the bounced (or complained) messages over the preceding
/// `window` divided by the messages sent over the same window, with the
/// send count alongside. Account moderation evaluates the organization-wide
/// rate, so use the organization endpoint to see the number it acts on;
/// the inbox view shows which inboxes contribute. Defaults to the rolling
/// 24-hour rate sampled hourly over the last day; `start` must be within
/// the last 90 days, `window` must be a whole multiple of `period`, and
/// the range plus window divided by `period` must not exceed 1000
/// buckets.
///
/// **CLI:**
/// ```bash
/// agentmail inboxes metrics query-rates --inbox-id <inbox_id>
/// ```
///
/// # Arguments
///
/// * `options` - Additional request options such as headers, timeout, etc.
///
/// # Returns
///
/// JSON response from the API
///
/// # Examples
///
/// ```no_run
/// use agentmail_sdk::prelude::*;
///
/// #[tokio::main]
/// async fn main() {
/// let config = ClientConfig {
/// token: Some("<token>".to_string()),
/// ..Default::default()
/// };
/// let client = AgentmailClient::new(config).expect("Failed to build client");
/// client
/// .inboxes
/// .metrics
/// .query_rates(
/// &InboxesInboxID("inbox_id".to_string()),
/// &InboxesMetricsQueryRatesQueryRequest {
/// rate_types: vec![],
/// start: None,
/// end: None,
/// period: None,
/// window: None,
/// limit: None,
/// descending: None,
/// },
/// None,
/// )
/// .await;
/// }
/// ```
pub async fn query_rates(
&self,
inbox_id: &InboxesInboxId,
request: &InboxesMetricsQueryRatesQueryRequest,
options: Option<RequestOptions>,
) -> Result<QueryRatesResponse, ApiError> {
self.http_client
.execute_request(
Method::GET,
&format!("v0/inboxes/{}/metrics/rates", inbox_id.0),
None,
QueryBuilder::new()
.serialize_array("rate_types", request.rate_types.clone())
.serialize("start", request.start.clone())
.serialize("end", request.end.clone())
.serialize("period", request.period.clone())
.serialize("window", request.window.clone())
.serialize("limit", request.limit.clone())
.serialize("descending", request.descending.clone())
.build(),
options,
)
.await
}
}
Loading
Loading