JustEmails
Start free trial
Guides··12 min read

The Email API Developer Glossary (2027)

14 email API terms that decide whether your integration is reliable or quietly broken — starting with the one that sent 41 welcome emails to one user.

By JustEmails Platform Team
Contents
  1. The Email API Cheat Sheet
  2. Idempotency, Retries, and the Duplicate Problem
  3. 1. Idempotency key
  4. 2. At-least-once delivery
  5. 3. Retry backoff (and jitter)
  6. Throughput: Limits, Windows, and Batches
  7. 4. Rate window
  8. 5. 429 and Retry-After
  9. 6. Batch endpoint
  10. Webhooks: Getting Events Back
  11. 7. Webhook signature
  12. 8. Timestamp tolerance
  13. 9. Webhook retry policy and dead-letter queue
  14. Environments, Routing, and State
  15. 10. Sandbox mode
  16. 11. Message stream
  17. 12. Suppression list
  18. 13. Message ID and message log
  19. 14. Sending domain vs From domain
  20. Honorable Mentions
  21. Quick Verdict
  22. Frequently Asked Questions
  23. What is an idempotency key in an email API?
  24. How do I verify a webhook signature safely?
  25. Do I need sandbox mode if I already have a staging environment?
  26. What's a message stream and why separate transactional from marketing?
  27. Try JustEmails

41 welcome emails. One user. Ninety seconds.

The signup endpoint called the email API, the API took longer than my HTTP client's 10-second timeout, the client threw, my retry wrapper caught it and tried again — and every one of those sends had actually succeeded. The API had no idea the requests were the same request, because I'd never given it a way to know.

The fix was one header. Four minutes, once I knew the word for it.

That's the annoying thing about email API terms: the concepts are simple, but without the vocabulary you can't search for the fix. You don't know what you're missing, so you can't google it.

So here are 14 of them, written for whoever's wiring up sends at 11pm and getting weird results.

The Email API Cheat Sheet

TermWhat it actually means
Idempotency keyA client-generated string that makes a repeated send request a no-op
At-least-once deliveryThe API guarantees your request lands, maybe more than once — dedupe is on you
Retry backoffEscalating waits between retry attempts, ideally with jitter
Rate windowThe rolling time span your request quota is measured over
429 / Retry-After"Slow down" plus the server telling you exactly how long
Batch endpointOne HTTP call carrying many messages, each with its own result
Webhook signatureAn HMAC proving the event came from your provider, not a stranger
Timestamp toleranceThe age limit that stops a captured webhook from being replayed
Dead-letter queueWhere events go after your endpoint fails every retry
Message streamA named sending lane with its own reputation and suppressions
Sandbox modeAccepts and validates a send, delivers nothing
Suppression listAddresses the provider refuses to send to, permanently
Message IDThe per-message identifier that ties a send to its later events
Sending domainThe domain that signs the mail, which isn't always the From domain

Idempotency, Retries, and the Duplicate Problem

1. Idempotency key

A unique string you attach to a send so the server can tell "retry of request A" from "new request B." Same key inside the retention window, same response, no second email. Stripe popularised the pattern for payments; email adopted it for the same reason — the failure mode is expensive and visible.

Generate it once, when you create the job, and store it. Generating it inside the retry loop defeats the whole mechanism — a mistake I've made. Don't hash the request body either: two separate password resets to the same address in an hour are legitimately two emails, and body-hashing swallows the second. JustEmails accepts idempotency keys on its REST API for exactly this.

2. At-least-once delivery

The contract almost every queue and HTTP API actually offers: your message will be processed, possibly more than once. Exactly-once is mostly marketing — the honest version is at-least-once plus a dedupe key, which is at-least-once wearing a nicer shirt.

SemanticWhat you getWho handles duplicates
At-most-onceFire and forget, may vanishNobody — you lose messages
At-least-onceAlways arrives, may repeatYou, via idempotency key
Exactly-onceMarketing copyStill you

3. Retry backoff (and jitter)

Escalating waits between attempts — 1s, 2s, 4s, 8s — so a struggling server gets room to recover instead of a wall of retries. Jitter is the part people skip: randomness, so ten thousand clients that failed at the same second don't all retry at the same second. Without it you've built a synchronised stampede that re-creates the outage you were retrying past.

