Skip to content

Send an email

POST
/emails
curl --request POST \
--url https://api.spacepost.dev/emails \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: welcome-user-4821' \
--data '{ "from": "Acme <onboarding@acme.com>", "to": [ "delivered@test.spacepost.dev" ], "subject": "Welcome to Acme", "html": "<p>Thanks for signing up!</p>" }'

Validates and queues one email. Each recipient counts towards your quota. Use scheduled_at to send later (up to 30 days ahead). Pass tenant_id to send on behalf of a tenant (not needed when the from domain belongs to one). Fails with 422 if tenant_id conflicts with the domain’s tenant, 403 sending_paused if the tenant is paused and 429 daily_quota_exceeded if it reached its daily cap.

Idempotency-Key
string
>= 1 characters <= 256 characters

A unique key (1 to 256 characters) that makes the request safe to retry for 24 hours.

Example

welcome-user-4821
Media typeapplication/json

Either html or text is required. reply_to is also accepted as replyTo and scheduled_at as scheduledAt.

object
from
required

An email address, optionally with a display name: Acme <hello@acme.com>.

string
to
required
One of:

An email address, optionally with a display name: Acme <hello@acme.com>.

string
subject
required
string
>= 1 characters <= 998 characters
cc
One of:

An email address, optionally with a display name: Acme <hello@acme.com>.

string
bcc
One of:

An email address, optionally with a display name: Acme <hello@acme.com>.

string
reply_to
One of:

An email address, optionally with a display name: Acme <hello@acme.com>.

string
html
string
text
string
headers
object
key
additional properties
string
attachments
Array<object>
<= 50 items

Provide exactly one of content or path.

object
filename
required
string
<= 255 characters
content

Base64-encoded file content.

string
path

A public URL fetched at send time.

string format: uri
content_type
string
content_id

Content-ID for inline images (cid:).

string
tags
Array<object>
<= 50 items
object
name
required
string
<= 256 characters /^[A-Za-z0-9_-]+$/
value
required
string
<= 256 characters /^[A-Za-z0-9_-]+$/
scheduled_at

ISO 8601 date-time or natural language such as “in 1 hour” or “in 2 days”. At most 30 days ahead.

string
tenant_id

Platform mode. Our tenant id or your external_id. Optional when the from domain belongs to a tenant; a conflict with the domain’s tenant is a 422.

string
>= 1 characters <= 200 characters

Examples

HTML email

{
"from": "Acme <onboarding@acme.com>",
"to": [
"delivered@test.spacepost.dev"
],
"subject": "Welcome to Acme",
"html": "<p>Thanks for signing up!</p>"
}

The email was accepted.

Media typeapplication/json
object
id
required
string format: uuid

Example

{
"id": "0198a1c2-7b3e-7a41-9d52-5f6c1e0b8a11"
}
ratelimit-limit
integer

Requests allowed per second for your team.

ratelimit-remaining
integer

Requests left in the current one-second window.

ratelimit-reset
integer

Seconds until the window resets.

An error. Common statuses: 400 invalid_idempotency_key; 401 missing_api_key or restricted_api_key; 403 invalid_api_key, invalid_from_address, sending_paused (team or tenant) or invalid_access; 404 not_found; 409 invalid_idempotent_request or concurrent_idempotent_requests; 422 validation_error (also: tenant_id conflicts with the domain’s tenant; deleting a tenant that still has domains); 429 quota errors.

Media typeapplication/json
object
statusCode
required
integer
name
required

