Resend a message
/api/v1/email-logs/{event}/resendSubmits the stored copy of this message again. Requires messages:send, not
events:read — it puts mail back on the wire.
Pass to to send it somewhere else. That is the usual reason to resend: the customer
gave the wrong address, and reconstructing the message by hand to send it to the right
one loses whatever the original actually said.
A redirected resend is not a privileged path — the new recipient is checked against your suppression list and counted against your rate limit exactly like a fresh send.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
eventrequired | path | string | The event identifier. |
Request body
toanySend to this address instead of the original recipient. Omit to resend to whoever it went to the first time.
Request
/api/v1/email-logs/{event}/resendcurl -X POST 'https://app.mailyte.com/api/v1/email-logs/01JBT8XQ2M9WYC3K4F6R7S8T9V/resend' \
-H 'Authorization: Bearer mk_live_YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"to": "corrected@example.com"
}'const response = await fetch('https://app.mailyte.com/api/v1/email-logs/01JBT8XQ2M9WYC3K4F6R7S8T9V/resend', {
method: 'POST',
headers: {
Authorization: 'Bearer mk_live_YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
"to": "corrected@example.com"
}),
});
const { data } = await response.json();import requests
response = requests.post(
"https://app.mailyte.com/api/v1/email-logs/01JBT8XQ2M9WYC3K4F6R7S8T9V/resend",
headers={"Authorization": "Bearer mk_live_YOUR_API_KEY"},
json={
"to": "corrected@example.com"
},
)
data = response.json()["data"]<?php
$response = Http::withToken('mk_live_YOUR_API_KEY')
->post('https://app.mailyte.com/api/v1/email-logs/01JBT8XQ2M9WYC3K4F6R7S8T9V/resend', [
'to' => 'corrected@example.com',
]);
$data = $response->json('data');require "net/http"
require "json"
uri = URI("https://app.mailyte.com/api/v1/email-logs/01JBT8XQ2M9WYC3K4F6R7S8T9V/resend")
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer mk_live_YOUR_API_KEY"
request["Content-Type"] = "application/json"
request.body = {
"to": "corrected@example.com"
}.to_json
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }Response
Success.
dataobjectobjectstringmessageidstringThe opaque handle for this submission: a BARE ULID, no host and no angle brackets. `GET /email-logs/messages/{id}` resolves it immediately -- you do not have to wait for a webhook. It is NOT the Message-ID. NULL WOULD MEAN UNKNOWN and cannot happen on a 2xx: the send mints this before it records anything, so a response that carries a receipt carries a handle. If you are holding null you are not holding an accepted message.
message_idstringThe RFC 5322 Message-ID as it went out on the wire, ANGLE BRACKETS INCLUDED -- `<01JBT8XQ2M...@example.com>`. It is the header your recipient sees and the id `GET /domains/{domain}/messages/{messageId}` takes; percent-encode it in the path. `id` is the bare ULID and the two are not interchangeable: giving `id` to the archive endpoint returns 404, which is precisely what this field used to publish. Null when no sending host could be determined, never a guess.
recipientstringThe PRIMARY addressee, without any display name. Published as `recipient` rather than `to`, matching every event and message row in this section. It stays a single string now that a message may have several recipients, so code reading it does not change type underneath you -- read `recipients` for the whole set. NULL WOULD MEAN UNKNOWN and cannot happen on a 2xx, since `to` is required.
recipientsobjectEveryone the message was addressed to. **`bcc` is deliberately absent**: blind recipients are recorded in your delivery log but never echoed on a receipt, which is the one response most likely to be forwarded, logged or shown to a customer.
toarray<string>As accepted, including any display name.
ccarray<string>Empty when none were given -- NONE, not unknown.
countintegerTo plus Cc. Excludes Bcc, which is not published here; the limit of 50 counts all three together.
reply_tostringThe Reply-To that went out. NULL MEANS NONE was set, in which case replies go to `from`.
attachment_countintegerHow many files were attached. Zero means none were sent, never that we did not look.
fromobjectThe sender. An object here, and everywhere else a sender appears, so one piece of caller code reads all of them.
emailstringThe address this was accepted as, echoed back. NULL WOULD MEAN UNKNOWN and cannot happen on a 2xx -- `from` is a required, validated field on the request and the receipt republishes the resolved sender's own address. It is never "sent from nowhere".
namestringThe display name the message was sent with — the same one that went into the `From:` header, not a lookup done afterwards. NULL MEANS NONE: this sender has no display name set, so the message went out as a bare address. It is not "unknown" and it is not withheld — set a name on the sender and it appears here.
subjectstringThe subject AS RENDERED -- `{{ }}` substituted, the same string that went into the header -- which is why it can differ from what you posted and why it is echoed at all. NULL WOULD MEAN UNKNOWN and cannot happen on a 2xx: the renderer falls back to the empty string, so a subjectless send is published as `""`, never as null. Test for `""`, not for null.
submitted_atstringWhen we ACCEPTED the message, not when it was delivered. A 200 here means queued; the outcome arrives as a delivery event or a webhook. NULL WOULD MEAN UNKNOWN -- we could not read the timestamp off the recorded submission -- and never that the message is not submitted yet. A 2xx has already written the row, and its timestamp column is `NOT NULL DEFAULT current_timestamp()`, so this is not a case to code for.
modestringlive | testWhether a real message was sent. `test` means this request was made with a TEST API KEY: it was validated exactly as a live one would be — the sender had to be verified, the recipients had to not be suppressed, the rate limit applied — and then nothing was handed to the mail server and nothing was recorded. `id`, `message_id` and `submitted_at` are null for that reason: there is no message to look up. Test mode is a property of the key, not of the request, so it cannot be switched on by a stray parameter in production code.
Returned inside the standard envelope.
Errors
| Status | When |
|---|---|
401 | The API key is missing, unknown, revoked or expired. All four answer identically, on purpose: distinguishing them would confirm which keys exist. |
403 | The key is valid but may not do this: it lacks the required scope, its IP allowlist does not include you, or this endpoint does not accept API keys. |
404 | No such resource in this organization. |
422 | The request was understood but the values were not acceptable. |
429 | Too many requests, or the organization has spent its sending allowance. `Retry-After` says how long to wait. |
Every status, with what causes it and what to do, is on the error reference.