tools tier

tools-mail-manager

Thin CLI dispatch over mail-sync: composite-account (paired MailReader/MailSender) config, sync/send/accounts commands. Sprint 3.45 crate 11 — mm shrinks to dispatch-only, provider selection lives in config, TUI stays out of v1.

Thin CLI dispatch over mail-sync: composite-account (paired MailReader/MailSender) config, sync/send/accounts commands. Sprint 3.45 crate 11 — mm shrinks to dispatch-only, provider selection lives in config, TUI stays out of v1.

Tiertools
Roleunclassified (baselined)
Pathcrates/tools/mail-manager
Edition2021
Targetstools-mail-manager, tools_mail_manager
Public items35 across 7 modules
Tests38

What it is for

tools-mail-manager — thin CLI dispatch over operations-mail-sync (Sprint 3.45 crate 11, last of the sprint).

account pairs an optional reader and an optional sender (AC-composite-account) — never a 1:1 provider-per-account model.

an account's config, resolving credentials at build time.

the sync worker writes cursors/messages through. Not Postgres: a v1 CLI tool's own local state, not a shared service (see CHANGELOG.md).

every send/throttle/deny event SendGuard produces.

Capabilities

FileAuditSink

FileAuditSink — a file-backed operations_mail_sync::AuditSink.

Item
pub struct FileAuditSink
FileAuditSink :: fn new(path : impl Into <PathBuf>) -> Self
FileAuditSink :: async fn record(& self, log : AuditLog) -> Result <(), String>

AccountsCmd

CLI surface: tools-mail-manager sync <account>, `tools-mail-manager send <account>

Item
pub enum AccountsCmd

Cli

CLI surface: tools-mail-manager sync <account>, `tools-mail-manager send <account>

Item
pub struct Cli

Command

