Skip to content
Docs

API reference

Every endpoint, generated from the same schemas the API checks requests with. The same description, as OpenAPI 3.1: /api/v1/openapi.json.

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

FieldTypeDescription
Idempotency-Keystring, 1 to 256 printable ASCII charactersThe same key and body within 24 hours answers the first answer again and queues nothing more. See Idempotency.

Body

FieldTypeDescription
fromrequiredstringThe sender: "Name <address>" or a bare address, at a domain verified on your account.
torequiredstring or array of stringsOne address or a list. To, cc and bcc together hold at most 50 recipients, each once.
ccstring or array of stringsOne address or a list.
bccstring or array of stringsOne address or a list. Never shown in the message’s headers.
reply_tostring or array of stringsOne address or a list, for the Reply-To header.
subjectrequiredstringOne line, 1 to 998 characters.
htmlstringThe HTML body. Give html, text or both.
textstringThe plain-text body. Give html, text or both.
headersobject of stringsExtra headers: X-* (not X-SES-*), List-Unsubscribe, List-Unsubscribe-Post, List-Id, In-Reply-To, References and Auto-Submitted. At most 20.
attachmentsarray of objectsUp to 20 files, each base64 in `content`. The whole request stays under 4 MB. Executable file types are refused.
attachments[].filenamerequiredstring
attachments[].contentrequiredstring
attachments[].content_typestring
tagsarray of objectsUp to 10 name and value pairs (letters, digits, _ and -), each name once, for finding the email later.
tags[].namerequiredstring
tags[].valuerequiredstring
scheduled_atstring (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

FieldTypeDescription
idrequiredstring (uuid)The email’s id: GET /emails/{id} reads it back.

Errors

StatusnameWhen
401unauthorizedThe API key is missing, wrong or revoked.
429rate_limitedMore than 10 requests a second with this key (bursts of 20). Wait for retry-after.
500internal_errorSomething failed on our side.
403forbidden, domain_not_verified, account_pausedThe from domain is not verified on this account, the key is limited to another domain, the sandbox refuses the recipient, or sending is paused.
409validation_errorThe Idempotency-Key was used for a different request in the last 24 hours.
413validation_errorThe request is larger than 4 MB.
422validation_errorThe 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.
429rate_limited, quota_exceededToo 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

FieldTypeDescription
Idempotency-Keystring, 1 to 256 printable ASCII charactersThe 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

FieldTypeDescription
datarequiredarray of objectsOne id per email, in the order they were sent.
data[].idrequiredstring (uuid)The email’s id: GET /emails/{id} reads it back.

Errors

StatusnameWhen
401unauthorizedThe API key is missing, wrong or revoked.
429rate_limitedMore than 10 requests a second with this key (bursts of 20). Wait for retry-after.
500internal_errorSomething failed on our side.
403forbidden, domain_not_verified, account_pausedThe from domain is not verified on this account, the key is limited to another domain, the sandbox refuses the recipient, or sending is paused.
409validation_errorThe Idempotency-Key was used for a different request in the last 24 hours.
413validation_errorThe request is larger than 4 MB.
422validation_errorThe 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.
429rate_limited, quota_exceededToo 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

FieldTypeDescription
limitintegerHow many to answer, 1 to 100. 20 unless given.
cursorstringThe `next_cursor` of the page before, as it was given, for the next (older) page.
statusone of: queued, sending, sent, delivered, bounced, complained, failed, suppressed, canceledOnly emails with this status.
tostring (email address)Only emails to exactly this address, in to, cc or bcc.
tagstringOnly emails with this tag name, or this name:value pair.
subjectstringOnly emails whose subject contains this text, in any case.
created_afterstring (ISO 8601 date and time)Only emails queued at or after this moment (ISO 8601 with its zone).
created_beforestring (ISO 8601 date and time)Only emails queued before this moment (ISO 8601 with its zone).

Answer

FieldTypeDescription
objectrequired"list"
datarequiredarray of objects
data[].objectrequired"email"
data[].idrequiredstring (uuid)
data[].fromrequiredstring
data[].torequiredarray of strings
data[].ccrequiredarray of strings
data[].bccrequiredarray of strings
data[].reply_torequiredarray of strings
data[].subjectrequiredstring
data[].tagsrequiredarray of objects
data[].tags[].namerequiredstring
data[].tags[].valuerequiredstring
data[].statusrequiredone of: queued, sending, sent, delivered, bounced, complained, failed, suppressed, canceled
data[].status_reasonrequiredstring or nullWhy it failed, was suppressed or canceled, as a short code; otherwise null.
data[].created_atrequiredstringWhen it was queued.
data[].scheduled_atrequiredstringWhen it may be sent: the moment it was queued, unless scheduled.
data[].sent_atrequiredstring or nullISO 8601, UTC; null until it happens.
data[].delivered_atrequiredstring or nullISO 8601, UTC; null until it happens.
data[].bounced_atrequiredstring or nullISO 8601, UTC; null until it happens.
data[].complained_atrequiredstring or nullISO 8601, UTC; null until it happens.
data[].failed_atrequiredstring or nullISO 8601, UTC; null until it happens.
data[].canceled_atrequiredstring or nullISO 8601, UTC; null until it happens.
data[].last_eventrequiredone of: send, delivery, bounce, complaint, reject, delivery_delay, rendering_failure or nullThe latest event Amazon SES reported.
data[].last_event_atrequiredstring or nullISO 8601, UTC; null until it happens.
has_morerequiredboolean
next_cursorrequiredstring or nullPass as `cursor` for the next page; null on the last page.

Errors

StatusnameWhen
401unauthorizedThe API key is missing, wrong or revoked.
429rate_limitedMore than 10 requests a second with this key (bursts of 20). Wait for retry-after.
500internal_errorSomething failed on our side.
403forbiddenA sending key was used: this takes a full-access key.
422validation_errorA 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

FieldTypeDescription
idrequiredstring (uuid)The email’s id, as POST /emails answered it.

Answer

FieldTypeDescription
objectrequired"email"
idrequiredstring (uuid)
fromrequiredstring
torequiredarray of strings
ccrequiredarray of strings
bccrequiredarray of strings
reply_torequiredarray of strings
subjectrequiredstring
tagsrequiredarray of objects
tags[].namerequiredstring
tags[].valuerequiredstring
statusrequiredone of: queued, sending, sent, delivered, bounced, complained, failed, suppressed, canceled
status_reasonrequiredstring or nullWhy it failed, was suppressed or canceled, as a short code; otherwise null.
created_atrequiredstringWhen it was queued.
scheduled_atrequiredstringWhen it may be sent: the moment it was queued, unless scheduled.
sent_atrequiredstring or nullISO 8601, UTC; null until it happens.
delivered_atrequiredstring or nullISO 8601, UTC; null until it happens.
bounced_atrequiredstring or nullISO 8601, UTC; null until it happens.
complained_atrequiredstring or nullISO 8601, UTC; null until it happens.
failed_atrequiredstring or nullISO 8601, UTC; null until it happens.
canceled_atrequiredstring or nullISO 8601, UTC; null until it happens.
last_eventrequiredone of: send, delivery, bounce, complaint, reject, delivery_delay, rendering_failure or nullThe latest event Amazon SES reported.
last_event_atrequiredstring or nullISO 8601, UTC; null until it happens.

Errors

StatusnameWhen
401unauthorizedThe API key is missing, wrong or revoked.
429rate_limitedMore than 10 requests a second with this key (bursts of 20). Wait for retry-after.
500internal_errorSomething failed on our side.
403forbiddenA sending key was used: this takes a full-access key.
404not_foundNo 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

FieldTypeDescription
idrequiredstring (uuid)The email’s id.

Body

FieldTypeDescription
scheduled_atrequiredstring (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

FieldTypeDescription
objectrequired"email"
idrequiredstring (uuid)
statusrequiredone of: queued, sending, sent, delivered, bounced, complained, failed, suppressed, canceled
scheduled_atrequiredstringISO 8601, UTC.

Errors

StatusnameWhen
401unauthorizedThe API key is missing, wrong or revoked.
429rate_limitedMore than 10 requests a second with this key (bursts of 20). Wait for retry-after.
500internal_errorSomething failed on our side.
403forbiddenA sending key was used: this takes a full-access key.
404not_foundNo email with that id belongs to this account.
409validation_errorThe email has already left the queue (or is being sent).
422validation_errorscheduled_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

FieldTypeDescription
idrequiredstring (uuid)The email’s id.

Answer

FieldTypeDescription
objectrequired"email"
idrequiredstring (uuid)
statusrequiredone of: queued, sending, sent, delivered, bounced, complained, failed, suppressed, canceled
scheduled_atrequiredstringISO 8601, UTC.

Errors

StatusnameWhen
401unauthorizedThe API key is missing, wrong or revoked.
429rate_limitedMore than 10 requests a second with this key (bursts of 20). Wait for retry-after.
500internal_errorSomething failed on our side.
403forbiddenA sending key was used: this takes a full-access key.
404not_foundNo email with that id belongs to this account.
409validation_errorThe 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

FieldTypeDescription
objectrequired"list"
datarequiredarray of objectsThe account’s keys that are not revoked, newest first.
data[].objectrequired"api_key"
data[].idrequiredstring (uuid)
data[].namerequiredstring
data[].prefixrequiredstringThe key’s first characters, to tell it apart. Never the key.
data[].permissionrequiredone of: full, sending
data[].domain_idrequiredstring (uuid) or nullThe one domain a sending key is limited to, or null.
data[].created_atrequiredstringISO 8601, UTC.
data[].last_used_atrequiredstring or nullISO 8601, UTC: moved at most once a minute; null if never used.

Errors

StatusnameWhen
401unauthorizedThe API key is missing, wrong or revoked.
429rate_limitedMore than 10 requests a second with this key (bursts of 20). Wait for retry-after.
500internal_errorSomething failed on our side.
403forbiddenA 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

FieldTypeDescription
namerequiredstringWhat the key is for, 1 to 60 characters, so you can tell keys apart.
permissionrequiredone of: full, sending`sending`: may only send email. `full`: may also read emails, change scheduled ones, and manage keys.
domain_idstring (uuid)A sending key only: limit it to sending from this one domain of your account.

Answer

FieldTypeDescription
objectrequired"api_key"
idrequiredstring (uuid)
namerequiredstring
prefixrequiredstringThe key’s first characters, to tell it apart. Never the key.
permissionrequiredone of: full, sending
domain_idrequiredstring (uuid) or nullThe one domain a sending key is limited to, or null.
created_atrequiredstringISO 8601, UTC.
last_used_atrequiredstring or nullISO 8601, UTC: moved at most once a minute; null if never used.
keyrequiredstringThe key itself. Shown in this answer only: we keep a hash, and cannot show it again.

Errors

StatusnameWhen
401unauthorizedThe API key is missing, wrong or revoked.
429rate_limitedMore than 10 requests a second with this key (bursts of 20). Wait for retry-after.
500internal_errorSomething failed on our side.
403forbiddenA sending key was used, or the account is closed.
422validation_errorThe 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

FieldTypeDescription
idrequiredstring (uuid)The key’s id, from GET /api-keys.

Answer

FieldTypeDescription
objectrequired"api_key"
idrequiredstring (uuid)
revokedrequiredtrue

Errors

StatusnameWhen
401unauthorizedThe API key is missing, wrong or revoked.
429rate_limitedMore than 10 requests a second with this key (bursts of 20). Wait for retry-after.
500internal_errorSomething failed on our side.
403forbiddenA sending key was used: this takes a full-access key.
404not_foundNo 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

FieldTypeDescription
objectrequired"list"
datarequiredarray of objects
data[].objectrequired"domain"
data[].idrequiredstring (uuid)
data[].namerequiredstring
data[].statusrequiredone of: pending, verified, failed, removing
data[].setting_uprequiredbooleanTrue while it is still being set up with Amazon SES.
data[].created_atrequiredstringISO 8601, UTC.
data[].verify_byrequiredstring or nullA pending domain only: 72 hours after it was added, the time to verify it by. Null otherwise.
data[].verified_atrequiredstring or nullISO 8601, UTC; null until it happens.
data[].last_checked_atrequiredstring or nullISO 8601, UTC; null until it happens.
data[].failurerequiredobject or nullWhy it failed, and the record that was missing; null unless failed.
data[].failure.reasonrequiredstring
data[].failure.missing_recordrequiredstring or null
data[].recordsrequiredarray of objectsThe DNS records to add at your DNS host; empty while it is being set up, and once it has failed.
data[].records[].recordrequiredone of: dkim, mail_from_mx, mail_from_spf, dmarcWhat it is for: three DKIM records, the MAIL FROM MX and SPF, and DMARC.
data[].records[].typerequiredone of: CNAME, MX, TXT
data[].records[].namerequiredstringThe full host name.
data[].records[].valuerequiredstringWhat to put in the record’s value (an MX without its priority).
data[].records[].priorityintegerAn MX record’s priority.
data[].records[].requiredrequiredbooleanFalse only for DMARC, which is suggested, not needed.

Errors

StatusnameWhen
401unauthorizedThe API key is missing, wrong or revoked.
429rate_limitedMore than 10 requests a second with this key (bursts of 20). Wait for retry-after.
500internal_errorSomething failed on our side.
403forbiddenA 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

FieldTypeDescription
namerequiredstringThe domain you send from, such as acme.ng. Not mydomainshub.com or its subdomains.

Answer

FieldTypeDescription
objectrequired"domain"
idrequiredstring (uuid)
namerequiredstring
statusrequiredone of: pending, verified, failed, removing
setting_uprequiredbooleanTrue while it is still being set up with Amazon SES.
created_atrequiredstringISO 8601, UTC.
verify_byrequiredstring or nullA pending domain only: 72 hours after it was added, the time to verify it by. Null otherwise.
verified_atrequiredstring or nullISO 8601, UTC; null until it happens.
last_checked_atrequiredstring or nullISO 8601, UTC; null until it happens.
failurerequiredobject or nullWhy it failed, and the record that was missing; null unless failed.
failure.reasonrequiredstring
failure.missing_recordrequiredstring or null
recordsrequiredarray of objectsThe DNS records to add at your DNS host; empty while it is being set up, and once it has failed.
records[].recordrequiredone of: dkim, mail_from_mx, mail_from_spf, dmarcWhat it is for: three DKIM records, the MAIL FROM MX and SPF, and DMARC.
records[].typerequiredone of: CNAME, MX, TXT
records[].namerequiredstringThe full host name.
records[].valuerequiredstringWhat to put in the record’s value (an MX without its priority).
records[].priorityintegerAn MX record’s priority.
records[].requiredrequiredbooleanFalse only for DMARC, which is suggested, not needed.

Errors

StatusnameWhen
401unauthorizedThe API key is missing, wrong or revoked.
429rate_limitedMore than 10 requests a second with this key (bursts of 20). Wait for retry-after.
500internal_errorSomething failed on our side.
403forbiddenA sending key was used, the plan’s domains are all taken, or the account is closed.
409validation_errorThe domain is already on this account, or in use on another.
422validation_errorThe 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

FieldTypeDescription
idrequiredstring (uuid)The domain’s id, from GET /domains.

Answer

FieldTypeDescription
objectrequired"domain"
idrequiredstring (uuid)
namerequiredstring
statusrequiredone of: pending, verified, failed, removing
setting_uprequiredbooleanTrue while it is still being set up with Amazon SES.
created_atrequiredstringISO 8601, UTC.
verify_byrequiredstring or nullA pending domain only: 72 hours after it was added, the time to verify it by. Null otherwise.
verified_atrequiredstring or nullISO 8601, UTC; null until it happens.
last_checked_atrequiredstring or nullISO 8601, UTC; null until it happens.
failurerequiredobject or nullWhy it failed, and the record that was missing; null unless failed.
failure.reasonrequiredstring
failure.missing_recordrequiredstring or null
recordsrequiredarray of objectsThe DNS records to add at your DNS host; empty while it is being set up, and once it has failed.
records[].recordrequiredone of: dkim, mail_from_mx, mail_from_spf, dmarcWhat it is for: three DKIM records, the MAIL FROM MX and SPF, and DMARC.
records[].typerequiredone of: CNAME, MX, TXT
records[].namerequiredstringThe full host name.
records[].valuerequiredstringWhat to put in the record’s value (an MX without its priority).
records[].priorityintegerAn MX record’s priority.
records[].requiredrequiredbooleanFalse only for DMARC, which is suggested, not needed.

Errors

StatusnameWhen
401unauthorizedThe API key is missing, wrong or revoked.
429rate_limitedMore than 10 requests a second with this key (bursts of 20). Wait for retry-after.
500internal_errorSomething failed on our side.
403forbiddenA sending key was used: managing domains takes a full-access key.
404not_foundNo 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

FieldTypeDescription
idrequiredstring (uuid)The domain’s id.

Answer

FieldTypeDescription
objectrequired"domain"
idrequiredstring (uuid)
namerequiredstring
statusrequiredone of: pending, verified, failed, removing
setting_uprequiredbooleanTrue while it is still being set up with Amazon SES.
created_atrequiredstringISO 8601, UTC.
verify_byrequiredstring or nullA pending domain only: 72 hours after it was added, the time to verify it by. Null otherwise.
verified_atrequiredstring or nullISO 8601, UTC; null until it happens.
last_checked_atrequiredstring or nullISO 8601, UTC; null until it happens.
failurerequiredobject or nullWhy it failed, and the record that was missing; null unless failed.
failure.reasonrequiredstring
failure.missing_recordrequiredstring or null
recordsrequiredarray of objectsThe DNS records to add at your DNS host; empty while it is being set up, and once it has failed.
records[].recordrequiredone of: dkim, mail_from_mx, mail_from_spf, dmarcWhat it is for: three DKIM records, the MAIL FROM MX and SPF, and DMARC.
records[].typerequiredone of: CNAME, MX, TXT
records[].namerequiredstringThe full host name.
records[].valuerequiredstringWhat to put in the record’s value (an MX without its priority).
records[].priorityintegerAn MX record’s priority.
records[].requiredrequiredbooleanFalse only for DMARC, which is suggested, not needed.

Errors

StatusnameWhen
401unauthorizedThe API key is missing, wrong or revoked.
429rate_limitedMore than 10 requests a second with this key (bursts of 20). Wait for retry-after.
500internal_errorSomething failed on our side.
403forbiddenA sending key was used: managing domains takes a full-access key.
404not_foundNo 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

FieldTypeDescription
idrequiredstring (uuid)The domain’s id.

Answer

FieldTypeDescription
objectrequired"domain"
idrequiredstring (uuid)
deletedrequiredtrue

Errors

StatusnameWhen
401unauthorizedThe API key is missing, wrong or revoked.
429rate_limitedMore than 10 requests a second with this key (bursts of 20). Wait for retry-after.
500internal_errorSomething failed on our side.
403forbiddenA sending key was used: managing domains takes a full-access key.
404not_foundNo domain with that id belongs to this account.
409validation_errorEmails 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.