Paths are under https://emails.mydomainshub.com/api/v1. Send Authorization: Bearer mdh_live_… and, with a body, Content-Type: application/json. Errors are described in Errors; limits in Limits.
POST/emails
Send an email
Queues one email and answers its id. Our worker then sends it — at `scheduled_at`, if you gave one. The answer means queued, not delivered: read the status back, or watch the log.
Takes a sending or a full-access key.
Headers
| Field | Type | Description |
|---|---|---|
Idempotency-Key | string, 1 to 256 printable ASCII characters | The same key and body within 24 hours answers the first answer again and queues nothing more. See Idempotency. |
Body
| Field | Type | Description |
|---|---|---|
fromrequired | string | The sender: "Name <address>" or a bare address, at a domain verified on your account. |
torequired | string or array of strings | One address or a list. To, cc and bcc together hold at most 50 recipients, each once. |
cc | string or array of strings | One address or a list. |
bcc | string or array of strings | One address or a list. Never shown in the message’s headers. |
reply_to | string or array of strings | One address or a list, for the Reply-To header. |
subjectrequired | string | One line, 1 to 998 characters. |
html | string | The HTML body. Give html, text or both. |
text | string | The plain-text body. Give html, text or both. |
headers | object of strings | Extra headers: X-* (not X-SES-*), List-Unsubscribe, List-Unsubscribe-Post, List-Id, In-Reply-To, References and Auto-Submitted. At most 20. |
attachments | array of objects | Up to 20 files, each base64 in `content`. The whole request stays under 4 MB. Executable file types are refused. |
attachments[].filenamerequired | string | |
attachments[].contentrequired | string | |
attachments[].content_type | string | |
tags | array of objects | Up to 10 name and value pairs (letters, digits, _ and -), each name once, for finding the email later. |
tags[].namerequired | string | |
tags[].valuerequired | string | |
scheduled_at | string (ISO 8601 date and time) | When to send it: an ISO 8601 date and time with its zone, at most 72 hours ahead. A time already past sends it at once. Leave it out to send now. |
Answer
| Field | Type | Description |
|---|---|---|
idrequired | string (uuid) | The email’s id: GET /emails/{id} reads it back. |
Errors
| Status | name | When |
|---|---|---|
401 | unauthorized | The API key is missing, wrong or revoked. |
429 | rate_limited | More than 10 requests a second with this key (bursts of 20). Wait for retry-after. |
500 | internal_error | Something failed on our side. |
403 | forbidden, domain_not_verified, account_paused | The from domain is not verified on this account, the key is limited to another domain, the sandbox refuses the recipient, or sending is paused. |
409 | validation_error | The Idempotency-Key was used for a different request in the last 24 hours. |
413 | validation_error | The request is larger than 4 MB. |
422 | validation_error | The body is not valid (the message says where), or the content check refuses it: a From that imitates a bank, a payments company or a government body, a link through a URL shortener, or a program attached. |
429 | rate_limited, quota_exceeded | Too many requests with this key, or a daily or monthly cap is reached. Wait for retry-after. |
POST/emails/batch
Send up to 100 emails
A JSON array of 1 to 100 emails, each shaped as for POST /emails. Every one is checked first, and either all are queued or none is: a refusal names the first email refused as `emails[n]`.
Takes a sending or a full-access key.
Headers
| Field | Type | Description |
|---|---|---|
Idempotency-Key | string, 1 to 256 printable ASCII characters | The same key and body within 24 hours answers the first answer again and queues nothing more. See Idempotency. |
Body
A JSON array of 1 to 100 emails, each with the fields of POST /emails.
Answer
| Field | Type | Description |
|---|---|---|
datarequired | array of objects | One id per email, in the order they were sent. |
data[].idrequired | string (uuid) | The email’s id: GET /emails/{id} reads it back. |
Errors
| Status | name | When |
|---|---|---|
401 | unauthorized | The API key is missing, wrong or revoked. |
429 | rate_limited | More than 10 requests a second with this key (bursts of 20). Wait for retry-after. |
500 | internal_error | Something failed on our side. |
403 | forbidden, domain_not_verified, account_paused | The from domain is not verified on this account, the key is limited to another domain, the sandbox refuses the recipient, or sending is paused. |
409 | validation_error | The Idempotency-Key was used for a different request in the last 24 hours. |
413 | validation_error | The request is larger than 4 MB. |
422 | validation_error | The body is not valid (the message says where), or the content check refuses it: a From that imitates a bank, a payments company or a government body, a link through a URL shortener, or a program attached. |
429 | rate_limited, quota_exceeded | Too many requests with this key, or a daily or monthly cap is reached. Wait for retry-after. |
GET/emails
List emails
The account’s emails, newest first, a page at a time. Filters combine: every one given must match.
Takes a full-access key.
Query parameters
| Field | Type | Description |
|---|---|---|
limit | integer | How many to answer, 1 to 100. 20 unless given. |
cursor | string | The `next_cursor` of the page before, as it was given, for the next (older) page. |
status | one of: queued, sending, sent, delivered, bounced, complained, failed, suppressed, canceled | Only emails with this status. |
to | string (email address) | Only emails to exactly this address, in to, cc or bcc. |
tag | string | Only emails with this tag name, or this name:value pair. |
subject | string | Only emails whose subject contains this text, in any case. |
created_after | string (ISO 8601 date and time) | Only emails queued at or after this moment (ISO 8601 with its zone). |
created_before | string (ISO 8601 date and time) | Only emails queued before this moment (ISO 8601 with its zone). |
Answer
| Field | Type | Description |
|---|---|---|
objectrequired | "list" | |
datarequired | array of objects | |
data[].objectrequired | "email" | |
data[].idrequired | string (uuid) | |
data[].fromrequired | string | |
data[].torequired | array of strings | |
data[].ccrequired | array of strings | |
data[].bccrequired | array of strings | |
data[].reply_torequired | array of strings | |
data[].subjectrequired | string | |
data[].tagsrequired | array of objects | |
data[].tags[].namerequired | string | |
data[].tags[].valuerequired | string | |
data[].statusrequired | one of: queued, sending, sent, delivered, bounced, complained, failed, suppressed, canceled | |
data[].status_reasonrequired | string or null | Why it failed, was suppressed or canceled, as a short code; otherwise null. |
data[].created_atrequired | string | When it was queued. |
data[].scheduled_atrequired | string | When it may be sent: the moment it was queued, unless scheduled. |
data[].sent_atrequired | string or null | ISO 8601, UTC; null until it happens. |
data[].delivered_atrequired | string or null | ISO 8601, UTC; null until it happens. |
data[].bounced_atrequired | string or null | ISO 8601, UTC; null until it happens. |
data[].complained_atrequired | string or null | ISO 8601, UTC; null until it happens. |
data[].failed_atrequired | string or null | ISO 8601, UTC; null until it happens. |
data[].canceled_atrequired | string or null | ISO 8601, UTC; null until it happens. |
data[].last_eventrequired | one of: send, delivery, bounce, complaint, reject, delivery_delay, rendering_failure or null | The latest event Amazon SES reported. |
data[].last_event_atrequired | string or null | ISO 8601, UTC; null until it happens. |
has_morerequired | boolean | |
next_cursorrequired | string or null | Pass as `cursor` for the next page; null on the last page. |
Errors
| Status | name | When |
|---|---|---|
401 | unauthorized | The API key is missing, wrong or revoked. |
429 | rate_limited | More than 10 requests a second with this key (bursts of 20). Wait for retry-after. |
500 | internal_error | Something failed on our side. |
403 | forbidden | A sending key was used: this takes a full-access key. |
422 | validation_error | A filter or the cursor is not valid. |
GET/emails/{id}
Read an email
Its status, its times and the last event Amazon SES reported. Never its body: bodies are kept 72 hours after sending, for the dashboard only.
Takes a full-access key.
Path
| Field | Type | Description |
|---|---|---|
idrequired | string (uuid) | The email’s id, as POST /emails answered it. |
Answer
| Field | Type | Description |
|---|---|---|
objectrequired | "email" | |
idrequired | string (uuid) | |
fromrequired | string | |
torequired | array of strings | |
ccrequired | array of strings | |
bccrequired | array of strings | |
reply_torequired | array of strings | |
subjectrequired | string | |
tagsrequired | array of objects | |
tags[].namerequired | string | |
tags[].valuerequired | string | |
statusrequired | one of: queued, sending, sent, delivered, bounced, complained, failed, suppressed, canceled | |
status_reasonrequired | string or null | Why it failed, was suppressed or canceled, as a short code; otherwise null. |
created_atrequired | string | When it was queued. |
scheduled_atrequired | string | When it may be sent: the moment it was queued, unless scheduled. |
sent_atrequired | string or null | ISO 8601, UTC; null until it happens. |
delivered_atrequired | string or null | ISO 8601, UTC; null until it happens. |
bounced_atrequired | string or null | ISO 8601, UTC; null until it happens. |
complained_atrequired | string or null | ISO 8601, UTC; null until it happens. |
failed_atrequired | string or null | ISO 8601, UTC; null until it happens. |
canceled_atrequired | string or null | ISO 8601, UTC; null until it happens. |
last_eventrequired | one of: send, delivery, bounce, complaint, reject, delivery_delay, rendering_failure or null | The latest event Amazon SES reported. |
last_event_atrequired | string or null | ISO 8601, UTC; null until it happens. |
Errors
| Status | name | When |
|---|---|---|
401 | unauthorized | The API key is missing, wrong or revoked. |
429 | rate_limited | More than 10 requests a second with this key (bursts of 20). Wait for retry-after. |
500 | internal_error | Something failed on our side. |
403 | forbidden | A sending key was used: this takes a full-access key. |
404 | not_found | No email with that id belongs to this account. |
PATCH/emails/{id}
Reschedule an email
Moves an email that is still waiting in the queue to another time. It counts against your caps on the day it was first queued.
Takes a full-access key.
Path
| Field | Type | Description |
|---|---|---|
idrequired | string (uuid) | The email’s id. |
Body
| Field | Type | Description |
|---|---|---|
scheduled_atrequired | string (ISO 8601 date and time) | The new moment to send it: ISO 8601 with its zone, at most 72 hours ahead. A time already past sends it at once. |
Answer
| Field | Type | Description |
|---|---|---|
objectrequired | "email" | |
idrequired | string (uuid) | |
statusrequired | one of: queued, sending, sent, delivered, bounced, complained, failed, suppressed, canceled | |
scheduled_atrequired | string | ISO 8601, UTC. |
Errors
| Status | name | When |
|---|---|---|
401 | unauthorized | The API key is missing, wrong or revoked. |
429 | rate_limited | More than 10 requests a second with this key (bursts of 20). Wait for retry-after. |
500 | internal_error | Something failed on our side. |
403 | forbidden | A sending key was used: this takes a full-access key. |
404 | not_found | No email with that id belongs to this account. |
409 | validation_error | The email has already left the queue (or is being sent). |
422 | validation_error | scheduled_at is missing, malformed or too far ahead. |
POST/emails/{id}/cancel
Cancel an email
Cancels an email that is still waiting in the queue — scheduled, or not yet picked up. Its recipients are given back to your caps, and its body is deleted. Cancelling a canceled email answers the same again.
Takes a full-access key.
Path
| Field | Type | Description |
|---|---|---|
idrequired | string (uuid) | The email’s id. |
Answer
| Field | Type | Description |
|---|---|---|
objectrequired | "email" | |
idrequired | string (uuid) | |
statusrequired | one of: queued, sending, sent, delivered, bounced, complained, failed, suppressed, canceled | |
scheduled_atrequired | string | ISO 8601, UTC. |
Errors
| Status | name | When |
|---|---|---|
401 | unauthorized | The API key is missing, wrong or revoked. |
429 | rate_limited | More than 10 requests a second with this key (bursts of 20). Wait for retry-after. |
500 | internal_error | Something failed on our side. |
403 | forbidden | A sending key was used: this takes a full-access key. |
404 | not_found | No email with that id belongs to this account. |
409 | validation_error | The email has already left the queue (or is being sent). |
GET/api-keys
List API keys
The account’s keys that are not revoked, newest first. Never a key itself.
Takes a full-access key.
Answer
| Field | Type | Description |
|---|---|---|
objectrequired | "list" | |
datarequired | array of objects | The account’s keys that are not revoked, newest first. |
data[].objectrequired | "api_key" | |
data[].idrequired | string (uuid) | |
data[].namerequired | string | |
data[].prefixrequired | string | The key’s first characters, to tell it apart. Never the key. |
data[].permissionrequired | one of: full, sending | |
data[].domain_idrequired | string (uuid) or null | The one domain a sending key is limited to, or null. |
data[].created_atrequired | string | ISO 8601, UTC. |
data[].last_used_atrequired | string or null | ISO 8601, UTC: moved at most once a minute; null if never used. |
Errors
| Status | name | When |
|---|---|---|
401 | unauthorized | The API key is missing, wrong or revoked. |
429 | rate_limited | More than 10 requests a second with this key (bursts of 20). Wait for retry-after. |
500 | internal_error | Something failed on our side. |
403 | forbidden | A sending key was used: this takes a full-access key. |
POST/api-keys
Create an API key
Makes a key and answers it once: we keep only a hash, so store it now. The account’s log records it, with the key that made it.
Takes a full-access key.
Body
| Field | Type | Description |
|---|---|---|
namerequired | string | What the key is for, 1 to 60 characters, so you can tell keys apart. |
permissionrequired | one of: full, sending | `sending`: may only send email. `full`: may also read emails, change scheduled ones, and manage keys. |
domain_id | string (uuid) | A sending key only: limit it to sending from this one domain of your account. |
Answer
| Field | Type | Description |
|---|---|---|
objectrequired | "api_key" | |
idrequired | string (uuid) | |
namerequired | string | |
prefixrequired | string | The key’s first characters, to tell it apart. Never the key. |
permissionrequired | one of: full, sending | |
domain_idrequired | string (uuid) or null | The one domain a sending key is limited to, or null. |
created_atrequired | string | ISO 8601, UTC. |
last_used_atrequired | string or null | ISO 8601, UTC: moved at most once a minute; null if never used. |
keyrequired | string | The key itself. Shown in this answer only: we keep a hash, and cannot show it again. |
Errors
| Status | name | When |
|---|---|---|
401 | unauthorized | The API key is missing, wrong or revoked. |
429 | rate_limited | More than 10 requests a second with this key (bursts of 20). Wait for retry-after. |
500 | internal_error | Something failed on our side. |
403 | forbidden | A sending key was used, or the account is closed. |
422 | validation_error | The body is not valid; the message says where. |
DELETE/api-keys/{id}
Revoke an API key
Revokes a key at once: requests with it are refused from now on, and emails it queued that have not left are not sent. Revoking a revoked key answers the same again.
Takes a full-access key.
Path
| Field | Type | Description |
|---|---|---|
idrequired | string (uuid) | The key’s id, from GET /api-keys. |
Answer
| Field | Type | Description |
|---|---|---|
objectrequired | "api_key" | |
idrequired | string (uuid) | |
revokedrequired | true |
Errors
| Status | name | When |
|---|---|---|
401 | unauthorized | The API key is missing, wrong or revoked. |
429 | rate_limited | More than 10 requests a second with this key (bursts of 20). Wait for retry-after. |
500 | internal_error | Something failed on our side. |
403 | forbidden | A sending key was used: this takes a full-access key. |
404 | not_found | No key with that id belongs to this account. |
GET/domains
List domains
The account’s domains, each with its status and, while it is pending, the DNS records to add.
Takes a full-access key.
Answer
| Field | Type | Description |
|---|---|---|
objectrequired | "list" | |
datarequired | array of objects | |
data[].objectrequired | "domain" | |
data[].idrequired | string (uuid) | |
data[].namerequired | string | |
data[].statusrequired | one of: pending, verified, failed, removing | |
data[].setting_uprequired | boolean | True while it is still being set up with Amazon SES. |
data[].created_atrequired | string | ISO 8601, UTC. |
data[].verify_byrequired | string or null | A pending domain only: 72 hours after it was added, the time to verify it by. Null otherwise. |
data[].verified_atrequired | string or null | ISO 8601, UTC; null until it happens. |
data[].last_checked_atrequired | string or null | ISO 8601, UTC; null until it happens. |
data[].failurerequired | object or null | Why it failed, and the record that was missing; null unless failed. |
data[].failure.reasonrequired | string | |
data[].failure.missing_recordrequired | string or null | |
data[].recordsrequired | array of objects | The DNS records to add at your DNS host; empty while it is being set up, and once it has failed. |
data[].records[].recordrequired | one of: dkim, mail_from_mx, mail_from_spf, dmarc | What it is for: three DKIM records, the MAIL FROM MX and SPF, and DMARC. |
data[].records[].typerequired | one of: CNAME, MX, TXT | |
data[].records[].namerequired | string | The full host name. |
data[].records[].valuerequired | string | What to put in the record’s value (an MX without its priority). |
data[].records[].priority | integer | An MX record’s priority. |
data[].records[].requiredrequired | boolean | False only for DMARC, which is suggested, not needed. |
Errors
| Status | name | When |
|---|---|---|
401 | unauthorized | The API key is missing, wrong or revoked. |
429 | rate_limited | More than 10 requests a second with this key (bursts of 20). Wait for retry-after. |
500 | internal_error | Something failed on our side. |
403 | forbidden | A sending key was used: managing domains takes a full-access key. |
POST/domains
Add a domain
Adds a domain to send from and sets it up with Amazon SES. The answer lists the DNS records to add at your DNS host; Amazon SES verifies the domain once it finds them.
Takes a full-access key.
Body
| Field | Type | Description |
|---|---|---|
namerequired | string | The domain you send from, such as acme.ng. Not mydomainshub.com or its subdomains. |
Answer
| Field | Type | Description |
|---|---|---|
objectrequired | "domain" | |
idrequired | string (uuid) | |
namerequired | string | |
statusrequired | one of: pending, verified, failed, removing | |
setting_uprequired | boolean | True while it is still being set up with Amazon SES. |
created_atrequired | string | ISO 8601, UTC. |
verify_byrequired | string or null | A pending domain only: 72 hours after it was added, the time to verify it by. Null otherwise. |
verified_atrequired | string or null | ISO 8601, UTC; null until it happens. |
last_checked_atrequired | string or null | ISO 8601, UTC; null until it happens. |
failurerequired | object or null | Why it failed, and the record that was missing; null unless failed. |
failure.reasonrequired | string | |
failure.missing_recordrequired | string or null | |
recordsrequired | array of objects | The DNS records to add at your DNS host; empty while it is being set up, and once it has failed. |
records[].recordrequired | one of: dkim, mail_from_mx, mail_from_spf, dmarc | What it is for: three DKIM records, the MAIL FROM MX and SPF, and DMARC. |
records[].typerequired | one of: CNAME, MX, TXT | |
records[].namerequired | string | The full host name. |
records[].valuerequired | string | What to put in the record’s value (an MX without its priority). |
records[].priority | integer | An MX record’s priority. |
records[].requiredrequired | boolean | False only for DMARC, which is suggested, not needed. |
Errors
| Status | name | When |
|---|---|---|
401 | unauthorized | The API key is missing, wrong or revoked. |
429 | rate_limited | More than 10 requests a second with this key (bursts of 20). Wait for retry-after. |
500 | internal_error | Something failed on our side. |
403 | forbidden | A sending key was used, the plan’s domains are all taken, or the account is closed. |
409 | validation_error | The domain is already on this account, or in use on another. |
422 | validation_error | The name is not a domain, or is one of ours. |
GET/domains/{id}
Read a domain
One domain: its status and the DNS records it needs.
Takes a full-access key.
Path
| Field | Type | Description |
|---|---|---|
idrequired | string (uuid) | The domain’s id, from GET /domains. |
Answer
| Field | Type | Description |
|---|---|---|
objectrequired | "domain" | |
idrequired | string (uuid) | |
namerequired | string | |
statusrequired | one of: pending, verified, failed, removing | |
setting_uprequired | boolean | True while it is still being set up with Amazon SES. |
created_atrequired | string | ISO 8601, UTC. |
verify_byrequired | string or null | A pending domain only: 72 hours after it was added, the time to verify it by. Null otherwise. |
verified_atrequired | string or null | ISO 8601, UTC; null until it happens. |
last_checked_atrequired | string or null | ISO 8601, UTC; null until it happens. |
failurerequired | object or null | Why it failed, and the record that was missing; null unless failed. |
failure.reasonrequired | string | |
failure.missing_recordrequired | string or null | |
recordsrequired | array of objects | The DNS records to add at your DNS host; empty while it is being set up, and once it has failed. |
records[].recordrequired | one of: dkim, mail_from_mx, mail_from_spf, dmarc | What it is for: three DKIM records, the MAIL FROM MX and SPF, and DMARC. |
records[].typerequired | one of: CNAME, MX, TXT | |
records[].namerequired | string | The full host name. |
records[].valuerequired | string | What to put in the record’s value (an MX without its priority). |
records[].priority | integer | An MX record’s priority. |
records[].requiredrequired | boolean | False only for DMARC, which is suggested, not needed. |
Errors
| Status | name | When |
|---|---|---|
401 | unauthorized | The API key is missing, wrong or revoked. |
429 | rate_limited | More than 10 requests a second with this key (bursts of 20). Wait for retry-after. |
500 | internal_error | Something failed on our side. |
403 | forbidden | A sending key was used: managing domains takes a full-access key. |
404 | not_found | No domain with that id belongs to this account. |
POST/domains/{id}/verify
Check a domain now
Asks Amazon SES about the domain now, as the dashboard’s “Check now” does, and answers what it found.
Takes a full-access key.
Path
| Field | Type | Description |
|---|---|---|
idrequired | string (uuid) | The domain’s id. |
Answer
| Field | Type | Description |
|---|---|---|
objectrequired | "domain" | |
idrequired | string (uuid) | |
namerequired | string | |
statusrequired | one of: pending, verified, failed, removing | |
setting_uprequired | boolean | True while it is still being set up with Amazon SES. |
created_atrequired | string | ISO 8601, UTC. |
verify_byrequired | string or null | A pending domain only: 72 hours after it was added, the time to verify it by. Null otherwise. |
verified_atrequired | string or null | ISO 8601, UTC; null until it happens. |
last_checked_atrequired | string or null | ISO 8601, UTC; null until it happens. |
failurerequired | object or null | Why it failed, and the record that was missing; null unless failed. |
failure.reasonrequired | string | |
failure.missing_recordrequired | string or null | |
recordsrequired | array of objects | The DNS records to add at your DNS host; empty while it is being set up, and once it has failed. |
records[].recordrequired | one of: dkim, mail_from_mx, mail_from_spf, dmarc | What it is for: three DKIM records, the MAIL FROM MX and SPF, and DMARC. |
records[].typerequired | one of: CNAME, MX, TXT | |
records[].namerequired | string | The full host name. |
records[].valuerequired | string | What to put in the record’s value (an MX without its priority). |
records[].priority | integer | An MX record’s priority. |
records[].requiredrequired | boolean | False only for DMARC, which is suggested, not needed. |
Errors
| Status | name | When |
|---|---|---|
401 | unauthorized | The API key is missing, wrong or revoked. |
429 | rate_limited | More than 10 requests a second with this key (bursts of 20). Wait for retry-after. |
500 | internal_error | Something failed on our side. |
403 | forbidden | A sending key was used: managing domains takes a full-access key. |
404 | not_found | No domain with that id belongs to this account. |
DELETE/domains/{id}
Remove a domain
Removes a domain from the account. Refused while emails from it wait to be sent.
Takes a full-access key.
Path
| Field | Type | Description |
|---|---|---|
idrequired | string (uuid) | The domain’s id. |
Answer
| Field | Type | Description |
|---|---|---|
objectrequired | "domain" | |
idrequired | string (uuid) | |
deletedrequired | true |
Errors
| Status | name | When |
|---|---|---|
401 | unauthorized | The API key is missing, wrong or revoked. |
429 | rate_limited | More than 10 requests a second with this key (bursts of 20). Wait for retry-after. |
500 | internal_error | Something failed on our side. |
403 | forbidden | A sending key was used: managing domains takes a full-access key. |
404 | not_found | No domain with that id belongs to this account. |
409 | validation_error | Emails from it still wait to be sent. |
GET/openapi.json
This API, described
This document: OpenAPI 3.1, generated from the schemas the API validates with.
Takes no key.
Answer
This API’s OpenAPI 3.1 document, as JSON.