Appendix — Headers
In one line: every email and HTTP header HIGHFIELD sets or reads, with where and why — because headers are where threading, auth, dedup, and loop-prevention actually live, and they're invisible in a feature description.
Email headers — SET (outbound)
| Header | Where (file:line) | Purpose | Consequence if wrong |
|---|---|---|---|
Auto-Submitted: auto-replied | email-notifications.ts:143 | RFC-3834 — tell recipient's server our mail is automated | Recipient autoresponders could bounce back → loop (inbound guard is the real backstop) |
X-Auto-Response-Suppress: All | email-notifications.ts:144 | Microsoft/Outlook — suppress auto-replies | Cosmetic if ignored |
Precedence: auto_reply | email-notifications.ts:145 | Common bulk/auto marker | Cosmetic if ignored |
inReplyTo / in_reply_to / parentMessageId | email-notifications.ts:125-129 | Threading hint to Lua send-message (multiple guessed field names) | Email arrives unthreaded |
references | email-notifications.ts:130-132 | Full References chain for threading | Email arrives unthreaded |
channelId (LUA_EMAIL_CHANNEL_ID) | email-notifications.ts:108-111 | Route send through property@highfieldproperty.ie | Tenant sees chat@heylua.ai |
Authorization: Bearer <LUA_API_KEY> | email-notifications.ts:153 | Auth to Lua send-message API | 401, email not sent |
Content-Type: application/json | email-notifications.ts:152 | Request body format | API rejects payload |
AgentMail Authorization: Bearer <AGENTMAIL_API_KEY> | agentmail.ts:38 | Auth to AgentMail API | AgentMail call fails |
The synthetic threading Message-IDs that anchor threads (
<ticket-<id>-<party>@highfieldproperty.ie>+ the party's real inbound Message-ID) are computed inemail-thread-anchor.ts(buildSyntheticRoot:42-46,buildThreadAnchor:99-122) and passed intonotifyByEmailasinReplyTo/references. Domain fromEMAIL_THREAD_DOMAIN(defaulthighfieldproperty.ie).
Email headers — READ (inbound)
| Header | Where (file:line) | Purpose | Consequence if wrong |
|---|---|---|---|
from / sender / fromAddress / From | auto-reply-guard.preprocessor.ts:44-45; inbound-email.webhook.ts:57-98 | Identify sender; loop detection | Mis-identify sender → wrong BC lookup / missed loop guard |
Auto-Submitted | auto-reply-detection.ts:49 | Detect automated mail | Reply to a bounce → loop |
X-Auto-Response-Suppress | auto-reply-detection.ts:55 | Detect OOO/auto | Loop risk |
Precedence | auto-reply-detection.ts:61 | Detect bulk/list/auto | Loop risk |
List-Id / List-Unsubscribe / Feedback-ID | auto-reply-detection.ts:67-69 | Detect mailing-list/bulk | Reply to a list → loop/spam |
X-Autoreply / X-Loop | auto-reply-detection.ts:72-75 | Detect autoresponders | Loop risk |
Reply-To / From (address scan) | auto-reply-detection.ts:78 | Detect no-reply/daemon senders | Loop risk |
In-Reply-To / in_reply_to | inbound-email.webhook.ts:134,139; thread-ticket-resolver.ts:39-40 | Bind inbound to a ticket thread | Thread split / wrong-ticket bind (cross-tenant risk) |
References / references | inbound-email.webhook.ts:135-142; thread-ticket-resolver.ts:45-55 | Thread root resolution (tier 3) | Loses thread continuity |
thread_id | inbound-email.webhook.ts:138 | Fallback thread key | Thread split |
Message-ID / message_id / messageId | inbound-email.webhook.ts:57; thread-ticket-resolver.ts:38; current-thread-ticket-injection.preprocessor.ts:353-369 | Stash inbound id for future thread anchoring; thread key of last resort | No future threading for this party |
subject | inbound-email.webhook.ts:57,144; thread-ticket-resolver.ts:42-43 | Extract MT-… id (tier 2), property-from-subject, reply subject | Wrong ticket binding / wrong property routing |
attachments[].content_type / content_disposition / content_id | inbound-email.webhook.ts:212-221,341-344 | Filter images, detect inline vs paperclip, CID cross-check | Missed/dropped images; false "no photo" guidance |
HTTP headers (outbound API requests)
| Header | On | Purpose |
|---|---|---|
Authorization: Bearer <token> | BC standard + custom API | OAuth2 access token from Entra |
Authorization: Bearer <LUA_API_KEY> | Lua send-message | API auth |
Authorization: Bearer <AGENTMAIL_API_KEY> | AgentMail | API auth |
If-Match: <etag> or * | BC PATCH (entity / attachmentContent) | Optimistic concurrency; * used on attachment content because BC mutates internal timestamps on read, staling the etag (bc-client.ts:357-371) |
Content-Type: application/json | all JSON requests | Body format |
HTTP headers (inbound webhook)
The inbound webhooks rely on body/event shape, not header signatures, except:
| Mechanism | Where | Notes |
|---|---|---|
HMAC token in query (?token=) | approval-decision.webhook.ts:21-95 | Not an HTTP header — a signed token param; constant-time verified |
| AgentMail event-shape check | inbound-email.webhook.ts:37-52 | event_type === 'message.received' + message.message_id — no signature verification |
⚠️ No inbound webhook verifies an HTTP signature header. See Security — 9 of 11 webhooks are unauthenticated.