Send an email
const url = 'https://api.connect.ms/v2/email';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"sender":"hello@example.com","recipient":"hello@example.com","subject":"example","content":{"html":"example","text":"example"},"template":{"name":"example","data":{"additionalProperty":"example"}},"format":"html","kind":"transactional","clientReference":"example","clientTag":"example","scheduledAt":"2026-04-15T12:00:00Z","trackOpens":true,"bypassSuppressions":true,"attachments":[{"filename":"example","contentType":"example","content":"example"}]}'};
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.connect.ms/v2/email \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "sender": "hello@example.com", "recipient": "hello@example.com", "subject": "example", "content": { "html": "example", "text": "example" }, "template": { "name": "example", "data": { "additionalProperty": "example" } }, "format": "html", "kind": "transactional", "clientReference": "example", "clientTag": "example", "scheduledAt": "2026-04-15T12:00:00Z", "trackOpens": true, "bypassSuppressions": true, "attachments": [ { "filename": "example", "contentType": "example", "content": "example" } ] }'Sends one email now or at scheduledAt, with the body given directly or rendered from a stored template. The response is the email with its current status; later changes are reported by email.* events and webhooks.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Header Parameters
Section titled “Header Parameters”The API version to use, for example 2026-10-01. Defaults to the version set on your API key.
A unique value of up to 255 characters, so a retried request is not acted on twice. Required for keys in Strict API Mode.
Request Bodyrequired
Section titled “Request Bodyrequired”An email to send. Provide exactly one of content and template.name.
An email to send. Provide exactly one of content and template.name.
object
The address to send from, up to 256 characters. Its domain must be one of your verified sending domains, or it is the shared test sender address, which only reaches your verified test recipients.
The address to send to, up to 256 characters.
The subject line, up to 256 characters.
The body to send. Cannot be combined with template.name.
object
The HTML body, or MJML when format is mjml. Liquid merge fields are rendered with template.data.
A plain-text alternative. Liquid merge fields are rendered with template.data.
The format of the html body: html, or mjml (compiled to HTML, with your includes, before sending).
The kind of email: transactional (service messages, the default), marketing (promotional, subject to marketing opt-outs) or authentication (one-time codes).
Your own reference for this email, up to 64 characters, returned on the email and its events.
A grouping tag for usage reporting, up to 64 characters. Stored in lower case with anything other than letters and digits replaced by hyphens.
When (UTC, ISO 8601) to send the email: more than 5 minutes and less than 3 months ahead. If not specified, the email is sent as soon as sending limits allow; not available with the shared test sender.
Track when the email is opened. Defaults to false.
Send even if the recipient is on the suppression list. Defaults to false; a connected app cannot set it to true.
Files to attach. Up to 30000000 bytes in total once decoded.
A file to attach.
object
The file name shown to the recipient, up to 255 characters.
The MIME type of the file, e.g. application/pdf, up to 255 characters. The type sent to the recipient is worked out from the file name.
The file contents, base64 encoded.
Responses
Section titled “Responses”The email was accepted; the body shows its current status. The Location header holds its URL.
An email. The same shape is returned by every email endpoint and carried by email.* events.
object
The unique id of the email.
The kind of email: transactional (service messages, the default), marketing (promotional, subject to marketing opt-outs) or authentication (one-time codes).
The address the email was sent from.
The address the email was sent to. Null when the caller may not see recipients.
The subject line. Null when the caller may not see content.
What is kept of the body after sending.
object
The HTML body. Not kept after sending, so always null.
A plain-text excerpt of the body, up to 2000 characters, taken from the text body or extracted from the HTML.
The email status: queued (accepted or scheduled, not yet handed over for delivery), sent (handed over, awaiting the outcome), delivered (accepted by the recipient’s mail server), failed (see reason) or cancelled.
Why an email failed or did not reach the inbox.
object
Why an email failed or did not reach the inbox: hard_bounce (the address does not exist or refuses mail), soft_bounce (a temporary problem at the recipient’s server; the email may still arrive), complaint (the recipient reported it as spam), suppressed (the address is on the suppression list), rejected (refused before sending) or failed (any other failure).
The specific error code in snake_case, e.g. hard_bounce or spam_complaint.
Details of the problem, such as what the recipient’s mail server said, or null when nothing useful was recorded.
True when sending the email again later may succeed.
Your own reference for this email, as supplied when it was sent.
The grouping tag for usage reporting, as stored when the email was sent (lower case, letters, digits and hyphens).
How many times the email’s tracking image has been loaded. Stays 0 unless trackOpens was set.
When (UTC) the email was created.
When (UTC) the email was asked to send, or null when no send time was given. Sending limits can delay an email beyond this time.
When (UTC) the email was handed over for delivery, or null if not yet recorded. Can still be null in the send response moments after handover.
When (UTC) the recipient’s mail server accepted the email, or null if not delivered.
When (UTC) the email was first opened, or null if never.
When (UTC) the email last changed.
Example
{ "kind": "transactional", "status": "queued", "reason": { "category": "hard_bounce" }}The request is not valid. The detail field says why, and errors lists any problems by field name.
Why a request failed, in the RFC 9457 problem details format.
object
A URI identifying the kind of problem, ending in a code such as validation_failed, not_found, sending_blocked or rate_limited.
A short, fixed summary of the kind of problem.
The HTTP status code of the response.
What went wrong with this particular request, when there is more to say than the title.
For validation failures, the problems found, keyed by field name (nested fields as template.name, list items as messages[3]).
object
The id recorded for this error, matching the Request-Id header when one is sent. Quote it when contacting support.
Example generated
{ "type": "example", "title": "example", "status": 1, "detail": "example", "errors": { "additionalProperty": [ "example" ] }, "requestId": "example"}The API key or bearer token is missing or not valid, or the request signature could not be verified.
Why a request failed, in the RFC 9457 problem details format.
object
A URI identifying the kind of problem, ending in a code such as validation_failed, not_found, sending_blocked or rate_limited.
A short, fixed summary of the kind of problem.
The HTTP status code of the response.
What went wrong with this particular request, when there is more to say than the title.
For validation failures, the problems found, keyed by field name (nested fields as template.name, list items as messages[3]).
object
The id recorded for this error, matching the Request-Id header when one is sent. Quote it when contacting support.
Example generated
{ "type": "example", "title": "example", "status": 1, "detail": "example", "errors": { "additionalProperty": [ "example" ] }, "requestId": "example"}The caller is not allowed to do this, or sending is blocked for the workspace (sending_blocked).
Why a request failed, in the RFC 9457 problem details format.
object
A URI identifying the kind of problem, ending in a code such as validation_failed, not_found, sending_blocked or rate_limited.
A short, fixed summary of the kind of problem.
The HTTP status code of the response.
What went wrong with this particular request, when there is more to say than the title.
For validation failures, the problems found, keyed by field name (nested fields as template.name, list items as messages[3]).
object
The id recorded for this error, matching the Request-Id header when one is sent. Quote it when contacting support.
Example generated
{ "type": "example", "title": "example", "status": 1, "detail": "example", "errors": { "additionalProperty": [ "example" ] }, "requestId": "example"}A request with this Idempotency-Key is still being processed. Retry after the Retry-After header.
Why a request failed, in the RFC 9457 problem details format.
object
A URI identifying the kind of problem, ending in a code such as validation_failed, not_found, sending_blocked or rate_limited.
A short, fixed summary of the kind of problem.
The HTTP status code of the response.
What went wrong with this particular request, when there is more to say than the title.
For validation failures, the problems found, keyed by field name (nested fields as template.name, list items as messages[3]).
object
The id recorded for this error, matching the Request-Id header when one is sent. Quote it when contacting support.
Example generated
{ "type": "example", "title": "example", "status": 1, "detail": "example", "errors": { "additionalProperty": [ "example" ] }, "requestId": "example"}This Idempotency-Key was already used for a different request. Use a new key.
Why a request failed, in the RFC 9457 problem details format.
object
A URI identifying the kind of problem, ending in a code such as validation_failed, not_found, sending_blocked or rate_limited.
A short, fixed summary of the kind of problem.
The HTTP status code of the response.
What went wrong with this particular request, when there is more to say than the title.
For validation failures, the problems found, keyed by field name (nested fields as template.name, list items as messages[3]).
object
The id recorded for this error, matching the Request-Id header when one is sent. Quote it when contacting support.
Example generated
{ "type": "example", "title": "example", "status": 1, "detail": "example", "errors": { "additionalProperty": [ "example" ] }, "requestId": "example"}This API key requires an Idempotency-Key header on every POST and PATCH.
Why a request failed, in the RFC 9457 problem details format.
object
A URI identifying the kind of problem, ending in a code such as validation_failed, not_found, sending_blocked or rate_limited.
A short, fixed summary of the kind of problem.
The HTTP status code of the response.
What went wrong with this particular request, when there is more to say than the title.
For validation failures, the problems found, keyed by field name (nested fields as template.name, list items as messages[3]).
object
The id recorded for this error, matching the Request-Id header when one is sent. Quote it when contacting support.
Example generated
{ "type": "example", "title": "example", "status": 1, "detail": "example", "errors": { "additionalProperty": [ "example" ] }, "requestId": "example"}A rate limit was reached. Retry after the Retry-After header when one is given.
Why a request failed, in the RFC 9457 problem details format.
object
A URI identifying the kind of problem, ending in a code such as validation_failed, not_found, sending_blocked or rate_limited.
A short, fixed summary of the kind of problem.
The HTTP status code of the response.
What went wrong with this particular request, when there is more to say than the title.
For validation failures, the problems found, keyed by field name (nested fields as template.name, list items as messages[3]).
object
The id recorded for this error, matching the Request-Id header when one is sent. Quote it when contacting support.
Example generated
{ "type": "example", "title": "example", "status": 1, "detail": "example", "errors": { "additionalProperty": [ "example" ] }, "requestId": "example"}The email could not be queued right now. Retry after the Retry-After header.
Why a request failed, in the RFC 9457 problem details format.
object
A URI identifying the kind of problem, ending in a code such as validation_failed, not_found, sending_blocked or rate_limited.
A short, fixed summary of the kind of problem.
The HTTP status code of the response.
What went wrong with this particular request, when there is more to say than the title.
For validation failures, the problems found, keyed by field name (nested fields as template.name, list items as messages[3]).
object
The id recorded for this error, matching the Request-Id header when one is sent. Quote it when contacting support.
Example generated
{ "type": "example", "title": "example", "status": 1, "detail": "example", "errors": { "additionalProperty": [ "example" ] }, "requestId": "example"}