email.received
Inbound mail arrived and was matched onto a thread.
Inbound mail. The one most applications are built around — it fires once per received message, with the thread it belongs to already resolved.
Payload
email_idstring
eml_… — retrieve it for bodies and headers.
stringthread_idstring
The conversation it belongs to.
stringdomain_idstring | null
The domain it was received on, or null when it came through a mailbox.
string | nullmailbox_idstring | null
The mailbox it was synced from, or null when it came in on a domain.
string | nullfromstring
Sender address.
stringtostring[]
Recipients on the envelope.
string[]subjectstring
The subject line.
stringsnippetstring
A short preview of the body.
stringcategorystring | null
human, out_of_office, auto_reply, bounce, verification, transactional, notification, marketing, or spam.
string | nullverdicts?object
Sender authentication results: spam, spf, dkim, dmarc.
objectattachments?object[]
id, filename, content_type, size, preparation — metadata only.
object[]{
"id": "evt_...",
"type": "email.received",
"created_at": "2026-09-01T10:31:04Z",
"space_id": null,
"data": {
"email_id": "eml_...",
"thread_id": "thr_...",
"domain_id": "dom_...",
"mailbox_id": null,
"from": "grace@example.com",
"to": ["support@yourapp.com"],
"subject": "Re: Quick question",
"snippet": "Thursday at 10 works for me…",
"category": "human",
"verdicts": { "spam": "PASS", "spf": "PASS", "dkim": "PASS", "dmarc": "PASS" },
"attachments": []
}
}
Handling it
The payload carries a snippet, not the body — fetch the email when you need the full content.
if (event.type === "email.received" && event.data.category === "human") {
const email = await aiinbx.emails.retrieve(event.data.email_id)
await queueReply(event.data.thread_id, email.text)
}
Receiving
Getting mail to arrive in the first place — a domain’s MX record, or a connected mailbox.