Cap the attempts, too. An unbounded retry loop against a permanently failing endpoint is a self-inflicted outage, and it's your own alerts inbox that pays for it — I've spent a morning deleting the evidence.

Throughput: Limits, Windows, and Batches

4. Rate window

The span your quota is measured over — 100 requests per rolling 60 seconds, say. Fixed and rolling windows differ at the edges, and the difference is real: with a fixed window you can send 100 at 11:59:59 and 100 more at 12:00:01, pass both, and still get throttled by a downstream rolling counter that saw 200 in two seconds. Check which one you're up against before tuning worker concurrency. Good luck finding it in the docs, though — in my experience roughly half of providers just don't say, so you learn which one it is by getting throttled.

5. 429 and Retry-After

429 Too Many Requests means you hit the limit. The Retry-After header tells you how long to wait, in seconds or as an HTTP date. Honour it. Treating a 429 like a 500 — retrying immediately — is the most common way to turn a brief throttle into a long block. I know because I wrote the retry wrapper that did it.

6. Batch endpoint

One request carrying many messages. Fewer TLS handshakes, less overhead, higher throughput. The catch nobody documents loudly enough: batch responses are usually partial success. HTTP 200, and an array where message 3 failed validation while the other 49 went out fine.

Check the status code and move on, and you've silently dropped an email while logging a success. Iterate the array. Every time.

Burying partial-success semantics three levels down in an API reference is, I think, the worst documentation habit in this whole category.

Webhooks: Getting Events Back

7. Webhook signature

An HMAC (SHA-256, typically) computed over the raw payload with a shared secret, sent in a header. Your endpoint is a public URL anyone can POST to, so the signature is what proves the event came from your provider. Skip verification and a stranger can tell your app a customer's email hard-bounced, then watch your code helpfully suppress that address forever.

Hash the raw bytes, before any JSON parsing. Compare in constant time. Two rules, and most broken verification code violates one of them.

8. Timestamp tolerance

The maximum age of a signed payload you'll accept, usually five minutes. Signatures don't expire on their own — without this check, a payload captured once stays valid forever. The timestamp goes inside the signed material, otherwise an attacker just edits it.

An endpoint that checks the signature but skips the timestamp isn't "mostly secure." It's unauthenticated with extra steps.

9. Webhook retry policy and dead-letter queue

When your endpoint returns a non-2xx or times out, the provider retries on a backoff, then eventually gives up and parks the event. That parking spot is the dead-letter queue.

So your handler needs to be fast and idempotent: acknowledge with a 200, push the work onto a queue, process asynchronously. A handler doing 8 seconds of database work inline will time out under load, get retried, and process the same bounce four times. Bounces and complaints are the events you least want to mishandle — handling bounce and complaint webhooks covers the reputation side.

Environments, Routing, and State

10. Sandbox mode

The provider accepts the request, validates it, returns a realistic response — and delivers nothing. Mailtrap built a business on the idea. It exists because "staging can't send real mail" is a promise your environment config makes and eventually breaks, usually the day someone restores a production dump into staging.

Strong opinion, take it or leave it: a provider that still ships no sandbox is telling you exactly how much they test their own API.

11. Message stream

A named lane with its own reputation, suppression list, and event log. Postmark made the term common. Transactional mail and bulk announcements have opposite engagement profiles, so mixing them lets the complaint rate from your newsletter decide whether password resets reach the inbox.

Related but separate: the dedicated sending subdomain, which does the same isolation job at the DNS level.

12. Suppression list

Addresses the provider will refuse to send to — hard bounces, spam complaints, unsubscribes. It's a safety rail, not a bug. Sending to a known-dead address is a reputation hit with a guaranteed-zero payoff.

Check whether your provider's API lets you read the list. If it does, sync it into your own database — otherwise your app queues a send, gets a silent drop, and support spends a morning on "the customer never got the email."

13. Message ID and message log

The identifier returned on a successful send, referenced by every later webhook event. Store it on the row that triggered the send. Skip that and you get a webhook saying "message a1b2c3 bounced" with no way to know which user that was — I've written that backfill after the fact and it isn't fun. JustEmails keeps message logs and sends webhook delivery notifications, including on the 1,000 transactional emails/month that come with the $49/year plan.

14. Sending domain vs From domain

