Send batch emails
const url = 'https://api.spacepost.dev/emails/batch';const options = { method: 'POST', headers: { 'Idempotency-Key': 'welcome-user-4821', Authorization: 'Bearer <token>', 'Content-Type': 'application/json' }, body: '[{"from":"Acme <hello@acme.com>","to":["a@example.com"],"subject":"Hello A","text":"Hi A"},{"from":"Acme <hello@acme.com>","to":["b@example.com"],"subject":"Hello B","text":"Hi B"}]'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api.spacepost.dev/emails/batch \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --header 'Idempotency-Key: welcome-user-4821' \ --data '[ { "from": "Acme <hello@acme.com>", "to": [ "a@example.com" ], "subject": "Hello A", "text": "Hi A" }, { "from": "Acme <hello@acme.com>", "to": [ "b@example.com" ], "subject": "Hello B", "text": "Hi B" } ]'Sends up to 100 emails in one call. All-or-nothing, if any email is invalid none are sent. Attachments, scheduled_at and a per-email tenant_id are supported; the paused-tenant and tenant-cap errors apply to the whole batch.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Header Parameters
Section titled “Header Parameters”A unique key (1 to 256 characters) that makes the request safe to retry for 24 hours.
Example
welcome-user-4821Request Bodyrequired
Section titled “Request Bodyrequired”Either html or text is required. reply_to is also accepted as replyTo and scheduled_at as scheduledAt.
object
An email address, optionally with a display name: Acme <hello@acme.com>.
An email address, optionally with a display name: Acme <hello@acme.com>.
An email address, optionally with a display name: Acme <hello@acme.com>.
An email address, optionally with a display name: Acme <hello@acme.com>.
An email address, optionally with a display name: Acme <hello@acme.com>.
object
Provide exactly one of content or path.
object
Base64-encoded file content.
A public URL fetched at send time.
Content-ID for inline images (cid:).
object
ISO 8601 date-time or natural language such as “in 1 hour” or “in 2 days”. At most 30 days ahead.
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.
Example
[ { "from": "Acme <hello@acme.com>", "to": [ "a@example.com" ], "subject": "Hello A", "text": "Hi A" }, { "from": "Acme <hello@acme.com>", "to": [ "b@example.com" ], "subject": "Hello B", "text": "Hi B" }]Responses
Section titled “Responses”All emails were accepted, ids are in input order.
object
object
Example
{ "data": [ { "id": "0198a1c2-7b3e-7a41-9d52-5f6c1e0b8a11" }, { "id": "0198a1c2-7b3f-7c02-8e13-2a9d4b7c6e22" } ]}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.
object
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 issending_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’sdaily_limitwas 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 bytenant_id, after a bounce or complaint spike or a manual pause.security_error(451)application_error(500)internal_server_error(500)
Examples
{ "statusCode": 422, "name": "validation_error", "message": "`subject`: Invalid input: expected string, received undefined"}{ "statusCode": 404, "name": "not_found", "message": "Email not found"}{ "statusCode": 401, "name": "missing_api_key", "message": "Missing API key in the authorization header. Include `Authorization: Bearer sp_live_...`."}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.
object
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 issending_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’sdaily_limitwas 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 bytenant_id, after a bounce or complaint spike or a manual pause.security_error(451)application_error(500)internal_server_error(500)
Examples
{ "statusCode": 422, "name": "validation_error", "message": "`subject`: Invalid input: expected string, received undefined"}{ "statusCode": 404, "name": "not_found", "message": "Email not found"}{ "statusCode": 401, "name": "missing_api_key", "message": "Missing API key in the authorization header. Include `Authorization: Bearer sp_live_...`."}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.
object
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 issending_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’sdaily_limitwas 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 bytenant_id, after a bounce or complaint spike or a manual pause.security_error(451)application_error(500)internal_server_error(500)
Examples
{ "statusCode": 422, "name": "validation_error", "message": "`subject`: Invalid input: expected string, received undefined"}{ "statusCode": 404, "name": "not_found", "message": "Email not found"}{ "statusCode": 401, "name": "missing_api_key", "message": "Missing API key in the authorization header. Include `Authorization: Bearer sp_live_...`."}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.
object
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 issending_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’sdaily_limitwas 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 bytenant_id, after a bounce or complaint spike or a manual pause.security_error(451)application_error(500)internal_server_error(500)
Examples
{ "statusCode": 422, "name": "validation_error", "message": "`subject`: Invalid input: expected string, received undefined"}{ "statusCode": 404, "name": "not_found", "message": "Email not found"}{ "statusCode": 401, "name": "missing_api_key", "message": "Missing API key in the authorization header. Include `Authorization: Bearer sp_live_...`."}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.
object
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 issending_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’sdaily_limitwas 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 bytenant_id, after a bounce or complaint spike or a manual pause.security_error(451)application_error(500)internal_server_error(500)
Examples
{ "statusCode": 422, "name": "validation_error", "message": "`subject`: Invalid input: expected string, received undefined"}{ "statusCode": 404, "name": "not_found", "message": "Email not found"}{ "statusCode": 401, "name": "missing_api_key", "message": "Missing API key in the authorization header. Include `Authorization: Bearer sp_live_...`."}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).
object
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 issending_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’sdaily_limitwas 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 bytenant_id, after a bounce or complaint spike or a manual pause.security_error(451)application_error(500)internal_server_error(500)
Example
{ "statusCode": 429, "name": "rate_limit_exceeded", "message": "Too many requests. You can only make 10 requests per second."}Headers
Section titled “Headers”Seconds to wait before retrying.
Requests allowed per second for your team.
Requests left in the current one-second window.
Seconds until the window resets.