Inboxes
An inbox is one email address. It belongs to the session that created it, or to the account if the session was logged in, and it expires after the retention period of your tier. Reading an inbox counts as activity and pushes its expiry forward.
Inbox endpoints accept a session token or an API key. An inbox owned by someone else returns 404.
The inbox model
- Name
id- Type
- string
- Description
Inbox id.
- Name
address- Type
- string
- Description
Full address, for example
kqv-7f3m2a@mail.nullnet.sh.
- Name
expires_at- Type
- timestamp
- Description
When the inbox and its mail are removed, unless it is used or extended first.
- Name
retention_secs- Type
- integer
- Description
The retention window of the owner's tier. Messages older than this are removed, and activity pushes
expires_atto at least now plus this window.
- Name
message_count- Type
- integer
- Description
Live messages.
- Name
storage_bytes- Type
- integer
- Description
Bytes stored in the inbox.
- Name
created_at- Type
- timestamp
- Description
Creation time.
Addresses
- Addresses are lowercased. A
+tagis ignored when resolving an address: mail tobob+news@nullnet.sharrives atbob@nullnet.sh. - Without a chosen local part, the server picks a random one: three letters, a dash and six letters or digits (
kqv-7f3m2a). - A local part is at most 64 characters of the usual address characters, with no leading, trailing or doubled dot.
- Reserved addresses. On the system domains, these local parts belong to the operator and cannot be created or claimed:
info,postmaster,abuse,admin,administrator,hostmaster,webmaster,security,support,root,noreply,no-reply,billing,sales. Creating one returns409 conflict, and availability is alwaysfalse. - Unclaimed mail. Mail to an address on a system domain that nobody has created yet is kept in an unowned inbox for 30 minutes. Creating that address claims it, with the mail already received.
Check availability
Whether an address can be created now. Credentials are optional. This endpoint is strictly rate limited, per caller and per client network (10 per minute for an anonymous session).
An unclaimed address with mail waiting counts as available. A reserved address never does. An unknown domain returns false.
Required query parameters
- Name
local- Type
- string
- Description
Local part.
- Name
domain- Type
- string
- Description
Domain.
Response
- Name
available- Type
- boolean
- Description
Whether
POST /v1/inboxeswould succeed for this address.
Request
curl -G https://mail.nullnet.sh/v1/inboxes/available \
-d local=alice \
-d domain=nullnet.sh
Response
{ "available": true }
Create an inbox
Creates an inbox. The body is optional: with no body you get a random address on the first system domain. Returns 201 with the inbox.
400 bad_request: invalid local part, or a domain you cannot use.409 conflict: the address is owned by someone else, or reserved.402 payment_required: you are at your tier's live-inbox limit. Delete one or upgrade.429 rate_limited: you are at your tier's inboxes-per-hour limit.
Optional attributes
- Name
local- Type
- string
- Description
The local part you want. Random when omitted.
- Name
domain- Type
- string
- Description
A system domain from
GET /v1/domains, or a verified custom domain you own. The first system domain when omitted.
Request
curl https://mail.nullnet.sh/v1/inboxes \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{"local": "alice", "domain": "nullnet.sh"}'
Response
{
"id": "019a2f50-1c3d-7e41-8b2a-4f6d8e0a1c3b",
"address": "alice@nullnet.sh",
"expires_at": "2026-10-26T09:00:00Z",
"retention_secs": 3600,
"message_count": 0,
"storage_bytes": 0,
"created_at": "2026-10-26T08:00:00Z"
}
List inboxes
Returns your live inboxes as an array. For an anonymous session, these are the session's inboxes. For a logged-in session, the account's inboxes plus any the session still owns itself. For an API key, the account's inboxes.
Request
curl https://mail.nullnet.sh/v1/inboxes \
-H "Authorization: Bearer {token}"
Response
[
{
"id": "019a2f50-1c3d-7e41-8b2a-4f6d8e0a1c3b",
"address": "alice@nullnet.sh",
"expires_at": "2026-10-26T09:00:00Z",
"retention_secs": 3600,
"message_count": 3,
"storage_bytes": 48211,
"created_at": "2026-10-26T08:00:00Z"
}
]
Get an inbox
Returns one inbox with its counters. Reading the inbox counts as activity: expires_at moves to at least now plus retention_secs, and the response shows the new value.
Request
curl https://mail.nullnet.sh/v1/inboxes/019a2f50-1c3d-7e41-8b2a-4f6d8e0a1c3b \
-H "Authorization: Bearer {token}"
Extend an inbox
Resets the expiry to a full retention window from now. Expiry never moves backwards. Returns the inbox.
Request
curl -X POST https://mail.nullnet.sh/v1/inboxes/019a2f50-1c3d-7e41-8b2a-4f6d8e0a1c3b/extend \
-H "Authorization: Bearer {token}"
Delete an inbox
Deletes the inbox. It disappears from the API at once, and its mail is purged shortly after. Returns 204.
Request
curl -X DELETE https://mail.nullnet.sh/v1/inboxes/019a2f50-1c3d-7e41-8b2a-4f6d8e0a1c3b \
-H "Authorization: Bearer {token}"
Custom domains
Premium accounts can receive mail on their own domains (up to 10). Other tiers get 403 tier_required. Custom domains are managed from a logged-in session, not with an API key.
- Register the domain with
POST /v1/domains. The response lists two DNS records to publish: anMXrecord pointing at the NULL mail server, and aTXTrecordgrrla-verify=<token>at_grrla.<domain>. - Publish both records at your DNS provider.
- Call
POST /v1/domains/:id/verify. The domain is verified when the TXT token matches and an MX record points at the server.
Until a domain is verified, mail to it is refused and inboxes cannot be created on it. A registration that is not verified within seven days is dropped and the name is freed. Verified domains are re-checked daily. If the TXT or MX record disappears, the domain becomes unverified and mail is refused again until verify passes.
On a verified custom domain, every address belongs to you. Only you can create inboxes on it, reserved local parts do not apply, and mail to an address you have not created yet creates an inbox owned by your account, with your retention.
The custom domain model
- Name
id- Type
- string
- Description
Domain id.
- Name
name- Type
- string
- Description
Domain name.
- Name
verified- Type
- boolean
- Description
Whether mail is accepted.
- Name
verified_at- Type
- timestamp | null
- Description
When verification passed.
- Name
created_at- Type
- timestamp
- Description
Registration time.
- Name
dns- Type
- array
- Description
Records to publish. Each has
kind(MXorTXT),name(owner name) andvalue.
Register a custom domain
Registers a domain and returns the records to publish. Returns 201.
400 bad_request: not a usable mail domain.402 payment_required: you are at your custom-domain limit.403 tier_required: your tier has no custom domains.409 conflict: the domain is already registered.
Required attributes
- Name
name- Type
- string
- Description
The domain, for example
mail.example.com.
Request
curl https://mail.nullnet.sh/v1/domains \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{"name": "mail.example.com"}'
Response
{
"id": "019a2f52-7a10-7c33-9e4b-2d5f7a9c1e3f",
"name": "mail.example.com",
"verified": false,
"verified_at": null,
"created_at": "2026-10-26T08:00:00Z",
"dns": [
{ "kind": "MX", "name": "mail.example.com", "value": "10 mail.nullnet.sh" },
{ "kind": "TXT", "name": "_grrla.mail.example.com", "value": "grrla-verify=4f1c9a7e2b6d8f0a3c5e7b9d1f2a4c6e" }
]
}
List your custom domains
Returns your custom domains with their records, as an array of custom domain objects.
Request
curl https://mail.nullnet.sh/v1/domains/mine \
-H "Authorization: Bearer {token}"
Verify a custom domain
Looks up the TXT and MX records now and marks the domain verified when both match. Limited to 20 checks per hour.
Response
- Name
verified- Type
- boolean
- Description
Verification state after this check.
- Name
txt_ok- Type
- boolean
- Description
Whether the TXT record was found with the right token.
- Name
mx_ok- Type
- boolean
- Description
Whether an MX record points at the server.
- Name
txt_found- Type
- array
- Description
TXT strings seen at
_grrla.<domain>.
- Name
mx_found- Type
- array
- Description
MX hosts seen.
- Name
error- Type
- string | null
- Description
Resolver error, if a lookup failed.
Request
curl -X POST https://mail.nullnet.sh/v1/domains/019a2f52-7a10-7c33-9e4b-2d5f7a9c1e3f/verify \
-H "Authorization: Bearer {token}"
Response
{
"verified": true,
"txt_ok": true,
"mx_ok": true,
"txt_found": ["grrla-verify=4f1c9a7e2b6d8f0a3c5e7b9d1f2a4c6e"],
"mx_found": ["mail.nullnet.sh"],
"error": null
}
Remove a custom domain
Removes the domain and deletes its inboxes. Returns 204.
Request
curl -X DELETE https://mail.nullnet.sh/v1/domains/019a2f52-7a10-7c33-9e4b-2d5f7a9c1e3f \
-H "Authorization: Bearer {token}"