Hostinger Email API + MCP β
Source: https://api.mail.hostinger.com/ (Scalar docs; spec at /openapi/openapi.json) Local spec copy: docs/contracts/hostinger-mail-openapi.json (v1.0.1, fetched 2026-07-02) Related: docs/MAILBOX_CONNECT.md β the current in-app IMAP integration for the same four Hostinger inboxes. This REST/MCP API is a programmatic alternative to IMAP.
Overview β
REST API to manage Hostinger Email mailboxes programmatically: read/search/send/move/flag/delete messages, manage folders, quotas, and webhooks.
| Base URL | https://api.mail.hostinger.com |
| Auth | Authorization: Bearer YOUR_API_TOKEN |
| Token source | hPanel β Emails β select domain β Agentic mail β API β Create API token (shown once β copy immediately) |
| Token scope | One order per token; optionally restricted to specific mailboxes within that order |
| Content type | application/json |
| Rate limiting | 429 Too Many Requests on excess; repeated abuse may temp-block the IP |
Local token location: env/local.secrets.json (gitignored β see env/README.md): HOSTINGER_MAIL_ALDILAIJAN_API_TOKEN (aldilaijan.com order) and HOSTINGER_MAIL_KHOBARA_API_TOKEN (khobara.com.kw order).
Our accounts (both tokens verified 2026-07-02 via GET /api/v1/me) β
Tokens are order-scoped, so each brand's order has its own token. All four production inboxes are covered:
| Token key | Order | Mailbox | Resource ID |
|---|---|---|---|
HOSTINGER_MAIL_ALDILAIJAN_API_TOKEN | OR7452ba096bde4fb9a6882efad75d | [email protected] | ACfb0f0524a66299f0f6a2f424bd03 |
[email protected] | ACb5225fcda06ecc739cf19ae9cf07 | ||
HOSTINGER_MAIL_KHOBARA_API_TOKEN | ORaadbc595abd420b460b4db4a5789 | [email protected] | AC9040a952971bef0b3f93fe3b9a31 |
[email protected] | AC370169a8b9bd46764279d020a98c |
Gotcha: the API sits behind Cloudflare bot protection. Requests with Python's default
urllib/requestsuser agent get 403 error 1010 before reaching the API. Send a browser-likeUser-Agentheader (curl's default also works).
Webmail login (branded, self-hosted Roundcube) β
Hostinger has no webmail white-labeling, so mail.<domain> runs our own branded Roundcube (navy/cyan design system, per-brand logo and product name, login domain auto-appended) against Hostinger IMAP/SMTP (ssl://imap.hostinger.com:993 / ssl://smtp.hostinger.com:465). Full deployment lives in infra/webmail/ and runs at /docker/webmail/ on the Hermes VPS behind Traefik.
| URL | Status |
|---|---|
https://mail.khobara.com.kw | Live (2026-07-02). DNS A mail β 187.124.11.201 via Hostinger DNS API; LE cert by Traefik. |
https://mail.aldilaijan.com | Live, Cloudflare-proxied (2026-07-02). A mail β 187.124.11.201 proxied (orange cloud); origin cert renews via DNS-01 (Traefik cloudflare resolver, token in /docker/traefik/.env = CLOUDFLARE_ALDILAIJAN_DNS_API_TOKEN in env/local.secrets.json), so renewals don't depend on the proxy passing HTTP-01. The interim redirect Worker was deleted. |
ACME gotchas hit during cutover: (1) failed HTTP-01 attempts burn Let's Encrypt's 5 failed authorizations per hour limit AND Traefik holds the failure in memory without retrying β restart Traefik once the window passes. (2) When switching a router to a different certresolver, Traefik keeps serving the old store's still-valid cert and the new resolver never issues β evict the hostname's entry from the old
acme.json(Traefik stopped, backup first) to force issuance into the new store.
Response conventions β
- All non-
204responses wrap the payload in a top-leveldatafield (object or array). - Paginated lists add a
paginationobject:{ "page", "perPage", "total", "totalPages" }. Default 50/page; select with?page=N. - All
4xx/5xxerrors share one envelope β parsecodeprogrammatically,erroris human-readable:
{ "error": "Mailbox not found.", "code": "ERR_MAILBOX_NOT_FOUND", "params": {} }Endpoints (v1) β
All paths are prefixed https://api.mail.hostinger.com. {mailboxResourceId} is the mailbox resource id (e.g. AC1a2b3c4d5e6f7g), {folder} a folder name, {uid} a message uid.
Account & quota β
| Method | Path | Summary |
|---|---|---|
| GET | /api/v1/me | Get the authenticated account |
| GET | /api/v1/mailboxes/{mailboxResourceId}/quota | Get mailbox quota |
Messages β
| Method | Path | Summary |
|---|---|---|
| GET | /api/v1/mailboxes/{id}/folders/{folder}/messages | List messages |
| DELETE | /api/v1/mailboxes/{id}/folders/{folder}/messages | Delete all messages in folder |
| GET | /api/v1/mailboxes/{id}/folders/{folder}/messages/{uid} | Get message |
| DELETE | /api/v1/mailboxes/{id}/folders/{folder}/messages/{uid} | Delete message |
| PATCH | /api/v1/mailboxes/{id}/folders/{folder}/messages/{uid} | Update message flags |
| POST | /api/v1/mailboxes/{id}/folders/{folder}/messages/delete | Delete messages (bulk) |
| GET | /api/v1/mailboxes/{id}/folders/{folder}/messages/{uid}/attachments/{attachmentId} | Download attachment |
| GET | /api/v1/mailboxes/{id}/folders/{folder}/messages/{uid}/source | Get raw message source |
| GET | /api/v1/mailboxes/{id}/folders/{folder}/messages/{uid}/text | Get message text content |
| POST | /api/v1/mailboxes/{id}/folders/{folder}/messages/{uid}/move | Move message |
| POST | /api/v1/mailboxes/{id}/folders/{folder}/messages/move | Move messages (bulk) |
| POST | /api/v1/mailboxes/{id}/folders/{folder}/messages/search | Search messages |
| POST | /api/v1/mailboxes/{id}/folders/{folder}/messages/flags | Update flags (bulk) |
Send β
| Method | Path | Summary |
|---|---|---|
| POST | /api/v1/mailboxes/{id}/send | Send email |
Folders β
| Method | Path | Summary |
|---|---|---|
| GET | /api/v1/mailboxes/{id}/folders | List folders |
| POST | /api/v1/mailboxes/{id}/folders | Create folder |
| PUT | /api/v1/mailboxes/{id}/folders/{folder} | Update folder |
| DELETE | /api/v1/mailboxes/{id}/folders/{folder} | Delete folder |
Webhooks β
| Method | Path | Summary |
|---|---|---|
| GET | /api/v1/mailboxes/{id}/webhooks | List webhooks |
| POST | /api/v1/mailboxes/{id}/webhooks | Create webhook |
| GET | /api/v1/mailboxes/{id}/webhooks/{webhook} | Get webhook |
| PATCH | /api/v1/mailboxes/{id}/webhooks/{webhook} | Update webhook |
| DELETE | /api/v1/mailboxes/{id}/webhooks/{webhook} | Delete webhook |
| POST | /api/v1/mailboxes/{id}/webhooks/{webhook}/regenerate-secret | Regenerate webhook secret |
| POST | /api/v1/mailboxes/{id}/webhooks/{webhook}/test | Test webhook |
AI agents (MCP) β
Hostinger ships an HTTP MCP server wrapping this API:
https://mcp.mail.hostinger.com/mcpSame bearer token as the REST API; the agent only reaches what the token permits (order-scoped, optionally mailbox-restricted). Tools mirror the REST surface: read, search, send, move, flag, delete messages; list folders and mailboxes; manage webhooks.
Claude Code (CLI) β
claude mcp add --scope user --transport http \
--header "Authorization: Bearer YOUR_HOSTINGER_API_TOKEN" \
-- hostinger-email https://mcp.mail.hostinger.com/mcpClaude Desktop β
Via mcp-remote stdio bridge in %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"hostinger-email": {
"command": "npx",
"args": [
"-y", "mcp-remote", "https://mcp.mail.hostinger.com/mcp",
"--header", "Authorization: Bearer YOUR_HOSTINGER_API_TOKEN"
]
}
}
}Or, with the paid Custom Connectors feature, direct HTTP:
{
"mcpServers": {
"hostinger-email": {
"type": "http",
"url": "https://mcp.mail.hostinger.com/mcp",
"headers": { "Authorization": "Bearer YOUR_HOSTINGER_API_TOKEN" }
}
}
}Cursor β
~/.cursor/mcp.json (global) or .cursor/mcp.json (project):
{
"mcpServers": {
"hostinger-email": {
"url": "https://mcp.mail.hostinger.com/mcp",
"headers": { "Authorization": "Bearer YOUR_HOSTINGER_API_TOKEN" }
}
}
}Quick smoke test β
After putting the token in env/local.secrets.json:
TOKEN=$(python -c "import json;print(json.load(open('env/local.secrets.json'))['HOSTINGER_MAIL_ALDILAIJAN_API_TOKEN'])")
curl -s -H "Authorization: Bearer $TOKEN" https://api.mail.hostinger.com/api/v1/meExpect {"data": {...account...}}; a 401 means the token is wrong or was pasted with whitespace.
