Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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’s full RPC surface. MX/ mail servers call this instead of talking to Solana directly. See Route index below for the complete method list.

Route index

Every RPC the SolanaMail service answers (mail_api/protos/sithbit.proto), grouped by area. The surface carries no auth of its own — see the network posture note above.

Alias directory

RPCRequest → ResponsePurpose
ResolveAliasAliasRequestAliasResponseresolve an email local-part alias to a wallet address
ListAliasesListAliasesRequestListAliasesResponselist every alias local-part pointing at a wallet, off the alias indexer

Mailbox and postage

RPCRequest → ResponsePurpose
GetMailboxMailboxRequestMailboxResponseread a mailbox’s mail count, default postage, and no_ipfs flag
GetMailboxKeyMailboxKeyRequestMailboxKeyResponsefetch a wallet’s published encryption key (X25519/RSA/none) plus no_ipfs
GetFromboxFromboxRequestFromboxResponselook up a (from, to) frombox: required postage, stamp count, stamp fee terms

Sending and receiving mail

RPCRequest → ResponsePurpose
SendMailSendMailRequestSendMailResponsesubmit a mail send on-chain, with an optional reply-bounty escrow
DeleteMailDeleteMailRequestDeleteMailResponsedelete a received message on-chain
RefundMailRefundMailRequestRefundMailResponserefund a received message back to its sender
FindMessageFindMessageRequestFindMessageResponselocate a landed message by IPFS CID — a dedupe check after a lost SendMail response

Reply bounties

RPCRequest → ResponsePurpose
ClaimBountyClaimBountyRequestClaimBountyResponseclaim an escrowed reply bounty using a reply message as evidence
RefundBountyRefundBountyRequestRefundBountyResponsereclaim an expired, unclaimed reply bounty

Transactions

RPCRequest → ResponsePurpose
GetTransactionStatusTransactionStatusRequestTransactionStatusResponsepoll the commitment status of a previously submitted transaction

Domains

RPCRequest → ResponsePurpose
GetMailDomainMailDomainRequestMailDomainResponsecheck a MailDomain account: exists, active, authority, gateway_is_authority
ListAuthoritativeDomainsListAuthoritativeDomainsRequestListAuthoritativeDomainsResponselist active domains whose on-chain authority is this gateway’s own signing key
GetSenderAttestationSenderAttestationRequestSenderAttestationResponsecheck whether a domain has attested a sender wallet as legitimate

Marketplace

RPCRequest → ResponsePurpose
BrowseListingsBrowseListingsRequestBrowseListingsResponsebrowse open marketplace listings (aliases and domains for sale)
ListSalesListSalesRequestListSalesResponseread the marketplace sales ledger (by wallet, name+kind, or newest overall)
ListParticipantsListParticipantsRequestListParticipantsResponsesearch on-chain participant opt-in beacons by tag bitmap filter

Reputation and pinning

RPCRequest → ResponsePurpose
GetSenderReputationSenderReputationRequestSenderReputationResponselook up a wallet’s cumulative stamp-spend reputation and resulting price-rate bps
GetPinLeasePinLeaseRequestPinLeaseResponselook up IPFS pinning-lease deposits/count on a CID

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

Run it as an OS service with mail-grpc service install — the shared subcommand is documented in Running as an OS service.

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-grpc no longer reads its legacy environment-only configuration. GRPC_SERVER_ADDRESS, DEFAULT_KEYPAIR (and DEFAULT_KEYPAIR_VAULT_URI / DEFAULT_KEYPAIR_SECRET_NAME), ALIAS_INDEX_DB, ALIAS_INDEX_POLL_SECONDS, ALIAS_CACHE_SECONDS, and HEALTH_BIND are all ignored. The one legacy name still honored is JSON_RPC_URL (bare, un-prefixed), for parity with the sithbit CLI and the standard Solana convention — it overrides the configured json_rpc_url. In particular, there is no keypair-content-in-an-environment-variable shape anymore: DEFAULT_KEYPAIR used to hold the raw JSON keypair array itself, while the TOML keypair names a key source — a keypair file path, or a cloud secret-manager secret. The nearest env-var equivalent is MAIL_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.