EmailAlias API
REST API for managing aliases, custom domains, and exposure intelligence.
Machine-readable spec: /openapi.json (OpenAPI 3 — for AI agents, code generators, and Postman/Insomnia imports).
API access is a Premium feature
API keys can only be created and used by Premium subscribers. Free accounts can still manage aliases through the web dashboard. Upgrade to Premium →
Quick Start
Create an API key
In the dashboard, go to Settings → API Keys and click Create. Copy the key immediately — it's only shown once.
Make your first request
Send the key as a Bearer token in the Authorization header.
curl -X POST https://emailalias.io/api/aliases \
-H "Authorization: Bearer ea_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"alias_type": "random", "label": "Shopping"}'Authentication
Every request must include a Bearer token in the Authorization header. API keys are prefixed with ea_live_, never expire, and are hashed at rest.
Authorization: Bearer ea_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Security: Keep your API key secret. If compromised, delete it from Settings → API Keys and create a new one. Each Premium account can hold up to 5 keys.
Rate Limits
Rate limit headers are returned on every response: X-RateLimit-Remaining, X-RateLimit-Reset.
| Limit | Premium |
|---|---|
| Requests per minute | 300 |
| Emails sent per day | 350 |
| Aliases created per day | 20 |
| Total aliases (soft cap) | 150 |
Forwarding Destinations
Manage additional verified inboxes that aliases can forward to. Your primary account email is always available as a destination; up to 5 extras can be added.
/api/destinationsList the primary destination followed by any extras (verified or pending). The primary row has id=null and is_primary=true.
[
{
"id": null,
"email": "you@example.com",
"verified": true,
"is_primary": true,
"created_at": "2026-03-01T12:00:00Z"
},
{
"id": "b2c3d4e5-...",
"email": "work@example.com",
"verified": true,
"is_primary": false,
"created_at": "2026-04-10T09:24:11Z"
},
{
"id": "c3d4e5f6-...",
"email": "newsletter@example.com",
"verified": false,
"is_primary": false,
"created_at": "2026-04-23T08:40:02Z"
}
]/api/destinationsAdd a new destination. Sends a verification email to the address. The destination is not usable until verified by clicking the link (24h expiry).
{ "email": "work@example.com" }{
"id": "b2c3d4e5-...",
"email": "work@example.com",
"verified": false,
"is_primary": false,
"created_at": "2026-04-23T08:40:02Z"
}/api/destinations/{destination_id}/resendRegenerate the verification token and resend the verification email.
{
"id": "b2c3d4e5-...",
"email": "work@example.com",
"verified": false,
"is_primary": false,
"created_at": "2026-04-23T08:40:02Z"
}/api/destinations/{destination_id}Remove a destination. Returns 409 if any alias still forwards to it — reassign those aliases first.
// 204 No Content
Aliases
Create, list, update, and delete email aliases.
/api/aliasesList all aliases belonging to the authenticated user.
[
{
"id": "5e2a7d8c-0f3b-4a1e-9c2d-4a6b8f9e1a7c",
"alias_code": "x7k9m",
"alias_email": "x7k9m@email91.com",
"destination_email": "you@example.com",
"active": true,
"label": "Shopping",
"display_name": "Sam Carter",
"display_name_pending": null,
"display_name_pending_since": null,
"created_at": "2026-04-20T10:15:32Z"
}
]/api/aliasesCreate a new alias. All fields except alias_type are optional. destination_email must be your primary address or a verified forwarding destination — omit to use primary. display_name is shown as the sender on outbound mail ("Name <addr>"); first-time set on creation activates immediately, subsequent edits go through the dedicated /display-name endpoint with a 24h cooldown.
{
"alias_type": "random",
"label": "Shopping",
"domain": "email91.com",
"destination_email": "secondary@example.com",
"display_name": "Sam Carter"
}{
"id": "5e2a7d8c-0f3b-4a1e-9c2d-4a6b8f9e1a7c",
"alias_code": "x7k9m",
"alias_email": "x7k9m@email91.com",
"destination_email": "you@example.com",
"active": true,
"label": "Shopping",
"display_name": "Sam Carter",
"display_name_pending": null,
"display_name_pending_since": null,
"created_at": "2026-04-23T08:42:11Z"
}/api/aliases/{alias_id}Toggle active state, update the label, or change the forwarding destination. To change the display name, use the dedicated /display-name endpoint instead — it has a 24h cooldown that this endpoint bypasses.
{
"active": false,
"label": "Retired"
}{
"id": "5e2a7d8c-0f3b-4a1e-9c2d-4a6b8f9e1a7c",
"alias_code": "x7k9m",
"alias_email": "x7k9m@email91.com",
"destination_email": "you@example.com",
"active": false,
"label": "Retired",
"display_name": "Sam Carter",
"display_name_pending": null,
"display_name_pending_since": null,
"created_at": "2026-04-20T10:15:32Z"
}/api/aliases/{alias_id}/display-nameSchedule a display-name change for the alias. Edits do NOT take effect immediately — the new value lands in display_name_pending and promotes to display_name 24 hours after the most recent edit. Editing again resets the clock to NOW. Capped at 3 edits per rolling 24h per alias. Sending null or an empty string clears the name (also 24h-delayed). Brand-impersonation patterns (PayPal, Apple, banks, etc.) are blocked after homoglyph and leetspeak normalisation. Returns 400 on validation failure, 429 when the rate limit is exhausted.
{
"display_name": "John Smith"
}{
"id": "5e2a7d8c-0f3b-4a1e-9c2d-4a6b8f9e1a7c",
"alias_code": "x7k9m",
"alias_email": "x7k9m@email91.com",
"destination_email": "you@example.com",
"active": true,
"label": "Shopping",
"display_name": "Sam Carter",
"display_name_pending": "John Smith",
"display_name_pending_since": "2026-05-01T10:00:00Z",
"created_at": "2026-04-20T10:15:32Z"
}/api/aliases/{alias_id}Permanently delete an alias. Returns 204 on success.
// 204 No Content
/api/aliases/domainsList domains available for alias creation (system + your verified custom domains).
[
{ "domain": "email91.com", "type": "system", "is_default": true },
{ "domain": "yourdomain.com", "type": "custom", "is_default": false }
]Send Email
Send outbound mail from an alias. The recipient only sees the alias address.
/api/send-emailSend an email from one of your aliases.
{
"alias_id": "5e2a7d8c-0f3b-4a1e-9c2d-4a6b8f9e1a7c",
"to_email": "recipient@example.com",
"subject": "Hello",
"body": "Sent from my alias.",
"html_body": "<p>Sent from my alias.</p>"
}{
"success": true,
"message_id": "010001909f4e-...-000000@us-west-2.amazonses.com",
"message": "Email sent successfully."
}Custom Domains
Register and verify your own domains for branded aliases.
/api/domainsList all custom domains on the account, with each DNS check reported individually. `verified` flips to true once txt, mx, spf, dkim, and dmarc all pass. `mail_from_verified` is a separate, optional cosmetic upgrade (bounce.<domain> Return-Path) and does not gate `verified`.
[
{
"id": "a1b2c3d4-5e6f-7a8b-9c0d-e1f2a3b4c5d6",
"domain_name": "yourdomain.com",
"verified": true,
"verification_token": "emailalias-verify=...",
"txt_verified": true,
"mx_verified": true,
"spf_verified": true,
"dkim_verified": true,
"dmarc_verified": true,
"mail_from_verified": true,
"alias_count": 12,
"created_at": "2026-03-12T14:22:08Z",
"required_dns_records": [
{ "type": "TXT", "name": "@", "value": "emailalias-verify=..." },
{ "type": "MX", "name": "@", "value": "inbound-smtp.us-east-1.amazonaws.com", "priority": 10 }
]
}
]/api/domainsRegister a new custom domain. Response includes the DNS records you must publish: ownership TXT, inbound MX, SPF/DMARC TXT, 3 DKIM CNAMEs, plus 2 optional records under bounce.<domain> for Custom MAIL FROM. The first 5 dimensions gate `verified`; MAIL FROM is opt-in and tracked separately as `mail_from_verified`.
{ "domain_name": "yourdomain.com" }{
"id": "a1b2c3d4-5e6f-7a8b-9c0d-e1f2a3b4c5d6",
"domain_name": "yourdomain.com",
"verified": false,
"verification_token": "emailalias-verify=abc123...",
"txt_verified": false,
"mx_verified": false,
"spf_verified": false,
"dkim_verified": false,
"dmarc_verified": false,
"mail_from_verified": false,
"alias_count": 0,
"created_at": "2026-04-23T08:45:00Z",
"required_dns_records": [
{ "type": "TXT", "name": "@", "value": "emailalias-verify=abc123..." },
{ "type": "MX", "name": "@", "value": "inbound-smtp.us-east-1.amazonaws.com", "priority": 10 },
{ "type": "TXT", "name": "@", "value": "v=spf1 include:amazonses.com ~all" },
{ "type": "TXT", "name": "_dmarc", "value": "v=DMARC1; p=quarantine; rua=mailto:dmarc@emailalias.io" },
{ "type": "MX", "name": "bounce", "value": "feedback-smtp.us-east-1.amazonses.com", "priority": 10 },
{ "type": "TXT", "name": "bounce", "value": "v=spf1 include:amazonses.com ~all" },
{ "type": "CNAME", "name": "<dkim>._domainkey", "value": "<dkim>.dkim.amazonses.com" }
]
}/api/domains/{domain_id}/verifyRe-check DNS. Domain becomes verified only when the 5 core checks pass (txt/mx/spf/dkim/dmarc). mail_from_verified is reported separately and does not gate the verified flag — including it would silently flip already-verified domains back to Pending after MAIL FROM was added as a feature.
{
"verified": true,
"txt_verified": true,
"mx_verified": true,
"spf_verified": true,
"dkim_verified": true,
"dmarc_verified": true,
"mail_from_verified": true,
"message": "Domain fully verified. SPF, DKIM, and DMARC are all configured correctly.",
"failed_checks": []
}/api/domains/{domain_id}Remove a domain. Aliases on this domain are also deleted. Returns 204 on success.
// 204 No Content
Analytics
Dashboard stats, forwarding logs, and exposure events.
/api/analytics/dashboardHigh-level counters for the authenticated user.
{
"total_aliases": 12,
"active_aliases": 10,
"emails_forwarded": 348,
"emails_blocked": 21,
"exposure_alerts": 2
}/api/analytics/logs?page=1&per_page=25Paginated email delivery log (inbound + outbound).
{
"items": [
{
"id": "c3d4e5f6-...",
"alias_id": "5e2a7d8c-...",
"alias_email": "x7k9m@email91.com",
"sender_email": "noreply@shop.com",
"recipient_email": "you@example.com",
"subject": "Your order #1234",
"received_at": "2026-04-23T07:12:45Z",
"direction": "inbound",
"status": "delivered",
"block_reason": null
}
],
"total": 348,
"page": 1,
"per_page": 25,
"pages": 14
}/api/analytics/exposure?page=1&per_page=25Aliases flagged with suspicious sender activity or leaked to third parties.
{
"items": [
{
"id": "e5f6a7b8-...",
"alias_id": "5e2a7d8c-...",
"alias_email": "x7k9m@email91.com",
"sender_domain": "suspicious-marketer.com",
"risk_score": 78,
"detected_at": "2026-04-18T03:01:17Z"
}
],
"total": 2,
"page": 1,
"per_page": 25,
"pages": 1
}Errors
All errors use standard HTTP status codes and return a JSON body.
{
"detail": "Human-readable error message"
}| Code | Status | Description |
|---|---|---|
| 400 | Bad Request | Invalid body or missing required fields. |
| 401 | Unauthorized | Missing or invalid API key. |
| 403 | Forbidden | Action not permitted (e.g. accessing an alias or domain you do not own). |
| 404 | Not Found | The requested resource does not exist. |
| 409 | Conflict | Resource already exists (e.g. duplicate domain). |
| 422 | Unprocessable Entity | Validation failed on the request body. |
| 429 | Too Many Requests | Rate limit exceeded. Retry after X-RateLimit-Reset. |
| 500 | Internal Server Error | Unexpected error. Contact support if it persists. |
cURL Cookbook
Copy-paste recipes for every endpoint. Set EMAILALIAS_API_KEY in your shell first:
export EMAILALIAS_API_KEY="ea_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Aliases
/api/aliasesList aliasescurl https://emailalias.io/api/aliases \ -H "Authorization: Bearer $EMAILALIAS_API_KEY"
/api/aliasesCreate a random aliascurl -X POST https://emailalias.io/api/aliases \
-H "Authorization: Bearer $EMAILALIAS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"alias_type":"random","label":"Shopping"}'/api/aliasesCreate a custom aliascurl -X POST https://emailalias.io/api/aliases \
-H "Authorization: Bearer $EMAILALIAS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"alias_type":"custom","custom_code":"work-signup","label":"Work","destination_email":"work@example.com"}'/api/aliasesCreate alias with display name (Premium)curl -X POST https://emailalias.io/api/aliases \
-H "Authorization: Bearer $EMAILALIAS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"alias_type":"random","display_name":"Sam Carter"}'/api/aliases/{id}/display-nameEdit display name — 24h cooldown (Premium)# Schedules the change. Goes live 24h after this edit.
# Limit: 3 edits per rolling 24h per alias. Brand impersonation
# (PayPal, Apple, banks, etc.) is rejected with 400.
curl -X PATCH https://emailalias.io/api/aliases/ALIAS_ID/display-name \
-H "Authorization: Bearer $EMAILALIAS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"display_name":"John Smith"}'/api/aliases/{id}/display-nameClear display name — 24h cooldown (Premium)# Clearing also goes through cooldown — blocks the
# "set brand → blast → clear" abuse cycle.
curl -X PATCH https://emailalias.io/api/aliases/ALIAS_ID/display-name \
-H "Authorization: Bearer $EMAILALIAS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"display_name":null}'/api/aliases/{id}Disable an aliascurl -X PATCH https://emailalias.io/api/aliases/ALIAS_ID \
-H "Authorization: Bearer $EMAILALIAS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"active":false}'/api/aliases/{id}Delete an aliascurl -X DELETE https://emailalias.io/api/aliases/ALIAS_ID \ -H "Authorization: Bearer $EMAILALIAS_API_KEY"
/api/aliases/domainsList available alias domainscurl https://emailalias.io/api/aliases/domains \ -H "Authorization: Bearer $EMAILALIAS_API_KEY"
Forwarding Destinations
/api/destinationsList destinationscurl https://emailalias.io/api/destinations \ -H "Authorization: Bearer $EMAILALIAS_API_KEY"
/api/destinationsAdd a destinationcurl -X POST https://emailalias.io/api/destinations \
-H "Authorization: Bearer $EMAILALIAS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"email":"work@example.com"}'/api/destinations/{id}/resendResend verification emailcurl -X POST https://emailalias.io/api/destinations/DESTINATION_ID/resend \ -H "Authorization: Bearer $EMAILALIAS_API_KEY"
/api/destinations/{id}Remove a destinationcurl -X DELETE https://emailalias.io/api/destinations/DESTINATION_ID \ -H "Authorization: Bearer $EMAILALIAS_API_KEY"
Send Email
/api/send-emailSend from an aliascurl -X POST https://emailalias.io/api/send-email \
-H "Authorization: Bearer $EMAILALIAS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"alias_id":"ALIAS_ID",
"to_email":"recipient@example.com",
"subject":"Hello",
"body":"Sent from my alias."
}'Custom Domains
/api/domainsList custom domainscurl https://emailalias.io/api/domains \ -H "Authorization: Bearer $EMAILALIAS_API_KEY"
/api/domainsRegister a new domaincurl -X POST https://emailalias.io/api/domains \
-H "Authorization: Bearer $EMAILALIAS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"domain_name":"yourdomain.com"}'/api/domains/{id}/verifyRe-verify DNScurl -X POST https://emailalias.io/api/domains/DOMAIN_ID/verify \ -H "Authorization: Bearer $EMAILALIAS_API_KEY"
/api/domains/{id}Remove a domaincurl -X DELETE https://emailalias.io/api/domains/DOMAIN_ID \ -H "Authorization: Bearer $EMAILALIAS_API_KEY"
Analytics
/api/analytics/dashboardDashboard counterscurl https://emailalias.io/api/analytics/dashboard \ -H "Authorization: Bearer $EMAILALIAS_API_KEY"
/api/analytics/logsEmail logs (paginated)curl "https://emailalias.io/api/analytics/logs?page=1&per_page=25" \ -H "Authorization: Bearer $EMAILALIAS_API_KEY"
/api/analytics/exposureExposure events (paginated)curl "https://emailalias.io/api/analytics/exposure?page=1&per_page=25" \ -H "Authorization: Bearer $EMAILALIAS_API_KEY"
Client Libraries
Official clients for common runtimes. Each wraps the same REST API documented above — install, drop in your API key, and go.
Using an AI assistant?
Manage aliases from Claude Desktop, Cursor, Zed and other MCP clients in natural language — “create a shopping alias,” “disable the amazon one,” “show this week's exposure events.”
Set up the EmailAlias MCP serverPython
emailalias/emailalias-python
pip install emailalias
from emailalias import Client
client = Client(api_key="ea_live_xxx")
alias = client.create_alias(alias_type="random", label="Shopping")
print(alias["alias_email"])
for a in client.list_aliases():
print(a["alias_email"], "→", a["destination_email"])Building for another language? The API is just REST + Bearer tokens — any HTTP client works. See the Quick Start curl example.