Fix: html mail fix with html_body content (#4011)
This commit is contained in:
parent
24b20c10ce
commit
5be9380547
7 changed files with 8685 additions and 26 deletions
|
@ -11,45 +11,60 @@ class MailPresenter < SimpleDelegator
|
||||||
encode_to_unicode(@mail.subject)
|
encode_to_unicode(@mail.subject)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# encode decoded mail text_part or html_part if mail is multipart email
|
||||||
|
# encode decoded mail raw bodyt if mail is not multipart email but the body content is text/html
|
||||||
|
def mail_content(mail_part)
|
||||||
|
if multipart_mail_body?
|
||||||
|
decoded_multipart_mail(mail_part)
|
||||||
|
else
|
||||||
|
text_html_mail(mail_part)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# encodes mail if mail.parts is present
|
||||||
|
# encodes mail content type is multipart
|
||||||
|
def decoded_multipart_mail(mail_part)
|
||||||
|
encoded = encode_to_unicode(mail_part&.decoded)
|
||||||
|
|
||||||
|
encoded if text_mail_body? || html_mail_body?
|
||||||
|
end
|
||||||
|
|
||||||
|
# encodes mail raw body if mail.parts is empty
|
||||||
|
# encodes mail raw body if mail.content_type is plain/text
|
||||||
|
# encodes mail raw body if mail.content_type is html/text
|
||||||
|
def text_html_mail(mail_part)
|
||||||
|
decoded = mail_part&.decoded || @mail.body&.decoded
|
||||||
|
encoded = encode_to_unicode(decoded)
|
||||||
|
|
||||||
|
encoded if html_mail_body? || text_mail_body?
|
||||||
|
end
|
||||||
|
|
||||||
def text_content
|
def text_content
|
||||||
@decoded_text_content = select_body(text_part) || ''
|
@decoded_text_content = mail_content(text_part) || ''
|
||||||
|
|
||||||
encoding = @decoded_text_content.encoding
|
encoding = @decoded_text_content.encoding
|
||||||
|
|
||||||
body = EmailReplyTrimmer.trim(@decoded_text_content)
|
body = EmailReplyTrimmer.trim(@decoded_text_content)
|
||||||
|
|
||||||
return {} if @decoded_text_content.blank?
|
return {} if @decoded_text_content.blank? || !text_mail_body?
|
||||||
|
|
||||||
@text_content ||= {
|
@text_content ||= {
|
||||||
full: select_body(text_part),
|
full: mail_content(text_part),
|
||||||
reply: @decoded_text_content,
|
reply: @decoded_text_content,
|
||||||
quoted: body.force_encoding(encoding).encode('UTF-8')
|
quoted: body.force_encoding(encoding).encode('UTF-8')
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
# returns encoded mail body text_part if available.
|
|
||||||
# returns encoded mail body as it is if mail_part not available.
|
|
||||||
# else returns parsed the html body if contains text/html content.
|
|
||||||
def select_body(mail_part)
|
|
||||||
return encoded_mail_body unless mail_part
|
|
||||||
|
|
||||||
decoded = encode_to_unicode(mail_part.decoded)
|
|
||||||
|
|
||||||
if mail.text_part
|
|
||||||
decoded
|
|
||||||
elsif html_mail_body?
|
|
||||||
::HtmlParser.parse_reply(decoded)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def html_content
|
def html_content
|
||||||
@decoded_html_content = select_body(html_part) || ''
|
encoded = mail_content(html_part) || ''
|
||||||
|
@decoded_html_content = ::HtmlParser.parse_reply(encoded)
|
||||||
|
|
||||||
return {} if @decoded_html_content.blank?
|
return {} if @decoded_html_content.blank? || !html_mail_body?
|
||||||
|
|
||||||
body = EmailReplyTrimmer.trim(@decoded_html_content)
|
body = EmailReplyTrimmer.trim(@decoded_html_content)
|
||||||
|
|
||||||
@html_content ||= {
|
@html_content ||= {
|
||||||
full: select_body(html_part),
|
full: mail_content(html_part),
|
||||||
reply: @decoded_html_content,
|
reply: @decoded_html_content,
|
||||||
quoted: body
|
quoted: body
|
||||||
}
|
}
|
||||||
|
@ -131,13 +146,14 @@ class MailPresenter < SimpleDelegator
|
||||||
end
|
end
|
||||||
|
|
||||||
def html_mail_body?
|
def html_mail_body?
|
||||||
((mail.content_type || '').include? 'text/html') || @mail.html_part || @mail.html_part.content_type.include?('text/html')
|
((mail.content_type || '').include? 'text/html') || @mail.html_part&.content_type&.include?('text/html')
|
||||||
end
|
end
|
||||||
|
|
||||||
# returns mail body if mail content_type is text/plain
|
def text_mail_body?
|
||||||
def encoded_mail_body
|
((mail.content_type || '').include? 'text/plain') || @mail.text_part&.content_type&.include?('text/plain')
|
||||||
return encode_to_unicode(@mail.body.decoded) if (@mail.content_type || '').include? 'text/plain'
|
end
|
||||||
|
|
||||||
''
|
def multipart_mail_body?
|
||||||
|
((mail.content_type || '').include? 'multipart') || @mail.parts.any?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
3862
spec/fixtures/files/html_and_attachments.eml
vendored
Normal file
3862
spec/fixtures/files/html_and_attachments.eml
vendored
Normal file
File diff suppressed because it is too large
Load diff
4548
spec/fixtures/files/only_attachments.eml
vendored
Normal file
4548
spec/fixtures/files/only_attachments.eml
vendored
Normal file
File diff suppressed because it is too large
Load diff
19
spec/fixtures/files/only_html.eml
vendored
Normal file
19
spec/fixtures/files/only_html.eml
vendored
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
Date: Wed, 23 Feb 2022 12:11:27 +0530
|
||||||
|
From: tejaswini@ex.com
|
||||||
|
To: care@example.com
|
||||||
|
Message-ID: <6215d71711c38_10bc61914022323@tejaswinis-MacBook-Pro.local.mail>
|
||||||
|
In-Reply-To:
|
||||||
|
Subject: test html only mail
|
||||||
|
Mime-Version: 1.0
|
||||||
|
Content-Type: text/html;
|
||||||
|
charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
x-original-to:
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<h1>
|
||||||
|
This is html only mail
|
||||||
|
</h1>
|
||||||
|
</body>
|
||||||
|
</html>
|
13
spec/fixtures/files/only_text.eml
vendored
Normal file
13
spec/fixtures/files/only_text.eml
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
Date: Wed, 23 Feb 2022 13:14:10 +0530
|
||||||
|
From: text@example.com
|
||||||
|
To: care@example.com
|
||||||
|
Message-ID: <6215e5ca3e3b2_10bc6197e4224d1@tejaswinis-MacBook-Pro.local.mail>
|
||||||
|
In-Reply-To:
|
||||||
|
Subject: test text only mail
|
||||||
|
Mime-Version: 1.0
|
||||||
|
Content-Type: text/plain;
|
||||||
|
charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
x-original-to:
|
||||||
|
|
||||||
|
text only mail
|
131
spec/fixtures/files/support_1.eml
vendored
Normal file
131
spec/fixtures/files/support_1.eml
vendored
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
Date: Fri, 11 Feb 2022 05:15:51 +0000
|
||||||
|
Mime-Version: 1.0
|
||||||
|
Subject: Get Paid to post an article
|
||||||
|
From: sony@chatwoot.com
|
||||||
|
To: care@example.com
|
||||||
|
X-Mailgun-Tag: test1
|
||||||
|
X-Mailgun-Track-Clicks: true
|
||||||
|
X-Mailgun-Track: true
|
||||||
|
X-Mailgun-Track-Opens: true
|
||||||
|
Message-Id: <20220211051551.0ac6490aa10da09b@chatwoot.com>
|
||||||
|
Content-Type: text/html; charset="ascii"
|
||||||
|
Content-Transfer-Encoding: quoted-printable
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title></title>
|
||||||
|
<meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3Dutf-8=
|
||||||
|
" />
|
||||||
|
<meta name=3D"viewport" content=3D"width=3Ddevice-width, initial-scale=
|
||||||
|
=3D1">
|
||||||
|
<meta http-equiv=3D"X-UA-Compatible" content=3D"IE=3Dedge" />
|
||||||
|
<style type=3D"text/css">
|
||||||
|
@media screen {
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Lato';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
src: local('Lato Regular'), local('Lato-Regular'), url(http=
|
||||||
|
s://fonts.gstatic.com/s/lato/v11/qIIYRU-oROkIk8vfvxw6QvesZW2xOQ-xsNqO47m55D=
|
||||||
|
A.woff) format('woff');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Lato';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
src: local('Lato Bold'), local('Lato-Bold'), url(https://fo=
|
||||||
|
nts.gstatic.com/s/lato/v11/qdgUG4U09HnJwhYI-uK18wLUuEpTyoUstqEm5AMlJo4.woff=
|
||||||
|
) format('woff');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Lato';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 400;
|
||||||
|
src: local('Lato Italic'), local('Lato-Italic'), url(https:=
|
||||||
|
//fonts.gstatic.com/s/lato/v11/RYyZNoeFgb0l7W3Vu1aSWOvvDin1pK8aKteLpeZ5c0A.=
|
||||||
|
woff) format('woff');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Lato';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 700;
|
||||||
|
src: local('Lato Bold Italic'), local('Lato-BoldItalic'), u=
|
||||||
|
rl(https://fonts.gstatic.com/s/lato/v11/HkF_qI1x_noxlxhrhMQYELO3LdcAZYWl9Si=
|
||||||
|
6vvxL-qU.woff) format('woff');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* CLIENT-SPECIFIC STYLES */
|
||||||
|
body,
|
||||||
|
table,
|
||||||
|
td,
|
||||||
|
a {
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
-ms-text-size-adjust: 100%;
|
||||||
|
}
|
||||||
|
table,
|
||||||
|
td {
|
||||||
|
mso-table-lspace: 0pt;
|
||||||
|
mso-table-rspace: 0pt;
|
||||||
|
}
|
||||||
|
td{
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
-ms-interpolation-mode: bicubic;
|
||||||
|
}
|
||||||
|
/* RESET STYLES */
|
||||||
|
img {
|
||||||
|
border: 0;
|
||||||
|
height: auto;
|
||||||
|
line-height: 100%;
|
||||||
|
outline: none;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
border-collapse: collapse !important;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
height: 100% !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
width: 100% !important;
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
/* iOS BLUE LINKS */
|
||||||
|
a[x-apple-data-detectors] {
|
||||||
|
color: inherit !important;
|
||||||
|
text-decoration: none !important;
|
||||||
|
font-size: inherit !important;
|
||||||
|
font-family: inherit !important;
|
||||||
|
font-weight: inherit !important;
|
||||||
|
line-height: inherit !important;
|
||||||
|
}
|
||||||
|
/* MOBILE STYLES */
|
||||||
|
@media screen and (max-width:600px) {
|
||||||
|
h1 {
|
||||||
|
font-size: 32px !important;
|
||||||
|
line-height: 32px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* ANDROID CENTER FIX */
|
||||||
|
div[style*=3D"margin: 16px 0;"] {
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
Hi,<br /><br />We are providing you platform from here you can sell =
|
||||||
|
paid posts on your website.
|
||||||
|
|
||||||
|
<div style=3D'width:100%'><p>Chatwoot | CS team | <a href=3D"https://d33wubrfki0l68.cloudfront.net/973467c532160fd8b940300a43fa85fa2d060307/dc9a0/static/brand-73f58cdefae282ae74cebfa74c1d7003.svg">C</hatwoota></p>
|
||||||
|
<p>Skype: live:.cid.something</p>
|
||||||
|
</d=
|
||||||
|
iv>
|
||||||
|
</div>
|
||||||
|
<img width=3D"1px" height=3D"1px" alt=3D"" src=3D"https://d33wubrfki0l68.cloudfront.net/973467c532160fd8b940300a43fa85fa2d060307/dc9a0/static/brand-73f58cdefae282ae74cebfa74c1d7003.svg"></=
|
||||||
|
body>
|
||||||
|
|
||||||
|
</html>
|
|
@ -175,5 +175,75 @@ RSpec.describe SupportMailbox, type: :mailbox do
|
||||||
expect(reply_to_mail.mail['From'].value).not_to include(conversation_1.contact.email)
|
expect(reply_to_mail.mail['From'].value).not_to include(conversation_1.contact.email)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'when mail part is not present' do
|
||||||
|
let(:support_mail) { create_inbound_email_from_fixture('support_1.eml') }
|
||||||
|
let(:only_text) { create_inbound_email_from_fixture('only_text.eml') }
|
||||||
|
let(:only_html) { create_inbound_email_from_fixture('only_html.eml') }
|
||||||
|
let(:only_attachments) { create_inbound_email_from_fixture('only_attachments.eml') }
|
||||||
|
let(:html_and_attachments) { create_inbound_email_from_fixture('html_and_attachments.eml') }
|
||||||
|
let(:described_subject) { described_class.receive support_mail }
|
||||||
|
|
||||||
|
it 'Considers raw html mail body' do
|
||||||
|
described_subject
|
||||||
|
expect(conversation.inbox.id).to eq(channel_email.inbox.id)
|
||||||
|
|
||||||
|
expect(conversation.messages.last.content_attributes['email']['html_content']['reply']).to include(
|
||||||
|
<<-BODY.strip_heredoc.chomp
|
||||||
|
Hi,
|
||||||
|
We are providing you platform from here you can sell paid posts on your website.
|
||||||
|
|
||||||
|
Chatwoot | CS team | [C](https://d33wubrfki0l68.cloudfront.net/973467c532160fd8b940300a43fa85fa2d060307/dc9a0/static/brand-73f58cdefae282ae74cebfa74c1d7003.svg)
|
||||||
|
|
||||||
|
Skype: live:.cid.something
|
||||||
|
|
||||||
|
[]
|
||||||
|
BODY
|
||||||
|
)
|
||||||
|
expect(conversation.messages.last.content_attributes['email']['subject']).to eq('Get Paid to post an article')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Considers only text body' do
|
||||||
|
described_class.receive only_text
|
||||||
|
|
||||||
|
expect(conversation.inbox.id).to eq(channel_email.inbox.id)
|
||||||
|
|
||||||
|
expect(conversation.messages.last.content).to eq('text only mail')
|
||||||
|
expect(conversation.messages.last.content_attributes['email']['subject']).to eq('test text only mail')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Considers only html body' do
|
||||||
|
described_class.receive only_html
|
||||||
|
|
||||||
|
expect(conversation.inbox.id).to eq(channel_email.inbox.id)
|
||||||
|
|
||||||
|
expect(conversation.messages.last.content).to eq(
|
||||||
|
<<-BODY.strip_heredoc.chomp
|
||||||
|
This is html only mail
|
||||||
|
BODY
|
||||||
|
)
|
||||||
|
expect(conversation.messages.last.content_attributes['email']['subject']).to eq('test html only mail')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Considers only attachments' do
|
||||||
|
described_class.receive only_attachments
|
||||||
|
|
||||||
|
expect(conversation.inbox.id).to eq(channel_email.inbox.id)
|
||||||
|
|
||||||
|
expect(conversation.messages.last.content).to eq(nil)
|
||||||
|
expect(conversation.messages.last.attachments.count).to eq(1)
|
||||||
|
expect(conversation.messages.last.content_attributes['email']['subject']).to eq('only attachments')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Considers html and attachments' do
|
||||||
|
described_class.receive html_and_attachments
|
||||||
|
|
||||||
|
expect(conversation.inbox.id).to eq(channel_email.inbox.id)
|
||||||
|
|
||||||
|
expect(conversation.messages.last.content).to eq('This is html and attachments only mail')
|
||||||
|
expect(conversation.messages.last.attachments.count).to eq(1)
|
||||||
|
expect(conversation.messages.last.content_attributes['email']['subject']).to eq('attachment with html')
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue