Skip to content

feat(email): add Message_Id_Util for RFC 5322 threading + signed Reply-To#31

Open
mpge wants to merge 1 commit intomainfrom
feat/email-message-id
Open

feat(email): add Message_Id_Util for RFC 5322 threading + signed Reply-To#31
mpge wants to merge 1 commit intomainfrom
feat/email-message-id

Conversation

@mpge
Copy link
Copy Markdown
Member

@mpge mpge commented Apr 24, 2026

Summary

Ports the NestJS email/message-id.ts helpers to WordPress. Coexists with the existing Email_Threading class during the migration window — new outbound paths should prefer this util so inbound Reply-To verification has something to check against.

API

  • build_message_id(ticket_id, reply_id, domain)
  • parse_ticket_id_from_message_id(raw)
  • build_reply_to(ticket_id, secret, domain)
  • verify_reply_to(address, secret)

Uses hash_hmac('sha256', ...) + hash_equals for timing-safe verification.

Why signed Reply-To

The 8-char HMAC-SHA256 prefix on the Reply-To local part means even clients that strip our Message-ID / In-Reply-To headers still route replies back to the right ticket — the inbound provider webhook can verify the prefix before routing.

Design divergence note

The existing Email_Threading class emits Message-IDs in a different shape: reply-{id}-ticket-{reference}@{domain} (uses reference, not id). This util uses the NestJS-compatible shape. Follow-up PR will migrate Email_Threading so inbound routing can use a single format.

Test plan

  • 13 PHPUnit tests covering round-trip, tamper rejection, case-insensitive hex, malformed input, local-part-only acceptance
  • CI green: test (8.1), test (8.2), lint

Ports the NestJS email/message-id.ts helpers to WordPress. Coexists
with the existing Email_Threading class during the migration window —
new outbound paths should prefer this util so inbound Reply-To
verification has something to check against.

API:
  build_message_id(ticket_id, reply_id, domain)
  parse_ticket_id_from_message_id(raw)
  build_reply_to(ticket_id, secret, domain)
  verify_reply_to(address, secret)

Uses hash_hmac('sha256', ...) + hash_equals for timing-safe verification.

Pure functions, no WP test harness — 13 unit tests covering round-trip,
tamper rejection, case-insensitive hex, malformed input, and the
local-part-only acceptance path.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant