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-generated and an X-Loop header naming the inbox.
  • On receipt, skip any message whose headers carry auto-submitted set to anything other than no, precedence of bulk, list, junk, or auto_reply, or your own x-loop value.
  • 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.

Next steps