Machine-readable error name.

  • missing_api_key (401): no bearer token.
  • invalid_api_key (403): unknown or malformed key.
  • restricted_api_key (401): the key is sending_access (or limited to another domain).
  • validation_error (422): invalid request. Also used with 403 for plan limits and test-domain restrictions.
  • not_found (404): the resource does not exist or belongs to another team.
  • method_not_allowed (405)
  • invalid_idempotency_key (400): key length outside 1 to 256.
  • concurrent_idempotent_requests (409): the original request is still running.
  • invalid_idempotent_request (409): the key was used with a different payload.
  • rate_limit_exceeded (429)
  • daily_quota_exceeded (429): the sandbox, daily limit or a tenant’s daily_limit was reached.
  • monthly_quota_exceeded (429): the plan’s monthly limit was reached (Free plan).
  • invalid_from_address (403): the sender domain is not verified.
  • invalid_access (422; 403 when a team that is not trusted tries to unpause a tenant paused for its bounce or complaint rate)
  • invalid_parameter (422)
  • sending_paused (403): sending is paused for the team, or for the tenant named by tenant_id, after a bounce or complaint spike or a manual pause.
  • security_error (451)
  • application_error (500)
  • internal_server_error (500)
string
Allowed values: missing_api_key invalid_api_key restricted_api_key validation_error not_found method_not_allowed invalid_idempotency_key concurrent_idempotent_requests invalid_idempotent_request rate_limit_exceeded daily_quota_exceeded monthly_quota_exceeded invalid_from_address invalid_access invalid_parameter sending_paused security_error application_error internal_server_error
message
required
string

Examples

{
"statusCode": 422,
"name": "validation_error",
"message": "`subject`: Invalid input: expected string, received undefined"
}

An error. Common statuses: 400 invalid_idempotency_key; 401 missing_api_key or restricted_api_key; 403 invalid_api_key, invalid_from_address, sending_paused (team or tenant) or invalid_access; 404 not_found; 409 invalid_idempotent_request or concurrent_idempotent_requests; 422 validation_error (also: tenant_id conflicts with the domain’s tenant; deleting a tenant that still has domains); 429 quota errors.

Media typeapplication/json
object
statusCode
required
integer
name
required

Machine-readable error name.

  • missing_api_key (401): no bearer token.
  • invalid_api_key (403): unknown or malformed key.
  • restricted_api_key (401): the key is sending_access (or limited to another domain).
  • validation_error (422): invalid request. Also used with 403 for plan limits and test-domain restrictions.
  • not_found (404): the resource does not exist or belongs to another team.
  • method_not_allowed (405)
  • invalid_idempotency_key (400): key length outside 1 to 256.
  • concurrent_idempotent_requests (409): the original request is still running.
  • invalid_idempotent_request (409): the key was used with a different payload.
  • rate_limit_exceeded (429)
  • daily_quota_exceeded (429): the sandbox, daily limit or a tenant’s daily_limit was reached.
  • monthly_quota_exceeded (429): the plan’s monthly limit was reached (Free plan).
  • invalid_from_address (403): the sender domain is not verified.
  • invalid_access (422; 403 when a team that is not trusted tries to unpause a tenant paused for its bounce or complaint rate)
  • invalid_parameter (422)
  • sending_paused (403): sending is paused for the team, or for the tenant named by tenant_id, after a bounce or complaint spike or a manual pause.
  • security_error (451)
  • application_error (500)
  • internal_server_error (500)
string
Allowed values: missing_api_key invalid_api_key restricted_api_key validation_error not_found method_not_allowed invalid_idempotency_key concurrent_idempotent_requests invalid_idempotent_request rate_limit_exceeded daily_quota_exceeded monthly_quota_exceeded invalid_from_address invalid_access invalid_parameter sending_paused security_error application_error internal_server_error
message
required
string

Examples

{
"statusCode": 422,
"name": "validation_error",
"message": "`subject`: Invalid input: expected string, received undefined"
}

An error. Common statuses: 400 invalid_idempotency_key; 401 missing_api_key or restricted_api_key; 403 invalid_api_key, invalid_from_address, sending_paused (team or tenant) or invalid_access; 404 not_found; 409 invalid_idempotent_request or concurrent_idempotent_requests; 422 validation_error (also: tenant_id conflicts with the domain’s tenant; deleting a tenant that still has domains); 429 quota errors.

Media typeapplication/json
object
statusCode
required
integer
name
required

