Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Use BODY.PEEK[HEADER] to avoid parsing issues with mail providers #8833

Merged
merged 6 commits into from
Feb 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 8 additions & 7 deletions app/jobs/inboxes/fetch_imap_emails_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ def process_message_id(channel, imap_client, message_id_with_seq)

return if email_already_present?(channel, message_id)

if message_id.blank?
Rails.logger.info "[IMAP::FETCH_EMAIL_SERVICE] Empty message id for #{channel.email} with seq no. <#{seq_no}>."
return
end

# Fetch the original mail content using the sequence no
mail_str = imap_client.fetch(seq_no, 'RFC822')[0].attr['RFC822']

Expand All @@ -74,7 +79,7 @@ def fetch_message_ids_with_sequence(imap_client, channel)
message_ids_with_seq = []
seq_nums.each_slice(10).each do |batch|
# Fetch only message-id only without mail body or contents.
batch_message_ids = imap_client.fetch(batch, 'BODY.PEEK[HEADER.FIELDS (MESSAGE-ID)]')
batch_message_ids = imap_client.fetch(batch, 'BODY.PEEK[HEADER]')

# .fetch returns an array of Net::IMAP::FetchData or nil
# (instead of an empty array) if there is no matching message.
Expand All @@ -85,7 +90,7 @@ def fetch_message_ids_with_sequence(imap_client, channel)
end

batch_message_ids.each do |data|
message_id = build_mail_from_string(data.attr['BODY[HEADER.FIELDS (MESSAGE-ID)]']).message_id
message_id = build_mail_from_string(data.attr['BODY[HEADER]']).message_id
message_ids_with_seq.push([data.seqno, message_id])
end
end
Expand All @@ -97,7 +102,7 @@ def fetch_message_ids_with_sequence(imap_client, channel)
# created between yesterday and today and returns message sequence numbers.
# Return <message set>
def fetch_available_mail_sequence_numbers(imap_client)
imap_client.search(['BEFORE', tomorrow, 'SINCE', yesterday])
imap_client.search(['SINCE', yesterday])
end

def fetch_mail_for_ms_provider(channel)
Expand Down Expand Up @@ -161,8 +166,4 @@ def valid_access_token(channel)
def yesterday
(Time.zone.today - 1).strftime('%d-%b-%Y')
end

def tomorrow
(Time.zone.today + 1).strftime('%d-%b-%Y')
end
end
1 change: 1 addition & 0 deletions spec/fixtures/files/mail_with_no_date.eml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ Date:
From: testemail@gmail.com
To: imap@outlook.com
Subject: test text only mail
Message-Id: <0CB459E0-0336-41DA-BC88-E6E28C697DDB@chatwoot.com>

text only mail
21 changes: 7 additions & 14 deletions spec/jobs/inboxes/fetch_imap_emails_job_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
let(:ms_email_inbox) { create(:inbox, channel: microsoft_imap_email_channel, account: account) }
let!(:conversation) { create(:conversation, inbox: imap_email_channel.inbox, account: account) }
let(:inbound_mail) { create_inbound_email_from_mail(from: 'testemail@gmail.com', to: 'imap@outlook.com', subject: 'Hello!') }
let(:inbound_mail_with_no_date) { create_inbound_email_from_fixture('mail_with_no_date.eml') }
let(:inbound_mail_with_attachments) { create_inbound_email_from_fixture('multiple_attachments.eml') }

it 'enqueues the job' do
Expand Down Expand Up @@ -53,25 +52,19 @@
end

it 'process the email with no date' do
email = Mail.new do
to 'test@outlook.com'
from 'test@gmail.com'
subject :test.to_s
body 'hello'
end

imap_fetch_mail = Net::IMAP::FetchData.new
imap_fetch_mail.attr = { seqno: 1, RFC822: email }.with_indifferent_access
fixture_path = Rails.root.join('spec/fixtures/files/mail_with_no_date.eml')
eml_content = File.read(fixture_path)
inbound_mail_with_no_date = create_inbound_email_from_fixture('mail_with_no_date.eml')
email_header = Net::IMAP::FetchData.new(1, 'BODY[HEADER]' => eml_content)
imap_fetch_mail = Net::IMAP::FetchData.new(1, 'RFC822' => eml_content)

imap = double

allow(Net::IMAP).to receive(:new).and_return(imap)
allow(imap).to receive(:authenticate)
allow(imap).to receive(:select)
allow(imap).to receive(:search).and_return([1])
allow(imap).to receive(:fetch).and_return([imap_fetch_mail])

allow(Mail).to receive(:read_from_string).and_return(inbound_mail_with_no_date.mail)
allow(imap).to receive(:fetch).with([1], 'BODY.PEEK[HEADER]').and_return([email_header])
pranavrajs marked this conversation as resolved.
Show resolved Hide resolved
allow(imap).to receive(:fetch).with(1, 'RFC822').and_return([imap_fetch_mail])

imap_mailbox = double

Expand Down