fix: Process non-image inline attachments as regular attachments (#10998)

In Chatwoot, we rely on the Content-ID for inline attachments to replace
the link with the uploaded attachment URL. Our expectation was that only
images would be inline, while other attachments would not. However,
email clients like Apple Mail (sigh) allow users to send inline
attachments that are not images, and these attachments often lack a
Content-ID. This creates significant issues in rendering.
 
I investigated how other email clients handle this scenario. When
viewing the same email (sent from Apple Mail) in Gmail, only one image
appears—and it’s treated as an attachment, not inline. This happens
because both attachments are the same image, and Apple Mail only sends
one copy. See the screenshot below.

| Apple Mail | Gmail | 
| -- | -- | 
| <img width="646" alt="Screenshot 2025-02-27 at 8 20 17 PM"
src="https://github.com/user-attachments/assets/e0d1cd2d-e47c-4081-a53b-7a67106341b3"
/> | <img width="360" alt="Screenshot 2025-02-27 at 8 20 51 PM"
src="https://github.com/user-attachments/assets/b206e56e-8f86-43e9-867b-d895c36aff78"
/> |

A good fix for this would be to check if the Content-ID is missing and
then upload the file as a regular attachment. However, the Mail gem (for
some reason) automatically adds a default Content-ID to inline parts. I
need to dig into the source code to understand why this happens.

For now, I’ve implemented a check to treat non-image attachments as
regular attachments. Inline image attachments are already handled by
appending an image tag at the end if the content-id is not found in the
body. A sample conversation to test this behavior is
[here](https://app.chatwoot.com/app/accounts/1/conversations/46732).
This commit is contained in:
Pranav
2025-02-28 13:33:48 -08:00
committed by GitHub
parent ef24eef0b9
commit 24f49b9b5a
3 changed files with 282 additions and 2 deletions

View File

@@ -59,6 +59,22 @@ RSpec.describe Imap::ImapMailbox do
end
end
context 'when the email has inline attachments other than images' do
let(:inbound_mail) { create_inbound_email_from_fixture('email_with_inline_pdf.eml') }
it 'creates a conversation and a message with non-image files as regular attachments' do
expect do
class_instance.process(inbound_mail.mail, channel)
end.to change(Conversation, :count).by(1)
last_message = conversation.messages.last
expect(last_message.attachments.count).to be 1
attachment = last_message.attachments.first
expect(attachment.file.blob.filename.to_s).to eq 'dummy.pdf'
end
end
context 'when the email has 15 or more attachments' do
let(:inbound_mail) { create_inbound_email_from_fixture('multiple_attachments.eml') }