Postbox docs

Groups & send limits

Mailbox groups are where per-mailbox send rate limits, spam thresholds, and retention overrides live.

A mailbox group is a policy bundle you attach mailboxes to. It is where per-mailbox send rate limits live, along with a spam threshold and a retention override. Use groups to stop one high-volume mailbox from burning a domain's whole sending reputation, and to hold different mailboxes to different rules.

A mailbox joins a group through its groupId (see Mailboxes). A mailbox with no group has no per-mailbox send cap of its own, though the project's default limits and your plan allowance still apply.

How limits resolve

Send limits resolve down a chain, most specific wins:

platform default  ->  project default  ->  group override

A field left null on the group inherits the project default; a field left null on the project inherits the platform default. So a group only needs to set the fields it wants to change. Project defaults are set under Settings (see Sending); the group is the tighter, per-cohort layer on top.

Create

Groups are project scoped, so pass the project with X-Project-Id:

import { Postbox } from "@postbox/sdk";

const pb = new Postbox({
  apiKey: process.env.PB_KEY!,
  projectId: process.env.PROJECT_ID!,
});

const group = await pb.mailboxGroups.create({
  name: "Transactional",
  hourlyLimit: 500,
  dailyLimit: 5000,
  burstLimit: 50,
});
import os
from postbox import Postbox

pb = Postbox(api_key=os.environ["PB_KEY"], project_id=os.environ["PROJECT_ID"])

group = pb.mailbox_groups.create(
    {
        "name": "Transactional",
        "hourlyLimit": 500,
        "dailyLimit": 5000,
        "burstLimit": 50,
    }
)
using Postbox;

var pb = new PostboxClient(
    new PostboxOptions
    {
        ApiKey = Environment.GetEnvironmentVariable("PB_KEY")!,
        ProjectId = Environment.GetEnvironmentVariable("PROJECT_ID")!,
    }
);

var group = await pb.MailboxGroups.CreateAsync(
    new MailboxGroupsCreateBody
    {
        Name = "Transactional",
        HourlyLimit = 500,
        DailyLimit = 5000,
        BurstLimit = 50,
    }
);
import cloud.postboxapp.*;
import cloud.postboxapp.gen.*;
import java.util.*;

Postbox pb = new Postbox(PostboxOptions.builder().apiKey(System.getenv("PB_KEY")).projectId(System.getenv("PROJECT_ID")).build());

var group = pb.mailboxGroups.create(MailboxGroupsCreateBody.builder().name("Transactional").hourlyLimit(500.0).dailyLimit(5000.0).burstLimit(50.0).build());
import postbox "github.com/postboxapp/postbox-go"

pb, err := postbox.New(postbox.Options{APIKey: os.Getenv("PB_KEY"), ProjectID: os.Getenv("PROJECT_ID")})
ctx := context.Background()

group, err := pb.MailboxGroups.Create(ctx, &postbox.MailboxGroupsCreateBody{Name: "Transactional", HourlyLimit: 500, DailyLimit: 5000, BurstLimit: 50})
curl -X POST https://api.postboxapp.cloud/v1/mailbox-groups \
  -H "Authorization: Bearer $PB_KEY" \
  -H "X-Project-Id: $PROJECT_ID" \
  -H "Content-Type: application/json" \
  -d '{
        "name": "Transactional",
        "hourlyLimit": 500,
        "dailyLimit": 5000,
        "burstLimit": 50,
        "spamScoreThreshold": 5,
        "actionOnSpam": "junk",
        "retentionDays": 90
      }'
FieldRequiredNotes
nameyesLabel for the group.
hourlyLimitnoMax sends per rolling hour. null inherits the project default.
dailyLimitnoMax sends per rolling day. null inherits.
burstLimitnoMax sends in a short burst window. null inherits.
spamScoreThresholdno0 to 10. Inbound score at or above which the spam action fires for this group's mailboxes.
actionOnSpamnoreject, junk, or tag. What to do when the threshold is hit.
retentionDaysnoDelete stored mail older than this. null keeps mail indefinitely.

Setting a limit to 0 is a real value: a hard pause, not "unlimited". Use null to inherit instead.

List, fetch, update, delete

await pb.mailboxGroups.list();

await pb.mailboxGroups.get(groupId);

await pb.mailboxGroups.update(groupId, { hourlyLimit: 1000 });

await pb.mailboxGroups.delete(groupId);
pb.mailbox_groups.list()

pb.mailbox_groups.get(group_id)

pb.mailbox_groups.update(group_id, {"hourlyLimit": 1000})

pb.mailbox_groups.delete(group_id)
await pb.MailboxGroups.ListAsync();

await pb.MailboxGroups.GetAsync(groupId);

await pb.MailboxGroups.UpdateAsync(groupId, new MailboxGroupsUpdateBody { HourlyLimit = 1000 });

await pb.MailboxGroups.DeleteAsync(groupId);
pb.mailboxGroups.list();

pb.mailboxGroups.get(groupId);

pb.mailboxGroups.update(groupId, MailboxGroupsUpdateBody.builder().hourlyLimit(1000.0).build());

pb.mailboxGroups.delete(groupId);
pb.MailboxGroups.List(ctx)

pb.MailboxGroups.Get(ctx, groupID)

pb.MailboxGroups.Update(ctx, groupID, &postbox.MailboxGroupsUpdateBody{HourlyLimit: 1000})

pb.MailboxGroups.Delete(ctx, groupID)
curl https://api.postboxapp.cloud/v1/mailbox-groups \
  -H "Authorization: Bearer $PB_KEY" -H "X-Project-Id: $PROJECT_ID"

curl https://api.postboxapp.cloud/v1/mailbox-groups/$GROUP_ID \
  -H "Authorization: Bearer $PB_KEY" -H "X-Project-Id: $PROJECT_ID"

curl -X PATCH https://api.postboxapp.cloud/v1/mailbox-groups/$GROUP_ID \
  -H "Authorization: Bearer $PB_KEY" -H "X-Project-Id: $PROJECT_ID" \
  -H "Content-Type: application/json" \
  -d '{ "hourlyLimit": 1000 }'

curl -X DELETE https://api.postboxapp.cloud/v1/mailbox-groups/$GROUP_ID \
  -H "Authorization: Bearer $PB_KEY" -H "X-Project-Id: $PROJECT_ID"

PATCH is a partial update: send only the fields you want to change. Every field accepted on create is editable, including name.

Attach a mailbox

Set groupId when you create a mailbox, or patch it later. Setting groupId to null detaches the mailbox, which also drops its per-mailbox send limits back to the project default.

await pb.mailboxes.update(mailboxId, { groupId: group.id });
await pb.mailboxes.update(mailboxId, { groupId: null }); // detach

A group is a shape, not a container

Mailboxes are not stored "inside" a group. The group holds the rules; a mailbox points at it. Deleting a group leaves its mailboxes in place, back on the project defaults.