feat: Add support for HTML emails in outgoing messages (#12662)
This PR adds sending custom HTML content in outgoing email messages
through Chatwoot's Email channels, while maintaining backward
compatibility with existing markdown rendering.
### API Usage
**Endpoint:** `POST
/api/v1/accounts/{account_id}/conversations/{conversation_id}/messages`
```json
{
"content": "Fallback text content",
"email_html_content": "<div><h1>Welcome!</h1><p>This is <strong>custom HTML</strong></p></div>"
}
```
---------
Co-authored-by: Muhsin <muhsinkeramam@gmail.com>
This commit is contained in:
@@ -335,6 +335,118 @@ RSpec.describe ConversationReplyMailer do
|
||||
expect(mail.body.encoded).not_to match(%r{<a [^>]*>avatar\.png</a>})
|
||||
end
|
||||
end
|
||||
|
||||
context 'with custom email content' do
|
||||
it 'uses custom HTML content when available and creates multipart email' do
|
||||
message_with_custom_content = create(:message,
|
||||
conversation: conversation,
|
||||
account: account,
|
||||
message_type: 'outgoing',
|
||||
content: 'Regular message content',
|
||||
content_attributes: {
|
||||
email: {
|
||||
html_content: {
|
||||
reply: '<p>Custom <strong>HTML</strong> content for email</p>'
|
||||
},
|
||||
text_content: {
|
||||
reply: 'Custom text content for email'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
mail = described_class.email_reply(message_with_custom_content).deliver_now
|
||||
|
||||
# Check HTML part contains custom HTML content
|
||||
html_part = mail.html_part || mail
|
||||
expect(html_part.body.encoded).to include('<p>Custom <strong>HTML</strong> content for email</p>')
|
||||
expect(html_part.body.encoded).not_to include('Regular message content')
|
||||
|
||||
# Check text part contains custom text content
|
||||
text_part = mail.text_part
|
||||
if text_part
|
||||
expect(text_part.body.encoded).to include('Custom text content for email')
|
||||
expect(text_part.body.encoded).not_to include('Regular message content')
|
||||
end
|
||||
end
|
||||
|
||||
it 'falls back to markdown rendering when custom HTML content is not available' do
|
||||
message_without_custom_content = create(:message,
|
||||
conversation: conversation,
|
||||
account: account,
|
||||
message_type: 'outgoing',
|
||||
content: 'Regular **markdown** content')
|
||||
|
||||
mail = described_class.email_reply(message_without_custom_content).deliver_now
|
||||
|
||||
html_part = mail.html_part || mail
|
||||
expect(html_part.body.encoded).to include('<strong>markdown</strong>')
|
||||
expect(html_part.body.encoded).to include('Regular')
|
||||
end
|
||||
|
||||
it 'handles empty custom HTML content gracefully' do
|
||||
message_with_empty_content = create(:message,
|
||||
conversation: conversation,
|
||||
account: account,
|
||||
message_type: 'outgoing',
|
||||
content: 'Regular **markdown** content',
|
||||
content_attributes: {
|
||||
email: {
|
||||
html_content: {
|
||||
reply: ''
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
mail = described_class.email_reply(message_with_empty_content).deliver_now
|
||||
|
||||
html_part = mail.html_part || mail
|
||||
expect(html_part.body.encoded).to include('<strong>markdown</strong>')
|
||||
expect(html_part.body.encoded).to include('Regular')
|
||||
end
|
||||
|
||||
it 'handles nil custom HTML content gracefully' do
|
||||
message_with_nil_content = create(:message,
|
||||
conversation: conversation,
|
||||
account: account,
|
||||
message_type: 'outgoing',
|
||||
content: 'Regular **markdown** content',
|
||||
content_attributes: {
|
||||
email: {
|
||||
html_content: {
|
||||
reply: nil
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
mail = described_class.email_reply(message_with_nil_content).deliver_now
|
||||
|
||||
expect(mail.body.encoded).to include('<strong>markdown</strong>')
|
||||
expect(mail.body.encoded).to include('Regular')
|
||||
end
|
||||
|
||||
it 'uses custom text content in text part when only text is provided' do
|
||||
message_with_text_only = create(:message,
|
||||
conversation: conversation,
|
||||
account: account,
|
||||
message_type: 'outgoing',
|
||||
content: 'Regular message content',
|
||||
content_attributes: {
|
||||
email: {
|
||||
text_content: {
|
||||
reply: 'Custom text content only'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
mail = described_class.email_reply(message_with_text_only).deliver_now
|
||||
|
||||
text_part = mail.text_part
|
||||
if text_part
|
||||
expect(text_part.body.encoded).to include('Custom text content only')
|
||||
expect(text_part.body.encoded).not_to include('Regular message content')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when smtp enabled for email channel' do
|
||||
|
||||
Reference in New Issue
Block a user