Mailbox API · Beta
Send and read mail
The Mailbox API lets you send and read mail from the mailboxes you own on builders.ac. It speaks Microsoft Graph, so if you already have a Graph client you keep it — you change the base URL and the credential, and nothing else.
- Base URL
https://api.builders.ac/api/mailbox/v1beta1- API Key
age1…The shared builders.ac API Key. Send it as a bearer token.
Before you start
Section titled “Before you start”Create a shared builders.ac API credential from the
API credentials page. Use its age1… API Key as the
bearer token. The matching API Secret stays local and is not used by the Mailbox API.
Base URL and auth
Section titled “Base URL and auth”Every request goes to:
https://api.builders.ac/api/mailbox/v1beta1The Graph surface lives under /azure/v1.0. Authenticate with your key as a bearer token:
Authorization: Bearer age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxPoint your client at us
Section titled “Point your client at us”Most Graph SDKs only attach the bearer token to hosts they trust. Pointed at another base
URL they send the request unauthenticated, and you get a 401 that looks like a bad key.
Tell the SDK to trust our host:
import { Client } from '@microsoft/microsoft-graph-client';
const client = Client.init({baseUrl: 'https://api.builders.ac/api/mailbox/v1beta1/azure',defaultVersion: 'v1.0',authProvider: (done) => done(null, process.env.BUILDERS_API_KEY),// Required. Without this the SDK omits your key and every call returns 401.customHosts: new Set(['api.builders.ac']),});var http = new HttpClient { BaseAddress = new Uri("https://api.builders.ac/api/mailbox/v1beta1/azure/v1.0")};
// Allow the credential to be sent to our host, as customHosts does in the JS SDK.var graph = new GraphServiceClient(http, new StaticTokenProvider(buildersApiKey));Send an email
Section titled “Send an email”sendMail takes Graph’s own payload and returns 202 Accepted with an empty body once
Microsoft accepts the message. Full request schema in
the reference.
curl -X POST \https://api.builders.ac/api/mailbox/v1beta1/azure/v1.0/users/alice@acme.com/sendMail \-H "Authorization: Bearer $BUILDERS_API_KEY" \-H "Content-Type: application/json" \-d '{"message":{"subject":"Hi","body":{"contentType":"Text","content":"hello"}, "toRecipients":[{"emailAddress":{"address":"lead@example.com"}}]}}'await client.api("/users/alice@acme.com/sendMail").post({ message: { subject: "Hi", body: { contentType: "Text", content: "hello" }, toRecipients: [{ emailAddress: { address: "lead@example.com" } }], }, saveToSentItems: true,});Read mail
Section titled “Read mail”List messages with the OData parameters you already use — $select, $filter, $top,
$orderby — forwarded to Microsoft untouched.
const inbox = await client .api("/users/alice@acme.com/messages") .select("id,subject,from,receivedDateTime") .top(25) .get();curl -G \https://api.builders.ac/api/mailbox/v1beta1/azure/v1.0/users/alice@acme.com/messages \-H "Authorization: Bearer $BUILDERS_API_KEY" \--data-urlencode '$select=id,subject,from,receivedDateTime' \--data-urlencode '$top=25'Always send $select. The default projection is large, and message bodies dominate the
response. Every supported parameter is listed under
List messages.
Paging
Section titled “Paging”We rewrite @odata.nextLink to point back at us, so page iterators work unchanged and you
never receive a raw graph.microsoft.com link that your key could not authenticate
against.
import { PageIterator } from "@microsoft/microsoft-graph-client";
const first = await client.api("/users/alice@acme.com/messages").top(25).get();
await new PageIterator(client, first, (message) => { console.log(message.subject); return true;}).iterate();What you can call
Section titled “What you can call”The proxy runs a strict allow-list. These four routes are reachable; anything else returns
404 even if it exists in Graph.
| Method | Path |
|---|---|
POST |
/users/{email}/sendMail |
GET |
/users/{email}/messages |
GET |
/users/{email}/messages/{id} |
GET |
/users/{email}/mailFolders |
You can only address mailboxes belonging to your account. A mailbox that is not yours
returns 404 rather than 403, so the API never confirms which addresses exist. A
supported path with the wrong method returns 405.
Errors
Section titled “Errors”Errors on the Graph surface come back in Microsoft’s own format, including errors we raise ourselves, so your existing Graph error handling keeps working.
{ "error": { "code": "ResourceNotFound", "message": "No such mailbox.", "innerError": { "request-id": "…", "date": "…" } }}| Status | Meaning |
|---|---|
401 |
Missing, invalid, or revoked API Key. |
403 |
The authenticated account is not permitted to perform the operation. |
404 |
Unknown mailbox or path, including a mailbox that is not yours. |
405 |
Supported path, unsupported method. |
413 |
Request body above 10 MB. |
429 |
Rate limit exceeded. See Retry-After. |
502 |
We could not reach Microsoft. Ambiguous for sends. |
503 |
Temporarily unavailable. Safe to retry with backoff. |
Rate limits
Section titled “Rate limits”60 requests per minute per API credential and per account. Creating another credential
does not increase the account-wide allowance. Going over either bucket returns 429 with
Retry-After and X-RateLimit-* headers — wait the number of seconds given and try again.
Microsoft’s own throttling is passed through with its headers intact, so your SDK’s built-in
backoff keeps working.
Read mailbox events
Section titled “Read mailbox events”GET /events lists sent and received messages observed across your mailboxes over the
last seven days. Use it when an integration needs classified activity such as replies or
warmup traffic without polling every mailbox through Graph.
curl -G https://api.builders.ac/api/mailbox/v1beta1/events \-H "Authorization: Bearer $BUILDERS_API_KEY" \--data-urlencode 'classification=reply,other_inbound' \--data-urlencode 'limit=100'Continue with next_cursor as starting_after, keeping the same filters and order.
Events can appear after their created_at time because classification is asynchronous;
when following the feed, overlap the created[gte] window and deduplicate on event id.
Coverage is limited to mailboxes with a live Microsoft Graph subscription, and
classification is best-effort.
Not available yet
Section titled “Not available yet”Two provider capabilities are reserved in the API reference but are not callable today:
- Event webhooks — push subscriptions are future work. Poll the available
/eventsfeed for now. - Gmail — reserved under a
/google/prefix, which answers501so you can detect it deliberately. Only Microsoft 365 mailboxes work today.
Migrate from v1alpha1
Section titled “Migrate from v1alpha1”The upstream Graph portion of the URL does not change. Only the builders.ac API version and credential change:
| Retiring | Current | |
|---|---|---|
| Base | https://api.builders.ac/api/mailbox/v1alpha1 | https://api.builders.ac/api/mailbox/v1beta1 |
| Bearer | Vibe sk_live_… Mailbox key |
Shared builders.ac age1… API Key |
| Graph suffix | /azure/v1.0 |
/azure/v1.0 |
Create the new credential, replace the bearer value, and change v1alpha1 to v1beta1.
The Microsoft Graph request paths and SDK calls stay the same.
Getting help
Section titled “Getting help”When something goes wrong, quote the x-correlation-id response header — the same value
appears as request-id inside our error bodies. It identifies the exact request,
including Microsoft’s own id from x-ms-request-id, which is what we need to escalate on
your behalf.