Skip to main content

Email statuses and events

After a 202 response you can read the email by its id: the email status, the status and reason of each recipient, open and click events. The same statuses and reasons arrive in email.* webhooks.

Before you start​

  • A token with the email.read scope.
  • The email's data.id from the send response.

Endpoints​

RequestReturns
GET /api/v1/public/emails/{emailId}The email and all its recipients, each with the first event of every type
GET /api/v1/public/emails/{emailId}/recipients/{recipientId}Delivery details for one recipient: the recipient server's SMTP response, click count
GET /api/v1/public/emails/{emailId}/recipients/{recipientId}/eventsAll events of a recipient, paginated

emailId is data.id from the send response, recipientId is recipients[].id. The email is readable right after the 202 response.

You can read emails accepted since ДД.ММ.ГГГГ by any method, including SMTP. Earlier sends can't be read by emailId (404) — their deliveries are in the sending history.

These endpoints use the shared public API request limit; when it's exceeded you get 429 RATE_LIMIT_EXCEEDED and a Retry-After header with the number of seconds before you can retry.

Reading an email​

const emailId = process.env.EMAIL_ID;
const response = await fetch(
`https://api.emailmassivo.com/api/v1/public/emails/${emailId}`,
{ headers: { 'Authorization': `Bearer ${process.env.API_TOKEN}` } },
);
const { data } = await response.json();
console.log(data.status, data.recipients.map((r) => [r.email, r.status]));
{
"ok": true,
"data": {
"id": "0199b2f4-6c1e-7a3d-9f2b-4e8c1d7a5b60",
"status": "delivered",
"keyId": 42,
"from": { "email": "noreply@shop.com", "name": "Shop" },
"subject": "Order confirmation",
"templateId": null,
"createdAt": "2026-09-30T10:15:00.000Z",
"sentAt": "2026-09-30T10:15:02.310Z",
"completedAt": "2026-09-30T10:15:04.870Z",
"recipients": [
{
"id": "3f6c2a9e-8b1d-4c7a-9e2f-5a1b7c3d9e01",
"email": "client@example.com",
"name": "John",
"type": "to",
"status": "delivered",
"reason": null,
"sentAt": "2026-09-30T10:15:02.310Z",
"completedAt": "2026-09-30T10:15:04.870Z",
"events": [
{ "type": "delivered", "occurredAt": "2026-09-30T10:15:04.870Z" },
{ "type": "clicked", "occurredAt": "2026-09-30T10:20:30.050Z", "url": "https://shop.com/orders/1234" }
]
},
{
"id": "c4a07e13-5d2b-4e8f-b916-7f3a2d0c8b44",
"email": "manager@shop.com",
"name": null,
"type": "cc",
"status": "bounced",
"reason": {
"code": "DELIVERY_MAILBOX_FULL",
"bounceType": "transient",
"message": "Recipient mailbox is full.",
"smtpResponse": "552 5.2.2 Mailbox full"
},
"sentAt": "2026-09-30T10:15:02.310Z",
"completedAt": "2026-09-30T10:15:05.020Z",
"events": [
{ "type": "bounced", "occurredAt": "2026-09-30T10:15:05.020Z" }
]
}
]
},
"meta": { "requestId": "01JB2W...", "timestamp": "2026-09-30T10:16:00.000Z" }
}

Email

FieldMeaning
idEmail identifier
statusEmail status — see Email status
keyIdThe sending key the email was accepted with
fromSender
subjectSubject after variable substitution
templateIdThe email's template or null. When sent by alias — the id of the template found by the alias
createdAtWhen the email was accepted
sentAtThe earliest send time among to recipients, or null
completedAtWhen the email reached a final status, or null
recipientsAll recipients of the email, each with its own id and status

Recipient

FieldMeaning
idIdentifier of the delivery to this recipient
email, nameAddress and name — as in the request
typeto, cc, or bcc
statusDelivery status — see Statuses
reasonReason for bounced, failed, and suppressed, otherwise null — see Reason
sentAtWhen the email was handed off for sending to this recipient; null if it wasn't sent
completedAtWhen the delivery reached a final status, or null
eventsThe first event of each type, oldest first — see Events

Statuses​

queued → sending → delivered | bounced | failed
recipients also have: suppressed
StatusMeaningFinal
queuedThe email is accepted and waiting to be sentno
sendingThe email has been handed off for sendingno
deliveredThe recipient's mail server confirmed receiptyes
bouncedNot delivered for a reason on the recipient's side: the address doesn't exist, the mailbox is full, the server refused or is unreachable — or the address is on the EmailMassivo list of undeliverable addresses. The bounce type is reason.bounceTypeyes
failedThe email couldn't be sent. The recipient address is fine — you can send the email againyes
suppressedRecipients only: the recipient unsubscribed from this sending key's emails or complained about them. The email wasn't sent to themyes

opened, clicked, unsubscribed, and complained are events, not statuses: after an open the recipient status stays delivered.

delivered sometimes turns into bounced

Occasionally the recipient's mail server sends a non-delivery report after it has already confirmed receipt. The recipient's status then changes from delivered to bounced, and an email.bounced webhook arrives. There are no other transitions out of a final status.

Email status​

The email status is a summary of the to recipients: while delivery is in progress — queued or sending; when delivered to everyone — delivered; otherwise — bounced or failed. cc and bcc don't affect it.

Make decisions about a specific address based on that recipient's status and reason.

Reason​

{
"code": "DELIVERY_MAILBOX_FULL",
"bounceType": "transient",
"message": "Recipient mailbox is full.",
"smtpResponse": "552 5.2.2 Mailbox full"
}
FieldMeaning
codeReason code — see the table below
bounceTypebounced only: permanent, transient, or undetermined
messageFixed English text for the code
smtpResponsebounced after a send attempt only: the recipient server's response with IP addresses removed. If the response isn't available, the field is absent

