Reputation: 1581
I am using Action Mailbox, to receive emails in my Rails application. When the emails contain images, I am not sure, how to save the email in the database, decode it, and then display it to the user so that it can be displayed like how we see emails in gmail etc.
I have used this code-
class MyMailbox < ApplicationMailbox
def process
mail_content = mail.body.decoded
post = Post.new(title: mail.subject, content: mail_content)
post.save
end
end
This works well for emails which don't have any images etc. But I want a way to save emails with images. This is apparently to be done by using the different parts of the multipart email, but i am not sure how to proceed.
Finally, I want to display those emails with original look. Let me know how to proceed here. Thanks.
Upvotes: 2
Views: 744
Reputation: 2735
Before you attempt to handle images in the body of an email, you should first check if the email body is multipart or not:
# handle multipart message
body = mail.parts.present? ? mail.parts[0].body.decoded : mail.decoded
What does a multipart email look like? Something like this:
MIME-Version: 1.0
Date: Mon, 8 Nov 2021 19:43:58 +0100
References: <....mail>
In-Reply-To: <....mail>
Message-ID: <[email protected]>
Subject: Re: Howdy
From: You <[email protected]>
To: Me <[email protected]>
Content-Type: multipart/alternative; boundary="000000000000376c4305d04b60e2"
--000000000000376c4305d04b60e2
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
Here is my reply to an original message.
--000000000000376c4305d04b60e2
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div>
<img src=3D"https://placeholder.img" />
<img src=3D"https://placeholder.img" />
</div>
--000000000000376c4305d04b60e2--
Note that the Content-Type header of the email contains a boundary which is used to separate the email parts. Now that you can see how each part can be a different content type, you have the proper context to understand how to parse each part.
https://github.com/mikel/mail#reading-a-multipart-email
Rails uses the mail
gem, so you should reference their docs to understand full functionality. But in short, you can do the following:
if mail.parts.present? && mail.parts[0].content_type == 'text/html'
sanitized = Rails::Html::WhiteListSanitizer.new.sanitize(mail.parts[0], tags: ['img'])
# => "\n <img src=\"https://placeholder.img\">\n <img src=\"https://placeholder.img\">\n\n"
html_doc = Nokogiri::HTML(sanitized)
html_doc.to_s
# => "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/REC-html40/loose.dtd\">\n<html><body>\n<img src=\"https://placeholder.img\">\n <img src=\"https://placeholder.img\">\n</body></html>\n"
end
To display the original content of the message, just save the part in its entirety. You'll have to either infer the content type store it alongside the message in your database.
Assuming you're saving an HTML message, you can use Nokogiri, which comes with Rails, to generate an HTML document.
Upvotes: 1