Machine-readable error name.

  • missing_api_key (401): no bearer token.
  • invalid_api_key (403): unknown or malformed key.
  • restricted_api_key (401): the key is sending_access (or limited to another domain).
  • validation_error (422): invalid request. Also used with 403 for plan limits and test-domain restrictions.
  • not_found (404): the resource does not exist or belongs to another team.
  • method_not_allowed (405)
  • invalid_idempotency_key (400): key length outside 1 to 256.
  • concurrent_idempotent_requests (409): the original request is still running.
  • invalid_idempotent_request (409): the key was used with a different payload.
  • rate_limit_exceeded (429)
  • daily_quota_exceeded (429): the sandbox, daily limit or a tenant’s daily_limit was reached.
  • monthly_quota_exceeded (429): the plan’s monthly limit was reached (Free plan).
  • invalid_from_address (403): the sender domain is not verified.
  • invalid_access (422; 403 when a team that is not trusted tries to unpause a tenant paused for its bounce or complaint rate)
  • invalid_parameter (422)
  • sending_paused (403): sending is paused for the team, or for the tenant named by tenant_id, after a bounce or complaint spike or a manual pause.
  • security_error (451)
  • application_error (500)
  • internal_server_error (500)
string
Allowed values: missing_api_key invalid_api_key restricted_api_key validation_error not_found method_not_allowed invalid_idempotency_key concurrent_idempotent_requests invalid_idempotent_request rate_limit_exceeded daily_quota_exceeded monthly_quota_exceeded invalid_from_address invalid_access invalid_parameter sending_paused security_error application_error internal_server_error
message
required
string

Examples

{
"statusCode": 422,
"name": "validation_error",
"message": "`subject`: Invalid input: expected string, received undefined"
}

An error. Common statuses: 400 invalid_idempotency_key; 401 missing_api_key or restricted_api_key; 403 invalid_api_key, invalid_from_address, sending_paused (team or tenant) or invalid_access; 404 not_found; 409 invalid_idempotent_request or concurrent_idempotent_requests; 422 validation_error (also: tenant_id conflicts with the domain’s tenant; deleting a tenant that still has domains); 429 quota errors.

Media typeapplication/json
object
statusCode
required
integer
name
required

Machine-readable error name.

  • missing_api_key (401): no bearer token.
  • invalid_api_key (403): unknown or malformed key.
  • restricted_api_key (401): the key is sending_access (or limited to another domain).
  • validation_error (422): invalid request. Also used with 403 for plan limits and test-domain restrictions.
  • not_found (404): the resource does not exist or belongs to another team.
  • method_not_allowed (405)
  • invalid_idempotency_key (400): key length outside 1 to 256.
  • concurrent_idempotent_requests (409): the original request is still running.
  • invalid_idempotent_request (409): the key was used with a different payload.
  • rate_limit_exceeded (429)
  • daily_quota_exceeded (429): the sandbox, daily limit or a tenant’s daily_limit was reached.
  • monthly_quota_exceeded (429): the plan’s monthly limit was reached (Free plan).
  • invalid_from_address (403): the sender domain is not verified.
  • invalid_access (422; 403 when a team that is not trusted tries to unpause a tenant paused for its bounce or complaint rate)
  • invalid_parameter (422)
  • sending_paused (403): sending is paused for the team, or for the tenant named by tenant_id, after a bounce or complaint spike or a manual pause.
  • security_error (451)
  • application_error (500)
  • internal_server_error (500)
string
Allowed values: missing_api_key invalid_api_key restricted_api_key validation_error not_found method_not_allowed invalid_idempotency_key concurrent_idempotent_requests invalid_idempotent_request rate_limit_exceeded daily_quota_exceeded monthly_quota_exceeded invalid_from_address invalid_access invalid_parameter sending_paused security_error application_error internal_server_error
message
required
string

Examples

{
"statusCode": 422,
"name": "validation_error",
"message": "`subject`: Invalid input: expected string, received undefined"
}

An error. Common statuses: 400 invalid_idempotency_key; 401 missing_api_key or restricted_api_key; 403 invalid_api_key, invalid_from_address, sending_paused (team or tenant) or invalid_access; 404 not_found; 409 invalid_idempotent_request or concurrent_idempotent_requests; 422 validation_error (also: tenant_id conflicts with the domain’s tenant; deleting a tenant that still has domains); 429 quota errors.

