From 02ab856520e7246cbfbaede557601e0adb3e64a3 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Wed, 7 Jan 2026 12:45:54 +0530 Subject: [PATCH] feat(CW-6187): include headers from incoming emails (#13139) --- app/presenters/mail_presenter.rb | 11 +++++++++ spec/mailboxes/reply_mailbox_spec.rb | 6 ++--- spec/presenters/mail_presenter_spec.rb | 34 ++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/app/presenters/mail_presenter.rb b/app/presenters/mail_presenter.rb index 202c255a1..08e370cd8 100644 --- a/app/presenters/mail_presenter.rb +++ b/app/presenters/mail_presenter.rb @@ -95,6 +95,7 @@ class MailPresenter < SimpleDelegator content_type: content_type, date: date, from: from, + headers: headers_data, html_content: html_content, in_reply_to: in_reply_to, message_id: message_id, @@ -136,6 +137,16 @@ class MailPresenter < SimpleDelegator from_email_address(@mail[:reply_to].try(:value)) || @mail['X-Original-Sender'].try(:value) || from_email_address(from.first) end + def headers_data + headers = { + 'x-original-from' => @mail['X-Original-From']&.value, + 'x-original-sender' => @mail['X-Original-Sender']&.value, + 'x-forwarded-for' => @mail['X-Forwarded-For']&.value + }.compact + + headers.presence + end + def from_email_address(email) Mail::Address.new(email).address end diff --git a/spec/mailboxes/reply_mailbox_spec.rb b/spec/mailboxes/reply_mailbox_spec.rb index 2658731bc..d062c7d73 100644 --- a/spec/mailboxes/reply_mailbox_spec.rb +++ b/spec/mailboxes/reply_mailbox_spec.rb @@ -12,8 +12,8 @@ RSpec.describe ReplyMailbox do let(:conversation) { create(:conversation, assignee: agent, inbox: create(:inbox, account: account, greeting_enabled: false), account: account) } let(:described_subject) { described_class.receive reply_mail } let(:serialized_attributes) do - %w[bcc cc content_type date from html_content in_reply_to message_id multipart number_of_attachments references subject text_content to - auto_reply] + %w[bcc cc content_type date from headers html_content in_reply_to message_id multipart number_of_attachments references subject text_content + to auto_reply] end context 'with reply uuid present' do @@ -397,7 +397,7 @@ RSpec.describe ReplyMailbox do let(:support_in_reply_to_mail) { create_inbound_email_from_fixture('support_in_reply_to.eml') } let(:described_subject) { described_class.receive support_mail } let(:serialized_attributes) do - %w[bcc cc content_type date from html_content in_reply_to message_id multipart number_of_attachments references subject + %w[bcc cc content_type date from headers html_content in_reply_to message_id multipart number_of_attachments references subject text_content to auto_reply] end let(:conversation) { Conversation.where(inbox_id: channel_email.inbox).last } diff --git a/spec/presenters/mail_presenter_spec.rb b/spec/presenters/mail_presenter_spec.rb index b9b23c8ce..bbe51c52d 100644 --- a/spec/presenters/mail_presenter_spec.rb +++ b/spec/presenters/mail_presenter_spec.rb @@ -41,6 +41,7 @@ RSpec.describe MailPresenter do :content_type, :date, :from, + :headers, :html_content, :in_reply_to, :message_id, @@ -60,6 +61,39 @@ RSpec.describe MailPresenter do expect(data[:auto_reply]).to eq(decorated_mail.auto_reply?) end + it 'includes forwarded headers in serialized_data' do + mail_with_headers = Mail.new do + from 'Sender ' + to 'Inbox ' + subject :header + body 'Hi' + header['X-Original-From'] = 'Original ' + header['X-Original-Sender'] = 'original@example.com' + header['X-Forwarded-For'] = 'forwarder@example.com' + end + + data = described_class.new(mail_with_headers).serialized_data + + expect(data[:headers]).to eq( + 'x-original-from' => 'Original ', + 'x-original-sender' => 'original@example.com', + 'x-forwarded-for' => 'forwarder@example.com' + ) + end + + it 'returns nil headers when forwarding headers are missing' do + mail_without_headers = Mail.new do + from 'Sender ' + to 'Inbox ' + subject :header + body 'Hi' + end + + data = described_class.new(mail_without_headers).serialized_data + + expect(data[:headers]).to be_nil + end + it 'give email from in downcased format' do expect(decorated_mail.from.first.eql?(mail.from.first.downcase)).to be true end