mail-grpc: the chain gateway
Standard port(s): gRPC 50051, health 8193 (both in-code defaults,
loopback-bound).
The gRPC gateway other servers use to reach Solana — it implements the
SolanaMail service (ResolveAlias, GetFrombox, SendMail, GetMailbox,
GetMailboxKey, DeleteMail). MX/ mail servers call this instead of talking
to Solana directly.
When you need it: always, in any deployment where mail should actually
reach the chain — without it, sithbitd runs with its chain pipeline
disabled.
Network posture: the gRPC surface carries no TLS or authentication — anyone who can reach the port can sign with the gateway’s keypair. Bind it to loopback or a private interface only, never a public address. Why the gateway is a separate private service at all (and what would change that) is recorded in the topology design note.
Quickstart:
cargo run -p mail-grpc
Config file mail_grpc.toml, or point MAIL_GRPC_CONFIG at an alternate
path — the same layered TOML/env mechanism as every other SithBit binary
(in-code default → TOML → ./.env → ./.env.$APP_ENV → environment;
MAIL_GRPC_* variables override individual settings, e.g.
MAIL_GRPC_BIND_ADDR or MAIL_GRPC_ALIAS_INDEX__DATABASE). An empty
or missing config file is a runnable dev gateway: it binds
127.0.0.1:50051 — the private-network posture above is the default the
code enforces now, not a convention — and resolves the chain endpoint and
the signing keypair from the operator’s Solana CLI config
(~/.config/solana/cli/config.yml; a missing file means the stock CLI
defaults, i.e. mainnet-beta), exactly like the sithbit CLI, so
solana config set governs a zero-config gateway. As with the CLI, a
bare JSON_RPC_URL environment variable overrides the endpoint (it wins
over a configured json_rpc_url), which is handy for pointing a gateway
at a local validator without editing config. The annotated
mail_grpc/mail_grpc.example.toml documents every key with its default;
the Configuration reference has the
key/default table.
Migration (clean break):
mail-grpcno longer reads its legacy environment-only configuration.GRPC_SERVER_ADDRESS,DEFAULT_KEYPAIR(andDEFAULT_KEYPAIR_VAULT_URI/DEFAULT_KEYPAIR_SECRET_NAME),ALIAS_INDEX_DB,ALIAS_INDEX_POLL_SECONDS,ALIAS_CACHE_SECONDS, andHEALTH_BINDare all ignored. The one legacy name still honored isJSON_RPC_URL(bare, un-prefixed), for parity with thesithbitCLI and the standard Solana convention — it overrides the configuredjson_rpc_url. In particular, there is no keypair-content-in-an-environment-variable shape anymore:DEFAULT_KEYPAIRused to hold the raw JSON keypair array itself, while the TOMLkeypairnames a key source — a keypair file path, or a cloud secret-manager secret. The nearest env-var equivalent isMAIL_GRPC_KEYPAIR=/path/to/id.json.
Signing keypair: a file or a cloud secret manager
keypair is a
key source like
the workspace’s other file-loaded secrets. A bare string is a Solana
keypair file; the table form fetches the keypair from a cloud secret
manager instead — the secret’s value holds exactly what the file would,
the raw JSON keypair array. Authentication is each cloud’s ambient
chain (Azure managed identity, the AWS credential chain, Google ADC):
no new auth to configure, and no key material in the config file — only
the secret’s coordinates.
keypair = "signer.json"
keypair = { kind = "akv", vault_uri = "https://<vault>.vault.azure.net/",
secret_name = "signer" }
keypair = { kind = "asm", secret_id = "sithbit/signer" }
keypair = { kind = "gsm", project = "my-project", secret = "signer" }
Unset (the default), the keypair comes from the Solana CLI config’s
keypair_path — ~/.config/solana/id.json unless solana config set
moved it.
mail-grpc also runs the alias indexer that backs Aliases’s
ListAliases lookups ([alias_index]; an explicitly empty database
disables it). See the
Configuration reference for the full
key/default table.