-
-
Notifications
You must be signed in to change notification settings - Fork 621
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[16.0][IMP] mail_embed_image: improve embedding type:
- CIDs are not working in some email managers (gmail and office365) To allow this behavior we need to change the content type to multipart/related - A new option to embed images is to include the base64 content inside the src. - Then to select these options, a selected field has been added to company
- Loading branch information
1 parent
7bf9209
commit 6dc1479
Showing
11 changed files
with
220 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -31,6 +31,12 @@ Mail Embed Image | |
This module finds images attached to outgoing emails and replaces their urls | ||
with cids. This will avoid rendering issues with some email clients. | ||
|
||
It also provides 2 options to embed internal URL images in a mail body: | ||
- CIDs: add fileparts as CIDs | ||
- Data URLs: add images as data URLs | ||
|
||
This option is configurable in an company settings variables. | ||
|
||
**Table of contents** | ||
|
||
.. contents:: | ||
|
@@ -60,6 +66,7 @@ Contributors | |
* George Daramouskas <[email protected]> | ||
* Giovanni Francesco Capalbo <[email protected]> | ||
* Italo LOPES <[email protected]> | ||
* Stéphane Mangin <[email protected]> | ||
|
||
Maintainers | ||
~~~~~~~~~~~ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,6 @@ | ||
# Copyright 2019 Therp BV <https://therp.nl> | ||
# Copyright 2024 Camptocamp SA | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). | ||
from . import ir_mail_server | ||
from . import company | ||
from . import res_config_settings |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# Copyright 2024 Camptocamp SA | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). | ||
from odoo import fields, models | ||
|
||
|
||
class ResCompany(models.Model): | ||
_inherit = "res.company" | ||
|
||
image_embedding_method = fields.Selection( | ||
selection=[ | ||
("none", "No attachment"), | ||
("cid", "CIDs attachment"), | ||
("data", "Data SRC"), | ||
], | ||
default="cid", # previous module version only supported CID | ||
required=True, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# Copyright 2024 Camptocamp SA | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). | ||
from odoo import fields, models | ||
|
||
|
||
class ResConfigSettings(models.TransientModel): | ||
_inherit = "res.config.settings" | ||
|
||
image_embedding_method = fields.Selection( | ||
related="company_id.image_embedding_method", | ||
readonly=False, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
* George Daramouskas <[email protected]> | ||
* Giovanni Francesco Capalbo <[email protected]> | ||
* Italo LOPES <[email protected]> | ||
* Stéphane Mangin <[email protected]> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,8 @@ | ||
This module finds images attached to outgoing emails and replaces their urls | ||
with cids. This will avoid rendering issues with some email clients. | ||
|
||
It also provides 2 options to embed internal URL images in a mail body: | ||
- CIDs: add fileparts as CIDs | ||
- Data URLs: add images as data URLs | ||
|
||
This option is configurable in an company settings variables. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
# Copyright 2019 Therp BV <https://therp.nl> | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). | ||
from base64 import b64encode | ||
import base64 | ||
|
||
from lxml import html | ||
from requests import get | ||
|
@@ -9,14 +9,23 @@ | |
|
||
|
||
class TestMailEmbedImage(common.TransactionCase): | ||
def test_mail_embed_image(self): | ||
"""We pass a mail with <img src="..." /> tags to build_email, | ||
and then look into the result, check there were attachments | ||
created and you find xpaths like //img[src] have a cid""" | ||
# DATA | ||
base_url = self.env["ir.config_parameter"].get_param("web.base.url") | ||
image_url = base_url + "/mail_embed_image/static/description/icon.png" | ||
image = get(image_url, timeout=10).content | ||
@classmethod | ||
def setUpClass(cls): | ||
super(TestMailEmbedImage, cls).setUpClass() | ||
cls.company = cls.env.ref("base.main_company") | ||
base_url = cls.env["ir.config_parameter"].get_param("web.base.url") | ||
cls.image_url = base_url + "/mail_embed_image/static/description/icon.png" | ||
cls.image_content = get(cls.image_url, timeout=10).content | ||
cls.email_from = "[email protected]" | ||
cls.email_to = "[email protected]" | ||
cls.subject = "test mail" | ||
|
||
def build_email(self, option="cid"): | ||
"""Build an email with a given embedding option | ||
option -- the embedding option to use according to the company setting | ||
""" | ||
self.company.image_embedding_method = option | ||
body = html.tostring( | ||
html.fromstring( | ||
""" | ||
|
@@ -27,24 +36,61 @@ def test_mail_embed_image(self): | |
</div>""" | ||
% ( | ||
# won't be hit because we ignore embedded images | ||
b64encode(image), | ||
base64.b64encode(self.image_content).decode("utf-8"), | ||
# dito, not uploaded content | ||
image_url, | ||
self.image_url, | ||
) | ||
) | ||
) | ||
email_from = "[email protected]" | ||
email_to = "[email protected]" | ||
subject = "test mail" | ||
# END DATA | ||
res = self.env["ir.mail_server"].build_email( | ||
email_from, | ||
[email_to], | ||
subject, | ||
return self.env["ir.mail_server"].build_email( | ||
self.email_from, | ||
[self.email_to], | ||
self.subject, | ||
body, | ||
subtype="html", | ||
subtype_alternative="plain", | ||
) | ||
|
||
def test_mail_embed_image_option_none(self): | ||
"""No embedding option | ||
We pass a mail with <img src="..." /> tags to build_email, | ||
and then look into the result, check there no changes were made""" | ||
res = self.build_email("none") | ||
images_in_mail = 0 | ||
for part in res.walk(): | ||
if part.get_content_type() == "text/html": | ||
# we do not search in text, just in case that texts exists in | ||
# the text elsewhere (not probable, but this is better) | ||
images_in_mail += len( | ||
html.fromstring(part.get_payload(decode=True)).xpath( | ||
"//img[starts-with(@src, 'data:image/png;base64,')]" | ||
) | ||
) | ||
images_in_mail += len( | ||
html.fromstring(part.get_payload(decode=True)).xpath( | ||
"//img[starts-with(@src, 'cid:')]" | ||
) | ||
) | ||
# verify 0 replaced images | ||
self.assertEqual(images_in_mail, 0) | ||
# verify 0 attachment present | ||
self.assertEqual( | ||
[ | ||
x.get_content_type() | ||
for x in res.walk() | ||
if x.get_content_type().startswith("image/") | ||
], | ||
[], | ||
) | ||
|
||
def test_mail_embed_image_option_cids(self): | ||
"""CIDs attachement option | ||
We pass a mail with <img src="..." /> tags to build_email, | ||
and then look into the result, check there were attachments | ||
created and you find xpaths like //img[src] have a cid""" | ||
res = self.build_email("cid") | ||
images_in_mail = 0 | ||
for part in res.walk(): | ||
if part.get_content_type() == "text/html": | ||
|
@@ -66,3 +112,32 @@ def test_mail_embed_image(self): | |
], | ||
["image/png"], | ||
) | ||
|
||
def test_mail_embed_image_option_data(self): | ||
"""Data URL option | ||
We pass a mail with <img src="..." /> tags to build_email, | ||
and then look into the result, check there were attachments | ||
created and you find xpaths like //img[src] have a data URL""" | ||
res = self.build_email("data") | ||
images_in_mail = 0 | ||
for part in res.walk(): | ||
if part.get_content_type() == "text/html": | ||
# we do not search in text, just in case that texts exists in | ||
# the text elsewhere (not probable, but this is better) | ||
images_in_mail += len( | ||
html.fromstring(part.get_payload(decode=True)).xpath( | ||
"//img[starts-with(@src, 'data:image/png;base64,')]" | ||
) | ||
) | ||
# verify 2 replaced image | ||
self.assertEqual(images_in_mail, 1) | ||
# verify 0 attachment present | ||
self.assertEqual( | ||
[ | ||
x.get_content_type() | ||
for x in res.walk() | ||
if x.get_content_type().startswith("image/") | ||
], | ||
[], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
<?xml version="1.0" encoding="utf-8" ?> | ||
<odoo> | ||
|
||
<record id="res_config_settings_view_form" model="ir.ui.view"> | ||
<field name="name">res.config.settings.view.form.inherit.mail</field> | ||
<field name="model">res.config.settings</field> | ||
<field name="inherit_id" ref="mail.res_config_settings_view_form" /> | ||
<field name="arch" type="xml"> | ||
<div id="companies_setting" position="inside"> | ||
<br /> | ||
<div | ||
class="o_setting_right_pane" | ||
id="mail_templates_setting" | ||
groups="mail.group_mail_template_editor,base.group_system" | ||
> | ||
<span class="o_form_label">Email Preprocessing</span> | ||
<div class="text-muted"> | ||
Method used to embed images in HTML emails. CIDs attachment does not work with all email clients. Data SRC is more reliable. | ||
</div> | ||
<field name="image_embedding_method" /> | ||
</div> | ||
</div> | ||
</field> | ||
</record> | ||
|
||
</odoo> |