Get email content
Text, HTML, headers, raw MIME, and plus-address threads.
Stored inbound mail and the JSON webhook share one payload. This page lists its fields and explains how threads work.
Payload fields
| Field | What it holds |
|---|---|
id |
The message id |
inbox_id |
The inbox that received it |
to, from, subject |
Addressing and subject |
text, html |
The plain-text and HTML bodies |
in_reply_to |
The In-Reply-To header |
headers |
from, to, cc, subject, date, message-id, in-reply-to, references, auto-submitted, precedence, x-auto-response-suppress, x-autoreply, list-id, and x-loop, when present |
envelope |
mail_from, rcpt_to, and plus_tag from the SMTP session |
authentication |
SPF, DKIM, DMARC, and ARC results |
attachments |
File metadata. See Receiving attachments. |
expires_at |
When PostShiba deletes the stored message |
thread_id |
The thread key. See below. |
API responses also include drain_status, and message show adds raw with the full MIME while PostShiba keeps it; with retention off, raw is null once the webhook delivers. See Retention and storage. Full field rows are on Inbound messages.
Threads and plus-addresses
Plus-addressing routes agent+thread@ to the inbox agent@ and sets thread_id to thread. Give each conversation its own tag to keep replies together.
Without a plus tag, thread_id is the first In-Reply-To value, then the first References value, then the message's own Message-ID.
Prevent mail loops
A loop starts when your app emails someone about inbound mail and that address forwards back to the inbox. Each copy triggers another email.
- Mark every automated email you send with
Auto-Submitted: auto-generatedand anX-Loopheader naming the inbox. - On receipt, skip any message whose
headerscarryauto-submittedset to anything other thanno,precedenceofbulk,list,junk, orauto_reply, or your ownx-loopvalue. - Never send a notification about a message you skipped.
- Cap notifications per sender and thread, so a loop the headers miss still stops.
The JSON webhook does not carry the raw MIME, so read these from headers. GET on the message returns raw only until the webhook delivers.
PostShiba also stops loops it can see. Once one sender has sent an inbox 10 messages in 10 minutes, further automated mail from that sender is stored with drain_status held. Mail counts as automated if it has one of the headers listed here, or if it was sent through PostShiba. A held message does not trigger the webhook or a forward. It still shows in the dashboard and the API until it expires. Mail from people is never held.