# Set up a mailbox (Porkbun email hosting)

A mailbox is a real inbox at the domain (`me@example.com`), read in any mail app
(IMAP or POP) or at https://webmail.porkbun.com, and able to send. Compare email
forwarding, which only passes mail on to an inbox elsewhere:
[Set up email forwarding](https://porkbun.com/llms/guides/set-up-email-forwarding).

Over MCP the tools are `list_mailboxes`, `setup_mailbox` and `create_mailbox`;
over the API, the `/email/...Mailbox` endpoints below. The domain must be in the
account, active and opted in to API access, and the account's email must be
verified along with its phone (or an approved ID check).

## 1. See what the domain already has

```bash
curl 'https://api.porkbun.com/api/json/v3/email/getMailboxes/example.com' \
  -H 'X-API-Key: pk1_...' -H 'X-Secret-API-Key: sk1_...'
# -> { "mailboxes":[{"id":8095474,"address":null,"status":"PENDINGSETUP","trial":true,"expires":"..."}],
#      "price":{"amount":3600,"formatted":"$36.00","interval":"year"}, "clientSettings":{...} }
```

A mailbox with `status: PENDINGSETUP` and no address is already paid for, or is
the **free trial mailbox every domain registration comes with**. Setting it up
costs nothing; go to step 2. With none waiting, step 3 buys one.

## 2. Set up a waiting mailbox (free)

```bash
curl -X POST https://api.porkbun.com/api/json/v3/email/setupMailbox/example.com \
  -H 'Content-Type: application/json' \
  -d '{"apikey":"pk1_...","secretapikey":"sk1_...","address":"me"}'
```

- `address`: the part before the @, 1-30 characters (letters, digits, `+ . - _`).
  It cannot be an address that is already a forward or a mailbox.
- `password`: leave it out and a strong one is generated and returned **once**,
  in `password`. Give it to the person straight away; it is not shown again (it
  can be changed with `/email/setPassword`). If you send one, it needs 12-72
  characters with an upper case letter, a lower case letter, a number and a
  special character.
- `mailboxId`: which waiting mailbox, if there are several.

The answer has the mailbox, `clientSettings` for mail apps (IMAP
`imap.porkbun.com:993`, SMTP `smtp.porkbun.com:587` STARTTLS, username = the full
address) and `dnsChanges`.

## 3. Buy a mailbox ($36.00 a year)

Tell the person the price and that it renews every year, then:

```bash
curl -X POST https://api.porkbun.com/api/json/v3/email/createMailbox/example.com \
  -H 'Content-Type: application/json' \
  -d '{"apikey":"pk1_...","secretapikey":"sk1_...","address":"me","cost":3600,"agreeToTerms":"yes"}'
```

`cost` must equal the price in cents (`COST_MISMATCH` says what it is;
`"dryRun": true` with `"cost": 0` quotes it and checks everything without
charging). It is paid from account credit (`INSUFFICIENT_FUNDS` gives the
shortfall), or directly by card or USDC with `payWith`, exactly as for a domain:
[Buy a domain from an agent](https://porkbun.com/llms/guides/buy-a-domain-from-an-agent).
It counts toward the account's monthly API limit. The mailbox is set up in the
same call, as in step 2.

If the charge went through but the setup did not, the answer is
`setupComplete: false` with a `mailboxId`: finish with step 2. Don't buy again.

## 4. Renewal

A set-up mailbox renews on its own each year when it is due (`autoRenews: true`
in `getMailboxes`), charged like any other Porkbun renewal. A trial mailbox that
was set up does the same at the end of its trial. To pay for a year now (to keep
a trial mailbox, or to renew early):

```bash
curl -X POST https://api.porkbun.com/api/json/v3/email/renewMailbox/example.com \
  -H 'Content-Type: application/json' \
  -d '{"apikey":"pk1_...","secretapikey":"sk1_...","address":"me","cost":3600,"agreeToTerms":"yes"}'
```

`cost` is the mailbox's `renewalPrice` (a dry run with `"cost": 0` quotes it and
shows `expiresAfter`). The year is added to the current expiry date. Payment works
as for buying: credit, or `payWith` card / USDC.

## 5. Mail DNS

A mailbox needs Porkbun's MX records and SPF include at the domain apex, the same
records as forwarding, and the call puts them in place. If that would delete
another mail service's MX records or rewrite the domain's SPF record, it stops
with `DNS_CHANGE_CONFIRMATION_REQUIRED` and `dnsChanges`, and nothing is changed
or charged. Tell the person what will change (mail stops arriving at the other
service) and resend with `"confirmDnsChanges": true` only if they agree. If the
domain uses other nameservers, the records must be added there:
[Set up email forwarding](https://porkbun.com/llms/guides/set-up-email-forwarding) covers that.

DKIM and DMARC are set up from the domain's Email Hosting page on porkbun.com.

## Refusals

| Error | Meaning |
|---|---|
| `NO_PENDING_MAILBOX` | Nothing waiting to set up; buy one (step 3) |
| `MAILBOX_EXISTS` / `FORWARD_EXISTS` | That address is already a mailbox or a forward |
| `INVALID_EMAIL` / `INVALID_PASSWORD` | The address or password breaks the rules in the message |
| `VERIFICATION_REQUIRED` | Verify the account's phone ([guide](https://porkbun.com/llms/guides/verify-the-account)) and email |
| `EMAIL_HOSTING_UNAVAILABLE` | This account cannot buy email hosting right now; the person contacts support |
| `EMAIL_BLOCKED` | Email services are blocked on the domain or account |


---

## More

- Guides (how-tos): https://porkbun.com/llms/guides
- Topic index: https://porkbun.com/llms
- Full reference (one file): https://porkbun.com/llms-full.txt
- OpenAPI spec (full schemas): https://porkbun.com/api/json/v3/spec
- Short overview: https://porkbun.com/llms.txt
- Official MCP server: https://porkbun.com/mcp (`npx -y @porkbunllc/mcp-server`)
- Create API keys: https://porkbun.com/account/api