CLI surface: tools-mail-manager sync <account>, `tools-mail-manager send <account>

Item
pub enum Command

AccountConfig

Account config: TOML shape, one entry per logical account, each entry

Item
pub struct AccountConfig
AccountConfig :: fn reader_kind(& self) -> Option <& 'static str>
AccountConfig :: fn sender_kind(& self) -> Option <& 'static str>

CredentialRef

Account config: TOML shape, one entry per logical account, each entry

Item
pub enum CredentialRef
CredentialRef :: fn resolve(& self) -> Result <(String, String), MailManagerError>

MailManagerConfig

Account config: TOML shape, one entry per logical account, each entry

Item
pub struct MailManagerConfig
fn load_config(path : & Path) -> Result <MailManagerConfig, MailManagerError>
fn parse_config(text : & str) -> Result <MailManagerConfig, MailManagerError>

ReaderConfig

Account config: TOML shape, one entry per logical account, each entry

Item
pub enum ReaderConfig

SenderConfig

Account config: TOML shape, one entry per logical account, each entry

Item
pub enum SenderConfig

MailManagerError

Errors for tools-mail-manager's config/factory/store/audit wiring.

Item
pub enum MailManagerError

factory (other)

Builds a Box<dyn MailReader> / Box<dyn MailSender> from one account's

Item
fn build_reader(account : & str, cfg : & ReaderConfig,) -> Result <Box <dyn MailReader>, MailManagerError>
fn build_sender(account : & str, cfg : & SenderConfig,) -> Result <Box <dyn MailSender>, MailManagerError>

run (other)

Dispatch glue: turns one parsed crate::cli::Command plus a loaded

Item
pub const CONFIG_ENV_VAR: & str
pub const DEFAULT_CONFIG_FILE: & str
fn resolve_config_path(explicit : Option <& Path>) -> PathBuf
fn default_state_dir() -> PathBuf
fn state_file_path(state_dir : & Path) -> PathBuf
fn audit_file_path(audit_dir : & Path) -> PathBuf
fn find_account <'a>(config : & 'a MailManagerConfig, account_name : & str,) -> Result <& 'a AccountConfig, MailManagerError>
async fn run_sync(account_name : & str, account : & AccountConfig, store : & dyn MailStore, mailbox : Option <& str>, full : bool, override_filter : Option <& str>, page_size : u32, max_messages : u32,) -> Result <SyncOutcome, MailManagerError>
async fn run_send(account_name : & str, account : & AccountConfig, audit : & dyn AuditSink, quota_per_day : u64, to : Vec <String>, cc : Vec <String>, bcc : Vec <String>, subject : String, body : String, override_quota : bool,) -> Result <SendReceipt, MailManagerError>

AccountSummary

Dispatch glue: turns one parsed crate::cli::Command plus a loaded

Item
pub struct AccountSummary
fn accounts_summary(config : & MailManagerConfig) -> Vec <AccountSummary>

FileMailStore

FileMailStore — a file-backed operations_mail_sync::MailStore.

Item
pub struct FileMailStore
FileMailStore :: fn open(path : impl Into <PathBuf>) -> Result <Self, MailManagerError>
FileMailStore :: async fn get_cursor(& self, account_id : & str, mailbox : Option <& str>,) -> Result <Option <Cursor>, String>
FileMailStore :: async fn save_cursor(& self, account_id : & str, mailbox : Option <& str>, cursor : Cursor,) -> Result <(), String>
FileMailStore :: async fn save_message(& self, account_id : & str, email : & Email) -> Result <bool, String>

How to use it

No examples/ target and no doctest in this crate's rustdoc. The tests listed under Verification are the closest executable usage.

Module structure

tools_mail_manager

flowchart TD
  n_tools_mail_manager["tools_mail_manager"]
  n_tools_mail_manager --> n_audit["audit"]
  n_tools_mail_manager --> n_cli["cli"]
  n_tools_mail_manager --> n_config["config"]
  n_tools_mail_manager --> n_error["error"]
  n_tools_mail_manager --> n_factory["factory"]
  n_tools_mail_manager --> n_run["run"]
  n_tools_mail_manager --> n_store["store"]

Public surface

`audit`

ItemWhat it is
pub struct FileAuditSinkAppends every SendGuard audit event to a JSONL file.
FileAuditSink :: fn new(path : impl Into <PathBuf>) -> SelfPoint the sink at path
FileAuditSink :: async fn record(& self, log : AuditLog) -> Result <(), String>

`cli`

ItemWhat it is
pub struct Clitools-mail-manager — thin CLI dispatch over operations-mail-sync
pub enum CommandTop-level verbs.
pub enum AccountsCmdaccounts ... subcommands.

`config`

ItemWhat it is
pub struct MailManagerConfigThe whole config file: one entry per logical account, keyed by the operator-chosen account name (southcity, personal-gmail, ...).
pub struct AccountConfigOne logical account: an optional read capability and an optional send capability, independently configured (AC-composite-account)
AccountConfig :: fn reader_kind(& self) -> Option <& 'static str>A short tag naming which reader backend is configured, for accounts list output — never None/Some Debug noise.
AccountConfig :: fn sender_kind(& self) -> Option <& 'static str>Same as Self::reader_kind for the sender side.
pub enum ReaderConfigA read-capability backend
pub enum SenderConfigA send-capability backend
pub enum CredentialRefWhere a provider's AUTH username/password come from
CredentialRef :: fn resolve(& self) -> Result <(String, String), MailManagerError>Resolve to a (username, password) pair
fn load_config(path : & Path) -> Result <MailManagerConfig, MailManagerError>Parse a config file at path into a MailManagerConfig
fn parse_config(text : & str) -> Result <MailManagerConfig, MailManagerError>Parse a config file's contents (test seam — avoids touching disk in unit tests that only care about shape validation)

`error`

ItemWhat it is
pub enum MailManagerErrorErrors raised while resolving config, building a provider pair, or driving operations-mail-sync for one account.

`factory`

ItemWhat it is
fn build_reader(account : & str, cfg : & ReaderConfig,) -> Result <Box <dyn MailReader>, MailManagerError>Build the MailReader an account's reader config describes
fn build_sender(account : & str, cfg : & SenderConfig,) -> Result <Box <dyn MailSender>, MailManagerError>Build the MailSender an account's sender config describes

`run`

ItemWhat it is
pub const CONFIG_ENV_VAR: & strEnv var naming an explicit config path, checked when --config is not passed on the command line.
pub const DEFAULT_CONFIG_FILE: & strDefault config file name, relative to the current directory, used when neither --config nor $MAIL_MANAGER_CONFIG is set.
fn resolve_config_path(explicit : Option <& Path>) -> PathBufResolve the config path: --config wins, then $MAIL_MANAGER_CONFIG, then ./tools-mail-manager.toml.
fn default_state_dir() -> PathBufDefault local-state directory: the XDG data dir's tools-mail-manager/ (falls back to .tools-mail-manager in the current directory if no data dir can be determined, e.g
fn state_file_path(state_dir : & Path) -> PathBufThe sync-state file within a state directory.
fn audit_file_path(audit_dir : & Path) -> PathBufThe audit-log file within an audit directory.
pub struct AccountSummaryOne row of accounts list output: the account name and each capability's provider kind (None = not configured).
fn accounts_summary(config : & MailManagerConfig) -> Vec <AccountSummary>Summarize every configured account, sorted by name (the config's BTreeMap already iterates in that order).
fn find_account <'a>(config : & 'a MailManagerConfig, account_name : & str,) -> Result <& 'a AccountConfig, MailManagerError>Look up account_name in config, erroring loudly if it isn't there
async fn run_sync(account_name : & str, account : & AccountConfig, store : & dyn MailStore, mailbox : Option <& str>, full : bool, override_filter : Option <& str>, page_size : u32, max_messages : u32,) -> Result <SyncOutcome, MailManagerError>Run sync for one account: build its reader, then drive operations_mail_sync::SyncWorker against store
async fn run_send(account_name : & str, account : & AccountConfig, audit : & dyn AuditSink, quota_per_day : u64, to : Vec <String>, cc : Vec <String>, bcc : Vec <String>, subject : String, body : String, override_quota : bool,) -> Result <SendReceipt, MailManagerError>Run send for one account: build its sender, then drive operations_mail_sync::SendGuard (per-recipient daily quota + mandatory audit)

`store`

ItemWhat it is
pub struct FileMailStoreA file-backed MailStore
FileMailStore :: fn open(path : impl Into <PathBuf>) -> Result <Self, MailManagerError>Open (or create) the store backed by the JSON file at path
FileMailStore :: async fn get_cursor(& self, account_id : & str, mailbox : Option <& str>,) -> Result <Option <Cursor>, String>
FileMailStore :: async fn save_cursor(& self, account_id : & str, mailbox : Option <& str>, cursor : Cursor,) -> Result <(), String>
FileMailStore :: async fn save_message(& self, account_id : & str, email : & Email) -> Result <bool, String>

Re-exports. Exported here, defined elsewhere.

ExportDefined in
FileAuditSinkaudit::FileAuditSink
FileMailStorestore::FileMailStore
MailManagerErrorerror::MailManagerError
{AccountsCmd,Cli,Command}cli::{AccountsCmd,Cli,Command}
{accounts_summary,audit_file_path,default_state_dir,find_account,resolve_config_path,run_send,run_sync,state_file_path,AccountSummary,CONFIG_ENV_VAR,DEFAULT_CONFIG_FILE,}run::{accounts_summary,audit_file_path,default_state_dir,find_account,resolve_config_path,run_send,run_sync,state_file_path,AccountSummary,CONFIG_ENV_VAR,DEFAULT_CONFIG_FILE,}
{build_reader,build_sender}factory::{build_reader,build_sender}
{load_config,AccountConfig,CredentialRef,MailManagerConfig,ReaderConfig,SenderConfig,}config::{load_config,AccountConfig,CredentialRef,MailManagerConfig,ReaderConfig,SenderConfig,}

Boundary

Reaches into foundation, infrastructure, operations.

Shares tier tools with 84 other crates: tools-advisory-reach, tools-archive-guard, tools-artifact-scaffold, tools-ask-ai-core, tools-ask-ais, tools-ask-gemini, tools-book, tools-book-report, … (84 total).

_What this crate deliberately does NOT own is a judgment. No committed registry records one for it, so none is stated here._

Where it sits

Tier (ontology)tools
Architectural role (taxonomy)unclassified (baselined)
Locationcrates/tools/mail-manager
Vocabulary in force (lexicon)current

Tier flow. Which tiers this crate's own edges cross.

flowchart LR
  n_tools["tools"] --> n_foundation["foundation"]
  n_tools["tools"] --> n_infrastructure["infrastructure"]
  n_tools["tools"] --> n_operations["operations"]

Dependencies

Runtime, in this workspace.

CrateTierOptionalOnly on
`foundation-audit-log`foundationnoalways
`foundation-mail-message`foundationnoalways
`foundation-refresh-policy`foundationnoalways
`infrastructure-adapters-google-gmail`infrastructurenoalways
`infrastructure-imap`infrastructurenoalways
`infrastructure-smtp`infrastructurenoalways
`operations-mail-sync`operationsnoalways

Runtime, from outside the workspace.

CrateRequirementFeaturesOptionalOnly on
async-trait^0.1noalways
clap^4derivenoalways
dirs^5noalways
serde^1derive, derivenoalways
serde_json^1noalways
thiserror^2noalways
tokio^1full, macros, rt-multi-threadnoalways
toml^0.8noalways
uuid^1v4, v7, serde, jsnoalways

Development, in this workspace.

CrateTierOptionalOnly on
`tools-cli-conformance`toolsnoalways

Development, from outside the workspace.

CrateRequirementFeaturesOptionalOnly on
tempfile^3noalways

Build. None.

Depended on by. Nothing in this workspace.

Signal flow — what reaches this crate, and what it reaches.

flowchart LR
  SELF["tools-mail-manager"]
  SELF -->|development| n_tools_cli_conformance["tools-cli-conformance"]
  SELF -->|runtime| n_foundation_audit_log["foundation-audit-log"]
  SELF -->|runtime| n_foundation_mail_message["foundation-mail-message"]
  SELF -->|runtime| n_foundation_refresh_policy["foundation-refresh-policy"]
  SELF -->|runtime| n_infrastructure_adapters_google_gmail["infrastructure-adapters-google-gmail"]
  SELF -->|runtime| n_infrastructure_imap["infrastructure-imap"]
  SELF -->|runtime| n_infrastructure_smtp["infrastructure-smtp"]
  SELF -->|runtime| n_operations_mail_sync["operations-mail-sync"]
  classDef self fill:#1f883d,stroke:#1f883d,color:#fff;
  class SELF self;

Feature flags

No Cargo features are defined: every capability is unconditional, so no consumer can receive a half-wired crate.

Targets

KindNameSource
bintools-mail-manager`src/main.rs`
libtools_mail_manager`src/lib.rs`

Error model

Error typeNamed by
MailManagerErrorbuild_reader, build_sender, find_account, load_config, parse_config, run_send, … (7 total)

Operational characteristics

PropertyEvidence
async public surfaceyes
async runtimeyes
database accessnone detected
network I/Onone detected
unsafe codenone detected
environment variablesnone detected

No unsafe block, unsafe fn, unsafe impl or unsafe trait was found by the parser anywhere in this crate's source.

Configuration

No environment variable is read with a literal name anywhere in this crate. A variable whose key is computed at run time cannot be listed here, and is not claimed to be absent.

No workspace crate depends on this one.

Verification

KindCount
Unit tests38
Integration tests0
Examples0
Doctests0

Evidence by module. How often each public module is named by something executable.

ModuleTestsExamplesConsumers
audit100
cli300
config700
error100
factory200
run1100
store100

What the tests establish, by name:

Documentation coverage

MeasureDocumentedTotal
Public items with rustdoc3135
Public modules with a //! block77
pie showData
    title Public items with rustdoc
    "Documented" : 31
    "No rustdoc detected" : 4

Metrics

MetricValue
Rust source files9
Source lines1945
Code lines1465
Public API items35
Public modules7
Tests38
Examples0
Cargo features0
Direct runtime dependencies16
Workspace reverse dependencies0
pie showData
    title Public API by kind
    "constant" : 2
    "enum" : 6
    "function" : 12
    "method" : 9
    "struct" : 6
pie showData
    title Rust source composition
    "Code" : 1465
    "Blank or comment" : 480

Generation

Rendered by tools-corpus corpus readme from repository evidence alone, renderer schema 2, lexicon current. No model, network service or database was consulted. Regenerate with tools-corpus corpus readme --write; verify with --check.

All tools · Manual