[FIX] mass_mailing: inline image not supported
Inline (base64) embedded images are not supported by most mail clients (gmail on top of them), this fix save those images as attachments and replace the src tag with the url of the generated image so the image correctly renders. opw-1929940 closes odoo/odoo#31532 Signed-off-by: Julien Castiaux <Julien00859@users.noreply.github.com>
This commit is contained in:
@@ -4,10 +4,12 @@
|
||||
import hashlib
|
||||
import hmac
|
||||
import logging
|
||||
import lxml
|
||||
import random
|
||||
import re
|
||||
import threading
|
||||
from ast import literal_eval
|
||||
from base64 import b64encode
|
||||
|
||||
from odoo import api, fields, models, tools, _, SUPERUSER_ID
|
||||
from odoo.exceptions import UserError
|
||||
@@ -26,6 +28,10 @@ MASS_MAILING_BUSINESS_MODELS = [
|
||||
]
|
||||
EMAIL_PATTERN = '([^ ,;<@]+@[^> ,;]+)'
|
||||
|
||||
# Syntax of the data URL Scheme: https://tools.ietf.org/html/rfc2397#section-3
|
||||
# Used to find inline images
|
||||
image_re = re.compile(r"data:(image/[A-Za-z]+);base64,(.*)")
|
||||
|
||||
|
||||
class MassMailingTag(models.Model):
|
||||
"""Model of categories of mass mailing, i.e. marketing, newsletter, ... """
|
||||
@@ -661,6 +667,53 @@ class MassMailing(models.Model):
|
||||
if len(record_lists) > 0:
|
||||
record.sudo().message_post(body=_(message % ', '.join(str(list.name) for list in record_lists.mapped('list_id'))))
|
||||
|
||||
@api.model
|
||||
def create(self, values):
|
||||
if values.get('body_html'):
|
||||
values['body_html'] = self._convert_inline_images_to_urls(values['body_html'])
|
||||
return super(MassMailing, self).create(values)
|
||||
|
||||
def write(self, values):
|
||||
if values.get('body_html'):
|
||||
values['body_html'] = self._convert_inline_images_to_urls(values['body_html'])
|
||||
return super(MassMailing, self).write(values)
|
||||
|
||||
def _convert_inline_images_to_urls(self, body_html):
|
||||
"""
|
||||
Find inline base64 encoded images, make an attachement out of
|
||||
them and replace the inline image with an url to the attachement.
|
||||
"""
|
||||
|
||||
def _image_to_url(b64image: bytes):
|
||||
"""Store an image in an attachement and returns an url"""
|
||||
attachment = self.env['ir.attachment'].create({
|
||||
'name': "cropped_image",
|
||||
'datas': b64image,
|
||||
'datas_fname': "cropped_image_mailing_{}".format(self.id),
|
||||
'type': 'binary',})
|
||||
|
||||
attachment.generate_access_token()
|
||||
|
||||
return '/web/image/%s?access_token=%s' % (
|
||||
attachment.id, attachment.access_token)
|
||||
|
||||
|
||||
modified = False
|
||||
root = lxml.html.fromstring(body_html)
|
||||
for node in root.iter('img'):
|
||||
match = image_re.match(node.attrib.get('src', ''))
|
||||
if match:
|
||||
mime = match.group(1) # unsed
|
||||
image = match.group(2).encode() # base64 image as bytes
|
||||
|
||||
node.attrib['src'] = _image_to_url(image)
|
||||
modified = True
|
||||
|
||||
if modified:
|
||||
return lxml.html.tostring(root)
|
||||
|
||||
return body_html
|
||||
|
||||
#------------------------------------------------------
|
||||
# Views & Actions
|
||||
#------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user