Skip to content

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.

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.

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))

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.

mailboxes, err := cl.ListMailboxes(ctx) // []client.MailboxInfo
for _, m := range mailboxes {
fmt.Println(m.FolderPath, m.Type, m.MaxMessages, m.RetentionDays)
}
info, err := cl.GetMailboxInfo(ctx, "inbox") // *client.MailboxDetail
fmt.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.

err = cl.DeleteMailbox(ctx, "old-folder")

Deleting a mailbox discards every message in it, including ones you have not retrieved.

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.

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.