Media typeapplication/json
object
statusCode
required
integer
name
required

Machine-readable error name.

  • missing_api_key (401): no bearer token.
  • invalid_api_key (403): unknown or malformed key.
  • restricted_api_key (401): the key is sending_access (or limited to another domain).
  • validation_error (422): invalid request. Also used with 403 for plan limits and test-domain restrictions.
  • not_found (404): the resource does not exist or belongs to another team.
  • method_not_allowed (405)
  • invalid_idempotency_key (400): key length outside 1 to 256.
  • concurrent_idempotent_requests (409): the original request is still running.
  • invalid_idempotent_request (409): the key was used with a different payload.
  • rate_limit_exceeded (429)
  • daily_quota_exceeded (429): the sandbox, daily limit or a tenant’s daily_limit was reached.
  • monthly_quota_exceeded (429): the plan’s monthly limit was reached (Free plan).
  • invalid_from_address (403): the sender domain is not verified.
  • invalid_access (422; 403 when a team that is not trusted tries to unpause a tenant paused for its bounce or complaint rate)
  • invalid_parameter (422)
  • sending_paused (403): sending is paused for the team, or for the tenant named by tenant_id, after a bounce or complaint spike or a manual pause.
  • security_error (451)
  • application_error (500)
  • internal_server_error (500)
string
Allowed values: missing_api_key invalid_api_key restricted_api_key validation_error not_found method_not_allowed invalid_idempotency_key concurrent_idempotent_requests invalid_idempotent_request rate_limit_exceeded daily_quota_exceeded monthly_quota_exceeded invalid_from_address invalid_access invalid_parameter sending_paused security_error application_error internal_server_error
message
required
string

Examples

{
"statusCode": 422,
"name": "validation_error",
"message": "`subject`: Invalid input: expected string, received undefined"
}

Too many requests (rate_limit_exceeded), or a daily or monthly sending quota was reached (daily_quota_exceeded also means a tenant’s daily_limit).

Media typeapplication/json
object
statusCode
required
integer
name
required

Machine-readable error name.

  • missing_api_key (401): no bearer token.
  • invalid_api_key (403): unknown or malformed key.
  • restricted_api_key (401): the key is sending_access (or limited to another domain).
  • validation_error (422): invalid request. Also used with 403 for plan limits and test-domain restrictions.
  • not_found (404): the resource does not exist or belongs to another team.
  • method_not_allowed (405)
  • invalid_idempotency_key (400): key length outside 1 to 256.
  • concurrent_idempotent_requests (409): the original request is still running.
  • invalid_idempotent_request (409): the key was used with a different payload.
  • rate_limit_exceeded (429)
  • daily_quota_exceeded (429): the sandbox, daily limit or a tenant’s daily_limit was reached.
  • monthly_quota_exceeded (429): the plan’s monthly limit was reached (Free plan).
  • invalid_from_address (403): the sender domain is not verified.
  • invalid_access (422; 403 when a team that is not trusted tries to unpause a tenant paused for its bounce or complaint rate)
  • invalid_parameter (422)
  • sending_paused (403): sending is paused for the team, or for the tenant named by tenant_id, after a bounce or complaint spike or a manual pause.
  • security_error (451)
  • application_error (500)
  • internal_server_error (500)
string
Allowed values: missing_api_key invalid_api_key restricted_api_key validation_error not_found method_not_allowed invalid_idempotency_key concurrent_idempotent_requests invalid_idempotent_request rate_limit_exceeded daily_quota_exceeded monthly_quota_exceeded invalid_from_address invalid_access invalid_parameter sending_paused security_error application_error internal_server_error
message
required
string

Example

{
"statusCode": 429,
"name": "rate_limit_exceeded",
"message": "Too many requests. You can only make 10 requests per second."
}
retry-after
integer

Seconds to wait before retrying.

ratelimit-limit
integer

Requests allowed per second for your team.

ratelimit-remaining
integer

Requests left in the current one-second window.

ratelimit-reset
integer

Seconds until the window resets.