Skip to content

Forward email to external recipient#296

Open
mageaustralia wants to merge 1 commit intoabhinavxd:mainfrom
mageaustralia:feat/forward-message
Open

Forward email to external recipient#296
mageaustralia wants to merge 1 commit intoabhinavxd:mainfrom
mageaustralia:feat/forward-message

Conversation

@mageaustralia
Copy link
Copy Markdown

Summary

End-to-end "forward this email" feature with internal-thread filtering so back-and-forth with a forwarded recipient never leaks into customer-facing replies.

Backend

  • New forwarded_to field on the send-message request. When set, the message is routed to those addresses instead of the conversation contact; CC/BCC pass through unchanged so an agent can loop in internal teammates on the forward.
  • At SMTP send: forwards strip In-Reply-To/References so the recipient sees a fresh thread, and prepend Fwd: to the subject (idempotent).
  • Activity-note records who forwarded to whom.
  • New is-source-id-from-forward SQL + intake hook: any incoming message whose In-Reply-To/References point at a previously-sent forward (or an already-tagged reply chain) gets meta.from_forward = true. Empty source-IDs are filtered before the lookup; the from_forward check uses jsonb @> '...' containment so it never throws on unexpected meta shapes.

Frontend

  • Per-message Forward button on email-channel, non-private bubbles.
  • ReplyBox listens for the forward event (via onMounted/onBeforeUnmount with matching .off), switches into a new forward mode, pre-quotes the original message, and clears recipient fields.
  • The Forward tab is only visible while in forward mode (no orphan tab in normal use).
  • Switching conversations or tabs out of forward resets the pre-quoted body and recipient fields so a stale forward can't be accidentally sent into a different conversation.
  • Forward-related bubbles (outgoing forward + incoming reply-to-forward) share the private-note bubble color so the internal thread groups visually distinct from customer-facing messages.
  • Small "Forwarded to:" badge on outgoing forwards and "Reply to forward (internal)" badge on tagged incoming.

Pairs especially well with #289 (CID inline-image embed) — without that PR, forwarded inline images use signed URLs that expire ~1 hour later. This PR works without #289 but with that lifetime caveat.

Test plan

  • Open an email conversation, hover any non-private message → small Forward link appears under the bubble
  • Click Forward → reply box switches to forward mode, third tab visible, TO/CC/BCC empty, editor pre-populated with ---- Forwarded message ---- From: ... Date: ... + the original body
  • Type an external recipient in TO + optional CC, send → outgoing email has Fwd: <subject>, no In-Reply-To, recipients include CC; bubble shows in cream bg-private color with "Forwarded to: ..." badge
  • When the forwarded recipient replies (via IMAP): their reply lands in the same conversation, bubble is also in cream, with "Reply to forward (internal)" badge underneath
  • Switch to that conversation's reply tab and reply to the customer → the auto-quoted thread does not include the internal forward exchange
  • Switch conversations mid-forward → forward state resets, no stale pre-quoted body in the new conversation
  • Switch tabs from Forward to Reply mid-forward → editor resets, recipient fields clear

Adds an end-to-end "forward this email" feature with internal-thread
filtering so back-and-forth with the forwarded recipient never leaks
into customer-facing replies.

Backend
- New `forwarded_to` field on the send-message request. When non-empty
  the message is routed to those addresses instead of the conversation
  contact; CC/BCC pass through unchanged so an agent can loop in
  internal teammates.
- At SMTP send: forwards strip In-Reply-To/References so the recipient
  sees a fresh thread, and prepend "Fwd: " to the subject (idempotent).
- Activity-note logging records who forwarded to whom.
- New `is-source-id-from-forward` SQL + intake hook: any incoming
  message whose In-Reply-To/References point at a previously-sent
  forward (or already-tagged reply chain) gets `meta.from_forward = true`.
  Empty source-IDs are filtered out before the lookup.

Frontend
- Per-message Forward button on email-channel, non-private bubbles.
- ReplyBox listens for the forward event (via lifecycle hooks, with
  matching .off on unmount), switches into a new `forward` mode,
  pre-quotes the original message, and clears recipient fields.
- Forward tab is only visible while in forward mode.
- Switching conversations or tabs out of `forward` resets the
  pre-quoted body and recipient fields so a stale forward can't be
  accidentally sent into a different conversation.
- Forward-related bubbles (outgoing forward + incoming reply-to-forward)
  share the private-note bubble color so the internal thread groups
  visually distinct from customer-facing messages.
- Small "Forwarded to:" badge on outgoing forwards and "Reply to
  forward (internal)" badge on tagged incoming.
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