Send email reliably
Verify a sender, submit an idempotent request, and distinguish acceptance from delivery.
Before sending#
Use an address on a domain you own and have verified with AWS SES. Your account's SES region, sandbox restrictions, quotas and reputation still apply. Mailat software does not allow sending from arbitrary unverified domains or remove AWS limits.
Sending-only domain setup leaves receiving with your existing mail provider. Prepare sending resources when using attachment storage or delivery feedback. A setup response can be partially ready: inspect storageReady, feedbackConfigured, subscriptionStatus, feedbackReady and any reason, even when HTTP status is 200.
First request#
With email:send, submit to POST /emails. Set the environment variables described in authentication.
curl "$MAILAT_BASE_URL/api/v1/emails" \
--header "Authorization: Bearer $MAILAT_TOKEN" \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: onboarding-job-42' \
--data '{"from":"[email protected]","to":["[email protected]"],"subject":"Welcome","text":"Hello from Mailat"}'
Replace both addresses. Store the returned public message UUID with your own job. It is different from an RFC Message-ID, SES provider ID or internal numeric database ID.
Retry without duplicate mail#
Persist one 8–128 character Idempotency-Key per logical send. Reuse it with identical content after a timeout or retry. Changed content under the same key returns 409. A single transactional request can use JSON idempotencyKey instead; if both are present, they must match.
Batch and compose require the header. A batch key binds the entire ordered request; retain that order and payload on retry. Stable per-item keys are optional; otherwise they derive from the batch key and item position. Inspect individual results instead of assuming every item succeeded.
JavaScript example#
const response = await fetch(`${process.env.MAILAT_BASE_URL}/api/v1/emails`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.MAILAT_TOKEN}`,
'Content-Type': 'application/json',
'Idempotency-Key': 'onboarding-job-42',
},
body: JSON.stringify({
from: '[email protected]', to: ['[email protected]'],
subject: 'Welcome', text: 'Hello from Mailat',
}),
})
if (!response.ok) throw new Error(`Mailat returned ${response.status}`)
const result = await response.json()
Use this in a trusted backend, not a visitor's browser. Persist the key before submission; the literal key above illustrates one job only.
Track the result#
Use GET /emails/{id} or delivery webhooks. pending/queued precede submission; sending means a worker has claimed it; sent means SES accepted it; delivered means the destination server accepted it. Neither acceptance nor delivery guarantees inbox placement.
bounced, complained and failed need investigation. unknown indicates ambiguous provider acceptance: do not blindly create a new send with a different key. See webhook recovery.