bounceType​

bounceTypeMeaningWhat to do
permanentThe address doesn't exist or is on the EmailMassivo list of undeliverable addressesRemove the address from your base, don't send to it
transientA refusal right now: the mailbox is full, the email was taken for spam, the sender domain's signature check failed, a rate limit, a temporary failure. The address is aliveYou can send later; for content or signature refusals fix the cause first
undeterminedThe server refused, but the reason is unclear or it's a recipient policy for a live addressNot a reason to remove the address; if refusals repeat, investigate using smtpResponse

Remove an address from your base on bounceType: permanent, not on any bounced.

Reason codes​

StatuscodebounceTypeMeaning
suppressedRECIPIENT_UNSUBSCRIBED—The recipient unsubscribed from this key's emails
suppressedRECIPIENT_COMPLAINED—The recipient complained about this key's emails
bouncedRECIPIENT_KNOWN_BOUNCEDpermanentThe address is already known as undeliverable; the email wasn't sent
bouncedRECIPIENT_BLOCKEDpermanentThe address is blocked; the email wasn't sent
bouncedRECIPIENT_INVALIDpermanentThe address is considered invalid; the email wasn't sent
bouncedRECIPIENT_DOMAIN_INVALIDpermanentThe address's domain doesn't accept mail; the email wasn't sent
bouncedDELIVERY_MAILBOX_NOT_FOUNDpermanentThe mailbox doesn't exist
bouncedDELIVERY_DOMAIN_NOT_FOUNDpermanentThe domain doesn't exist or has no mail server
bouncedDELIVERY_REJECTEDpermanent or undeterminedThe recipient server rejected the email
bouncedDELIVERY_MAILBOX_FULLtransientThe mailbox is full
bouncedDELIVERY_RATE_LIMITEDtransientThe recipient server is limiting the rate of incoming email
bouncedDELIVERY_SPAM_REJECTEDtransientThe recipient server took the email for spam
bouncedDELIVERY_SENDER_AUTH_FAILEDtransientThe sender domain's SPF, DKIM, or DMARC check failed
bouncedDELIVERY_TEMPORARY_FAILUREtransientThe recipient server temporarily refused the email
bouncedDELIVERY_CONNECTION_FAILEDundeterminedThe recipient's mail server couldn't be reached
bouncedDELIVERY_UNDETERMINEDundeterminedThe server refused for an undetermined reason
failedINTERNAL_ERROR—The email couldn't be sent

RECIPIENT_* codes on bounced mean an early rejection: the email wasn't sent to this recipient, no quota was charged for them, sentAt is null, and there's no smtpResponse. failed never has an SMTP response.

Sending again​

bounced and failed are final statuses: there will be no more delivery attempts for this email. Sending again means a new email: a new request with a new Idempotency-Key, and quota is charged for it again.

  • suppressed — don't send to this recipient through this key: they opted out themselves.
  • bounced with permanent — don't send to this address.
  • bounced with transient — you can send later. For DELIVERY_SPAM_REJECTED and DELIVERY_SENDER_AUTH_FAILED, fix the content or the domain's DNS records first — otherwise the refusal repeats.
  • bounced with undetermined — you can send later; if refusals repeat, investigate using smtpResponse.
  • failed — the address is fine; send the email again.

Events​

TypeWhen
suppressed, delivered, bounced, failedThe recipient reached a final status
openedThe recipient opened the email
clickedThe recipient clicked a link; the event has url
unsubscribedThe recipient unsubscribed from this sending key's emails
complainedThe recipient complained about the email

In GET /api/v1/public/emails/{emailId} each recipient has no more than five events: the final one plus the first opened, clicked, unsubscribed, and complained.

All events of a recipient​

curl "https://api.emailmassivo.com/api/v1/public/emails/$EMAIL_ID/recipients/$RECIPIENT_ID/events?type=clicked,opened&page=1&limit=20" \
-H "Authorization: Bearer $API_TOKEN"
  • type — comma-separated event types; without the parameter — all types.
  • page — starts at 1; limit — 1 to 100, 20 by default. Pagination totals are in meta.pagination.
  • Events are sorted by occurredAt ascending.
  • opened and clicked have device (desktop, phone, tablet, or null) and client (outlook, chrome, firefox, safari, apple_mail, other, or null).

Repeated opens aren't stored: events contain only the first opened. All clicks are stored.

Delivery details for a recipient​

GET /api/v1/public/emails/{emailId}/recipients/{recipientId} returns the same recipient fields as reading the email, plus:

FieldMeaning
emailIdThe email this delivery belongs to
smtpResponseThe recipient server's last response with IP addresses removed — for delivered and for bounced after a send attempt. If the response is temporarily unavailable, the field is absent
clickCountHow many times the recipient clicked links in the email

Responses don't include the email content, the Message-ID header, or the recipient's IP addresses and user agent.

Handling errors​

HTTPerror.codeCauseAction
403SCOPE_REQUIREDThe token lacks the email.read scopeAdd the scope to the token
404EMAIL_NOT_FOUNDThere's no email with this id, it belongs to someone else, it was accepted before ДД.ММ.ГГГГ, or the id isn't a UUID. A recipients[].id passed as emailId also gets this codeCheck that the path has data.id from the send response
404EMAIL_RECIPIENT_NOT_FOUNDThe email exists but has no such recipientTake recipientId from this email's recipients[]
429RATE_LIMIT_EXCEEDEDThe shared public API request limit is exceededRetry after the pause from Retry-After

See also​