wait (1–30 seconds) and the server holds the connection until mail
arrives, returning the instant it does:
There is nothing to install and no library to learn. A held HTTP request works in
CI, in a shell script, and in every HTTP client in every language — which is
exactly why long-polling was chosen over SSE or webhooks.
The cursor contract
This is the part worth reading twice. Get it wrong and you will either miss mail or reprocess it.1
Pass `since` with the newest id you have already seen
On the first call you have nothing, so omit it.
2
Feed `meta.next_since` into your next request
Every response echoes a cursor. Use it verbatim; do not compute your own.
3
Keep the cursor across empty responses
A
wait that times out returns data: [] and still echoes your cursor.
Discarding it on an empty response is the classic bug — you rewind and
reprocess mail you already handled.Two ways this bites people
Your client times out before the server answers
Your client times out before the server answers
If you ask for
wait=30 with a default 10-second client timeout, your own
HTTP library hangs up first and you see a timeout error, not an empty result.
Set the client timeout above the wait value — the Python example uses
timeout=40 for wait=30 for exactly this reason.You get `too_many_waiters` unexpectedly
You get `too_many_waiters` unexpectedly
Each key may hold 5 concurrent long-polls. A test suite running with
--parallel 8 against one key will trip this. Either lower the parallelism,
mint a key per worker, or catch the 429 and retry — it is a capacity signal,
not a failure.If you get key_required instead, you are calling wait anonymously.
Long-polling needs a key.Building in a browser instead?
There is a realtime Phoenix channel that pushes events with no polling at all:inbox:<local_part>@<domain> — for example
inbox:jay@meowmail.in. The server pushes new_email when mail arrives and
email_expired when it is deleted by TTL.
Long-polling exists because it works everywhere the channel does not: CI, shell
scripts, and any HTTP client without a Phoenix library.