Mailboxes & ACLs
This page shows how to create and configure the mailboxes your peer owns, and how to let other peers
read or write them. A mailbox is a folder of messages, owned by one peer and addressed by the owner’s
peer ID plus a folder path such as inbox or orders.
Mailbox types
Section titled “Mailbox types”The type is fixed when the mailbox is created. There is no call to change it.
| Type | Who may write | Who may read |
|---|---|---|
wire.MailboxPrivate |
Any peer (only messages addressed to the owner) | The owner |
wire.MailboxShared |
The owner, and peers granted AccessWriteOnly or AccessReadWrite |
The owner, and peers granted AccessReadOnly or AccessReadWrite |
wire.MailboxPublic |
The owner, and peers granted AccessWriteOnly or AccessReadWrite |
Any peer |
A message sent to a folder that does not exist creates it as a private mailbox, which any peer can write to. If a folder must be shared or public, create it before anyone sends to it; the first creation wins, and deleting and recreating a mailbox discards its messages.
A sender without write access to a shared or public mailbox gets a refused SendResult whose Err() is
client.ErrForbidden.
Create a mailbox
Section titled “Create a mailbox”err := cl.CreateMailbox(ctx, "invoices", wire.MailboxPrivate)err = cl.CreateMailbox(ctx, "team-updates", wire.MailboxShared)err = cl.CreateMailbox(ctx, "announcements", wire.MailboxPublic, client.WithMailboxMaxMessages(500), client.WithRetentionDays(7),)| Option | Server default | Meaning |
|---|---|---|
WithMailboxMaxMessages(n) |
1000 | Cap on stored messages. At the cap, new deliveries are refused with client.ErrMailboxFull. |
WithRetentionDays(d) |
30 | Messages older than this are removed by the server’s maintenance sweep. |
WithRetentionCount(n) |
none | A rolling window: when the mailbox reaches its cap, the server prunes it to the newest n and stores the new message. Must be below the cap to have an effect. |
The defaults and ceilings are the server’s (storage.max_messages_per_mailbox,
storage.retention_days); larger values are clamped to them and zero or negative values are refused.
An owner may hold at most storage.max_mailboxes_per_owner mailboxes (100 by default), counting those
created by deliveries. See Storage, quotas & retention.
Change the settings of an existing mailbox with UpdateMailboxConfig, which takes the same options and
leaves the ones you omit unchanged:
err = cl.UpdateMailboxConfig(ctx, "announcements", client.WithRetentionDays(14))Grant and revoke access
Section titled “Grant and revoke access”Grants apply to shared and public mailboxes you own.
err = cl.GrantAccess(ctx, "team-updates", colleagueID, wire.AccessReadWrite)err = cl.RevokeAccess(ctx, "team-updates", colleagueID)
entries, err := cl.ListACL(ctx, "team-updates")for _, e := range entries { fmt.Println(e.PeerID, e.AccessMode, time.UnixMilli(e.GrantedAt)) // AccessMode: "readOnly", ...}wire.AccessMode |
Read (shared) | Write (shared, public) |
|---|---|---|
wire.AccessReadOnly |
yes | no |
wire.AccessWriteOnly |
no | yes |
wire.AccessReadWrite |
yes | yes |
Granting again replaces the peer’s mode. Grant the specific peers that need access; there is no wildcard.
A peer with read access reads the mailbox with RetrieveMessages(ctx, client.WithTargetPeer(ownerID), client.WithRetrieveFolderPath("team-updates")). It cannot acknowledge, flag or delete the owner’s
messages.
List and inspect
Section titled “List and inspect”mailboxes, err := cl.ListMailboxes(ctx) // []client.MailboxInfofor _, m := range mailboxes { fmt.Println(m.FolderPath, m.Type, m.MaxMessages, m.RetentionDays)}
info, err := cl.GetMailboxInfo(ctx, "inbox") // *client.MailboxDetailfmt.Printf("%d of %d messages\n", info.MessageCount, info.MaxMessages)GetMailboxInfo is the call to check before a mailbox fills: when MessageCount reaches
MaxMessages, senders’ deliveries start failing. Only the owner can ask.
Delete a mailbox
Section titled “Delete a mailbox”err = cl.DeleteMailbox(ctx, "old-folder")Deleting a mailbox discards every message in it, including ones you have not retrieved.
Server capacity
Section titled “Server capacity”QueryCapacity reports the server’s storage figures as a *wire.ServerCapacity. Any peer can ask.
capacity, err := cl.QueryCapacity(ctx)fmt.Printf("used %.1f%%, sampled %s\n", capacity.UsagePercent(), capacity.SampledAt)if capacity.IsNearCapacity() { // above 90% // prefer another server for new data}The figures are sampled on a timer, not computed per request; SampledAt says when. Once the database
reaches the server’s storage limit, every write is refused with status 507 until space is freed.
A least-privilege inbox for one peer
Section titled “A least-privilege inbox for one peer”To receive messages from one known peer and nobody else, create a shared mailbox and grant that peer write access before it first sends:
// Owner, at pairing time:_ = cl.CreateMailbox(ctx, "sync/device-b", wire.MailboxShared)_ = cl.GrantAccess(ctx, "sync/device-b", deviceB, wire.AccessWriteOnly)
// Device B:res, err := clB.SendMessage(ctx, ownerID, payload, client.WithFolderPath("sync/device-b"))If device B sends first, the folder is created private, which accepts mail from anyone.