The sending domain signs the mail (DKIM) and owns the Return-Path; the From domain is what the human sees. They can differ — that's what Gmail's "sent via" label is reacting to — and aligning them is what DMARC checks. Return-Path vs From address has the mechanics; why no-reply@ is a bad default covers the part that's a product decision, not a DNS one.

Honorable Mentions

202 vs 200 — most email APIs return 202 Accepted, meaning queued, not delivered; treating it as delivered is a reporting bug waiting to happen. Idempotency window — how long keys are remembered, typically hours to a day. Hard vs soft bounce — permanent versus temporary; suppress the first, retry the second, and mixing them up quietly shrinks your list. List-Unsubscribe-Post — the RFC 8058 header behind one-click unsubscribe, now effectively mandatory for bulk senders. Template versioning — pinning a send to a version so a designer's edit can't rewrite last month's receipts. Oh, and structured logging on the app side: JustAnalytics keeps logs, traces, and uptime together, which beats chasing a send failure across three dashboards. Rate limiting at the edge is a cousin of the same problem — ClickzProtect does it for bot traffic before the request costs you anything.

Quick Verdict

If you keep four of these email API terms, keep idempotency key, partial success on batch endpoints, webhook signature with a timestamp check, and 202 means queued. Those four cover the failure modes that produce silent, expensive bugs — duplicates, dropped messages, spoofed events, dashboards that lie.

And a take not everyone shares: your integration's reliability depends far more on your retry and webhook code than on which provider you picked. Providers converge on features fast. Your retry loop is bespoke, untested, and runs at 3am. That's where the bugs live.

Frequently Asked Questions

What is an idempotency key in an email API?

It's a unique string you generate and attach to a send request so the API can recognise a repeat of that exact request. If your client times out and retries, the server sees the key it already processed, returns the original result, and does not send a second email. The key has to be stable across retries and unique across distinct sends — a UUID stored alongside the job usually works, while a hash of the request body does not, because two genuinely separate welcome emails to the same address hash identically. Most APIs remember keys for a bounded window measured in hours or days, so it protects against retry storms, not against a duplicate you fire next week.

How do I verify a webhook signature safely?

Compute an HMAC over the raw request body using your signing secret, then compare it to the header value with a constant-time comparison function. Three details break most implementations: parsing the JSON before hashing (your framework re-serialises it and the bytes no longer match), using == instead of hmac.compare_digest (timing leak), and ignoring the timestamp. Without a timestamp tolerance — five minutes is the common window — a signature stays valid forever, so anyone who captures one payload can replay it at will. Verify signature and timestamp, then process.

Do I need sandbox mode if I already have a staging environment?

Usually yes, and for a reason that has nothing to do with environments. A staging server with real API credentials still hits real inboxes when someone seeds it with a production database dump. Sandbox mode accepts the request, validates it, returns a normal response, and drops the message instead of delivering it — so your integration tests exercise the real code path without mailing 4,000 people a test order confirmation. If your provider has no sandbox, the workaround is a fake domain plus an allowlist of internal addresses, checked in code before the send call.

What's a message stream and why separate transactional from marketing?

A message stream is a named lane inside your account with its own sending reputation, suppression list, and event history. Transactional mail — password resets, receipts — gets opened and rarely reported. Bulk announcements get ignored and sometimes marked as spam. Put them in one stream and the complaint rate from the second category drags down delivery of the first, which is how a company ends up with password reset emails in the junk folder. Separate streams (or at minimum separate sending subdomains) keep one category's reputation from poisoning the other.


Try JustEmails

Unlimited custom domain email hosting for $49/year flat — unlimited domains, unlimited mailboxes, 10 GB storage, full IMAP/SMTP. Built for agencies, freelancers, and anyone managing email across more than one domain.

The trial wants a card up front. That's there to stop trial-farming, not to catch you out — cancel anytime before day seven and nothing is charged.

Start your 7-day free trial → · How it compares

email-apitransactional-emailwebhooksidempotencydeveloper-glossarybuildinpublicsaasstudioaiworkforcebuildwithclaude

Related posts

Industry
Email Outage Statistics 2027: SLAs, Downtime and Credits
13 min read
Tutorials
Typeform and Tally Email Notifications to a Custom Domain Inbox
14 min read
Comparisons
AhaSend Alternative: Comparing the JustEmails Transactional API
12 min read