From 938d4e0e51e41873d748d12d0add106983c6bb8c Mon Sep 17 00:00:00 2001 From: George Daramouskas Date: Tue, 23 Apr 2019 18:21:41 +0200 Subject: [PATCH 01/19] [ADD] mail_embed_image module --- mail_embed_image/README.rst | 74 +++ mail_embed_image/__init__.py | 4 + mail_embed_image/__manifest__.py | 16 + mail_embed_image/models/__init__.py | 4 + mail_embed_image/models/ir_mail_server.py | 123 +++++ mail_embed_image/readme/CONTRIBUTORS.rst | 1 + mail_embed_image/readme/DESCRIPTION.rst | 2 + mail_embed_image/static/description/icon.png | Bin 0 -> 9455 bytes .../static/description/index.html | 420 ++++++++++++++++++ mail_embed_image/tests/__init__.py | 4 + .../tests/test_mail_embed_image.py | 87 ++++ 11 files changed, 735 insertions(+) create mode 100644 mail_embed_image/README.rst create mode 100644 mail_embed_image/__init__.py create mode 100644 mail_embed_image/__manifest__.py create mode 100644 mail_embed_image/models/__init__.py create mode 100644 mail_embed_image/models/ir_mail_server.py create mode 100644 mail_embed_image/readme/CONTRIBUTORS.rst create mode 100644 mail_embed_image/readme/DESCRIPTION.rst create mode 100644 mail_embed_image/static/description/icon.png create mode 100644 mail_embed_image/static/description/index.html create mode 100644 mail_embed_image/tests/__init__.py create mode 100644 mail_embed_image/tests/test_mail_embed_image.py diff --git a/mail_embed_image/README.rst b/mail_embed_image/README.rst new file mode 100644 index 0000000000..23ba1cb56d --- /dev/null +++ b/mail_embed_image/README.rst @@ -0,0 +1,74 @@ +================ +Mail Embed Image +================ + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fsocial-lightgray.png?logo=github + :target: https://github.com/OCA/social/tree/10.0/mail_embed_image + :alt: OCA/social +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/social-10-0/social-10-0-mail_embed_image + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/205/10.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module finds images attached to outgoing emails and replaces their urls +with cids. This will avoid rendering issues with some email clients. + +**Table of contents** + +.. contents:: + :local: + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Therp BV + +Contributors +~~~~~~~~~~~~ + +* George Daramouskas + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/social `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/mail_embed_image/__init__.py b/mail_embed_image/__init__.py new file mode 100644 index 0000000000..cff20de52b --- /dev/null +++ b/mail_embed_image/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Copyright 2019 Therp BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from . import models diff --git a/mail_embed_image/__manifest__.py b/mail_embed_image/__manifest__.py new file mode 100644 index 0000000000..f92233a299 --- /dev/null +++ b/mail_embed_image/__manifest__.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# Copyright 2019 Therp BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +{ + "name": "Mail Embed Image", + "version": "10.0.1.0.0", + "author": "Therp BV,Odoo Community Association (OCA)", + "license": "AGPL-3", + "category": "Social", + "summary": "Replace img.src's which start with http with inline cids", + "depends": [ + 'mail', + ], + "installable": True, + "application": False, +} diff --git a/mail_embed_image/models/__init__.py b/mail_embed_image/models/__init__.py new file mode 100644 index 0000000000..4278fd5d08 --- /dev/null +++ b/mail_embed_image/models/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Copyright 2019 Therp BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from . import ir_mail_server diff --git a/mail_embed_image/models/ir_mail_server.py b/mail_embed_image/models/ir_mail_server.py new file mode 100644 index 0000000000..f12a2a76be --- /dev/null +++ b/mail_embed_image/models/ir_mail_server.py @@ -0,0 +1,123 @@ +# -*- coding: utf-8 -*- +# Copyright 2019 Therp BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +import uuid +import logging +from odoo import models, http +from odoo.addons.base.ir.ir_mail_server import encode_header_param +from werkzeug.wrappers import Request +from werkzeug.test import EnvironBuilder +from lxml.html.soupparser import fromstring +from lxml.etree import tostring +from base64 import b64encode +from email.mime.image import MIMEImage +from odoo.http import root as root_wsgi +import threading + + +logger = logging.getLogger(__name__) + + +class IrMailServer(models.Model): + _inherit = 'ir.mail_server' + + def build_email( + self, + email_from, + email_to, + subject, + body, + email_cc=None, + email_bcc=None, + reply_to=None, + attachments=None, + message_id=None, + references=None, + object_id=None, + subtype='plain', + headers=None, + body_alternative=None, + subtype_alternative='plain'): + result = super(IrMailServer, self).build_email( + email_from=email_from, + email_to=email_to, + subject=subject, + body=body, + email_cc=email_cc, + email_bcc=email_bcc, + reply_to=reply_to, + attachments=attachments, + message_id=message_id, + references=references, + object_id=object_id, + subtype=subtype, + headers=headers, + body_alternative=body_alternative, + subtype_alternative=subtype_alternative, + ) + return self._build_email_replace_img_src(result) + + def _build_email_replace_img_src(self, email): + """ Given a message, find it's img tags and if they + are URLs, replace them with cids. + """ + base_url = self.env['ir.config_parameter'].get_param( + 'web.base.url') + for part in email.walk(): + if part.get_content_maintype() == 'text': + body = part.get_payload(decode=True) + if not body: + continue + root = fromstring(body) + for img in root.xpath( + "//img[starts-with(@src, '%s/web/image')]" + "|" + "//img[starts-with(@src, '/web/image')]" % ( + base_url or '', )): + # check if there is a bound request + imgpath = img.get('src').replace(base_url, '') + env = EnvironBuilder(imgpath).get_environ() + endpoint, arguments = http.routing_map( + self.env.registry._init_modules, + False, + self.env['ir.http']._get_converters(), + ).bind_to_environ( + env, + ).match(return_rule=False) + try: + req = http.request.pop() + except RuntimeError: + # if there is not one, just create a fake one + req = Request(env) + # setup session + session_store = root_wsgi.session_store + session = session_store.new() + session.update({ + 'db': threading.current_thread().dbname, + 'login': self.env.user.login, + 'uid': self.env.user.id, + 'content': self.env.context, + }) + req.session = session + req = http.HttpRequest(req) + http._request_stack.push(req) + # now go ahead and call the endpoint and fetch the data + response = endpoint.method(**arguments) + if not response: + logger.warning('Could not get %s', img.get('src')) + continue + cid = uuid.uuid4().hex + filename_rfc2047 = encode_header_param(cid) + filepart = MIMEImage(response.data) + filepart.set_param('name', filename_rfc2047) + filepart.add_header( + 'Content-Disposition', + 'inline', + cid=cid, + filename=filename_rfc2047, + ) + # attach the image into the email as attachment + email.attach(filepart) + img.set('src', 'cid:%s' % (cid)) + part.set_payload(b64encode(tostring(root))) + return email diff --git a/mail_embed_image/readme/CONTRIBUTORS.rst b/mail_embed_image/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000000..3afbb32178 --- /dev/null +++ b/mail_embed_image/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* George Daramouskas diff --git a/mail_embed_image/readme/DESCRIPTION.rst b/mail_embed_image/readme/DESCRIPTION.rst new file mode 100644 index 0000000000..1856fc3768 --- /dev/null +++ b/mail_embed_image/readme/DESCRIPTION.rst @@ -0,0 +1,2 @@ +This module finds images attached to outgoing emails and replaces their urls +with cids. This will avoid rendering issues with some email clients. diff --git a/mail_embed_image/static/description/icon.png b/mail_embed_image/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d GIT binary patch literal 9455 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 z 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 Xviia!U7SGha1wx#SCgwmn*{w2TRX*I literal 0 HcmV?d00001 diff --git a/mail_embed_image/static/description/index.html b/mail_embed_image/static/description/index.html new file mode 100644 index 0000000000..a926ae04e9 --- /dev/null +++ b/mail_embed_image/static/description/index.html @@ -0,0 +1,420 @@ + + + + + + +Mail Embed Image + + + +
+

Mail Embed Image

+ + +

Beta License: AGPL-3 OCA/social Translate me on Weblate Try me on Runbot

+

This module finds images attached to outgoing emails and replaces their urls +with cids. This will avoid rendering issues with some email clients.

+

Table of contents

+ +
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Therp BV
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/social project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/mail_embed_image/tests/__init__.py b/mail_embed_image/tests/__init__.py new file mode 100644 index 0000000000..5a437961a8 --- /dev/null +++ b/mail_embed_image/tests/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Copyright 2019 Therp BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from . import test_mail_embed_image diff --git a/mail_embed_image/tests/test_mail_embed_image.py b/mail_embed_image/tests/test_mail_embed_image.py new file mode 100644 index 0000000000..e7fb6d266b --- /dev/null +++ b/mail_embed_image/tests/test_mail_embed_image.py @@ -0,0 +1,87 @@ +# -*- coding: utf-8 -*- +# Copyright 2019 Therp BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from base64 import b64encode +from odoo.tests import common +from mock import patch, mock +from lxml import html +from requests import get +from odoo import api, registry, SUPERUSER_ID + + +class TestMailEmbedImage(common.TransactionCase): + + post_install = True + at_install = False + + @patch( + 'odoo.fields.html_sanitize', + side_effect=lambda *args, **kwargs: args[0], + ) + def test_mail_embed_image(self, html_sanitize): + """ The following are tested here: + 1) Create an email with no image, send it. + 2) Create an email with three images, one base64 content, one http + full url and one of the format `/web/image/.*` + + We assert that nothing has changed on 1) and only the `/web/image/.*` + has changed in 2) + """ + # we do not want to completely mock out the `build_email` and + # `send_email`, rather we want to be able to get information about + # them such as call arguments, no of times called etc. + # the `wraps` attribute of `Mock` helps us do that + reg = registry(common.get_db_name()) + env = api.Environment(reg.cursor(), SUPERUSER_ID, {}) + model_ir_mail_server = env['ir.mail_server'] + mock_build_email = mock.Mock(wraps=model_ir_mail_server.build_email) + model_ir_mail_server._patch_method('build_email', mock_build_email) + mock_send_email = mock.Mock(wraps=model_ir_mail_server.send_email) + model_ir_mail_server._patch_method('send_email', mock_send_email) + model_mail_mail = self.env['mail.mail'] + 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).content + body1 = '
this is an email
' + email1 = model_mail_mail.create({ + 'body_html': body1, + 'email_from': 'test@example.com', + 'email_to': 'test@example.com', + }) + email1.send() + model_ir_mail_server.build_email.assert_called() + self.assertIn( + body1, + model_ir_mail_server.build_email.call_args[1].get('body') or + # if body is passed as positional argument + model_ir_mail_server.build_email.call_args[0][3]) + self.assertIn( + body1, + model_ir_mail_server.send_email.call_args[0][0].get_payload( + )[0].get_payload()[1].get_payload(decode=True), + ) + body2 = html.tostring(html.fromstring(""" +
+ this is an email + + + +
""" % ( + b64encode(image), + image_url, + '/web/image/res.partner/1/image', + ))) + email2 = model_mail_mail.create({ + 'body_html': body2, + 'email_from': 'test@example.com', + 'email_to': 'test@example.com', + }) + email2.send() + model_ir_mail_server.build_email.assert_called() + self.assertIn( + 'img src="cid:', + model_ir_mail_server.send_email.call_args[0][0].get_payload( + )[0].get_payload()[1].get_payload(decode=True), + ) From fda3a6f6e9c6a6ee9957009ae9043cd15bf6ed0c Mon Sep 17 00:00:00 2001 From: Giovanni Francesco Capalbo Date: Thu, 14 Nov 2019 14:06:06 +0100 Subject: [PATCH 02/19] [FIX] solves SMTP line limit error [maximum allowed line length is 998 octets] --- mail_embed_image/models/ir_mail_server.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mail_embed_image/models/ir_mail_server.py b/mail_embed_image/models/ir_mail_server.py index f12a2a76be..89c3980f81 100644 --- a/mail_embed_image/models/ir_mail_server.py +++ b/mail_embed_image/models/ir_mail_server.py @@ -9,7 +9,7 @@ from werkzeug.test import EnvironBuilder from lxml.html.soupparser import fromstring from lxml.etree import tostring -from base64 import b64encode +from base64 import encodebytes from email.mime.image import MIMEImage from odoo.http import root as root_wsgi import threading @@ -66,7 +66,7 @@ def _build_email_replace_img_src(self, email): for part in email.walk(): if part.get_content_maintype() == 'text': body = part.get_payload(decode=True) - if not body: + if not body or body == '\n': continue root = fromstring(body) for img in root.xpath( @@ -119,5 +119,6 @@ def _build_email_replace_img_src(self, email): # attach the image into the email as attachment email.attach(filepart) img.set('src', 'cid:%s' % (cid)) - part.set_payload(b64encode(tostring(root))) + # encodebytes will put a newline every 74 char + part.set_payload(encodebytes(tostring(root))) return email From 1c2d9d74baa2b160165f5b96591e9231e3421830 Mon Sep 17 00:00:00 2001 From: Giovanni Francesco Capalbo Date: Fri, 15 Nov 2019 12:01:20 +0100 Subject: [PATCH 03/19] [REF] refactor and improvements --- mail_embed_image/README.rst | 1 + mail_embed_image/models/ir_mail_server.py | 125 +++++++++--------- mail_embed_image/readme/CONTRIBUTORS.rst | 1 + .../tests/test_mail_embed_image.py | 88 ++++-------- 4 files changed, 96 insertions(+), 119 deletions(-) diff --git a/mail_embed_image/README.rst b/mail_embed_image/README.rst index 23ba1cb56d..932d31e9c7 100644 --- a/mail_embed_image/README.rst +++ b/mail_embed_image/README.rst @@ -55,6 +55,7 @@ Contributors ~~~~~~~~~~~~ * George Daramouskas +* Giovanni Francesco Capalbo Maintainers ~~~~~~~~~~~ diff --git a/mail_embed_image/models/ir_mail_server.py b/mail_embed_image/models/ir_mail_server.py index 89c3980f81..7010bdae3b 100644 --- a/mail_embed_image/models/ir_mail_server.py +++ b/mail_embed_image/models/ir_mail_server.py @@ -3,16 +3,17 @@ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). import uuid import logging +from contextlib import contextmanager from odoo import models, http from odoo.addons.base.ir.ir_mail_server import encode_header_param -from werkzeug.wrappers import Request from werkzeug.test import EnvironBuilder +from werkzeug.wrappers import Request as WerkzeugRequest from lxml.html.soupparser import fromstring from lxml.etree import tostring -from base64 import encodebytes -from email.mime.image import MIMEImage -from odoo.http import root as root_wsgi +from base64 import encodestring import threading +from odoo.http import root as root_wsgi +from email.mime.image import MIMEImage logger = logging.getLogger(__name__) @@ -21,6 +22,32 @@ class IrMailServer(models.Model): _inherit = 'ir.mail_server' + @contextmanager + def _fetch_image(self, path): + public_user = self.env.ref('base.public_user') + session_store = root_wsgi.session_store + session = session_store.new() + session.update({ + 'db': threading.current_thread().dbname, + 'login': public_user.login, + 'uid': public_user.id, + 'context': self.env.context, + }) + werkzeug_env = EnvironBuilder(path).get_environ() + werkzeug_request = WerkzeugRequest(werkzeug_env) + werkzeug_request.session = session + # construct an odoo request with this werkzeug request. + request = http.HttpRequest(werkzeug_request) + with request: + request._env = self.env(user=public_user) + endpoint, arguments = http.routing_map( + self.env.registry._init_modules, + False, + self.env['ir.http']._get_converters() + ).bind_to_environ( + werkzeug_env).match(return_rule=False,) + yield endpoint, arguments + def build_email( self, email_from, @@ -61,64 +88,42 @@ def _build_email_replace_img_src(self, email): """ Given a message, find it's img tags and if they are URLs, replace them with cids. """ - base_url = self.env['ir.config_parameter'].get_param( - 'web.base.url') for part in email.walk(): - if part.get_content_maintype() == 'text': + if part.get_content_type() == 'text/html': body = part.get_payload(decode=True) if not body or body == '\n': continue - root = fromstring(body) - for img in root.xpath( - "//img[starts-with(@src, '%s/web/image')]" - "|" - "//img[starts-with(@src, '/web/image')]" % ( - base_url or '', )): - # check if there is a bound request - imgpath = img.get('src').replace(base_url, '') - env = EnvironBuilder(imgpath).get_environ() - endpoint, arguments = http.routing_map( - self.env.registry._init_modules, - False, - self.env['ir.http']._get_converters(), - ).bind_to_environ( - env, - ).match(return_rule=False) - try: - req = http.request.pop() - except RuntimeError: - # if there is not one, just create a fake one - req = Request(env) - # setup session - session_store = root_wsgi.session_store - session = session_store.new() - session.update({ - 'db': threading.current_thread().dbname, - 'login': self.env.user.login, - 'uid': self.env.user.id, - 'content': self.env.context, - }) - req.session = session - req = http.HttpRequest(req) - http._request_stack.push(req) - # now go ahead and call the endpoint and fetch the data - response = endpoint.method(**arguments) - if not response: - logger.warning('Could not get %s', img.get('src')) - continue - cid = uuid.uuid4().hex - filename_rfc2047 = encode_header_param(cid) - filepart = MIMEImage(response.data) - filepart.set_param('name', filename_rfc2047) - filepart.add_header( - 'Content-Disposition', - 'inline', - cid=cid, - filename=filename_rfc2047, - ) - # attach the image into the email as attachment - email.attach(filepart) - img.set('src', 'cid:%s' % (cid)) - # encodebytes will put a newline every 74 char - part.set_payload(encodebytes(tostring(root))) + root = self._build_email_process_img_body( + fromstring(body), email) + # encodestring will put a newline every 74 char + part.set_payload(encodestring(tostring(root))) return email + + def _build_email_process_img_body(self, root, email): + base_url = self.env['ir.config_parameter'].get_param( + 'web.base.url') + for img in root.xpath( + ".//img[starts-with(@src, '%s/web/image')]" + "| .//img[starts-with(@src, '/web/image')]" % (base_url)): + image_path = img.get('src').replace(base_url, '') + with self._fetch_image(image_path) as (endpoint, arguments): + # now go ahead and call the endpoint and fetch the data + response = endpoint.method(**arguments) + if not response: + logger.warning('Could not get %s', img.get('src')) + continue + cid = uuid.uuid4().hex + filename_rfc2047 = encode_header_param(cid) + filepart = MIMEImage(response.data) + # TODO check if filepart exists (do not attach twice) + filepart.set_param('name', filename_rfc2047) + filepart.add_header( + 'Content-Disposition', + 'inline', + cid=cid, + filename=filename_rfc2047, + ) + # attach the image into the email as attachment + email.attach(filepart) + img.set('src', 'cid:%s' % (str(cid))) + return root diff --git a/mail_embed_image/readme/CONTRIBUTORS.rst b/mail_embed_image/readme/CONTRIBUTORS.rst index 3afbb32178..33ea1440fe 100644 --- a/mail_embed_image/readme/CONTRIBUTORS.rst +++ b/mail_embed_image/readme/CONTRIBUTORS.rst @@ -1 +1,2 @@ * George Daramouskas +* Giovanni Francesco Capalbo diff --git a/mail_embed_image/tests/test_mail_embed_image.py b/mail_embed_image/tests/test_mail_embed_image.py index e7fb6d266b..9d70dde23f 100644 --- a/mail_embed_image/tests/test_mail_embed_image.py +++ b/mail_embed_image/tests/test_mail_embed_image.py @@ -3,66 +3,25 @@ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). from base64 import b64encode from odoo.tests import common -from mock import patch, mock from lxml import html from requests import get -from odoo import api, registry, SUPERUSER_ID class TestMailEmbedImage(common.TransactionCase): post_install = True - at_install = False - @patch( - 'odoo.fields.html_sanitize', - side_effect=lambda *args, **kwargs: args[0], - ) - def test_mail_embed_image(self, html_sanitize): - """ The following are tested here: - 1) Create an email with no image, send it. - 2) Create an email with three images, one base64 content, one http - full url and one of the format `/web/image/.*` - - We assert that nothing has changed on 1) and only the `/web/image/.*` - has changed in 2) - """ - # we do not want to completely mock out the `build_email` and - # `send_email`, rather we want to be able to get information about - # them such as call arguments, no of times called etc. - # the `wraps` attribute of `Mock` helps us do that - reg = registry(common.get_db_name()) - env = api.Environment(reg.cursor(), SUPERUSER_ID, {}) - model_ir_mail_server = env['ir.mail_server'] - mock_build_email = mock.Mock(wraps=model_ir_mail_server.build_email) - model_ir_mail_server._patch_method('build_email', mock_build_email) - mock_send_email = mock.Mock(wraps=model_ir_mail_server.send_email) - model_ir_mail_server._patch_method('send_email', mock_send_email) - model_mail_mail = self.env['mail.mail'] + def test_mail_embed_image(self): + """We pass a mail with 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).content - body1 = '
this is an email
' - email1 = model_mail_mail.create({ - 'body_html': body1, - 'email_from': 'test@example.com', - 'email_to': 'test@example.com', - }) - email1.send() - model_ir_mail_server.build_email.assert_called() - self.assertIn( - body1, - model_ir_mail_server.build_email.call_args[1].get('body') or - # if body is passed as positional argument - model_ir_mail_server.build_email.call_args[0][3]) - self.assertIn( - body1, - model_ir_mail_server.send_email.call_args[0][0].get_payload( - )[0].get_payload()[1].get_payload(decode=True), - ) - body2 = html.tostring(html.fromstring(""" + body = html.tostring(html.fromstring("""
this is an email @@ -73,15 +32,26 @@ def test_mail_embed_image(self, html_sanitize): image_url, '/web/image/res.partner/1/image', ))) - email2 = model_mail_mail.create({ - 'body_html': body2, - 'email_from': 'test@example.com', - 'email_to': 'test@example.com', - }) - email2.send() - model_ir_mail_server.build_email.assert_called() - self.assertIn( - 'img src="cid:', - model_ir_mail_server.send_email.call_args[0][0].get_payload( - )[0].get_payload()[1].get_payload(decode=True), - ) + email_from = 'test@example.com' + email_to = 'test@example.com' + subject = 'test mail' + # END DATA + res = self.env['ir.mail_server'].build_email( + email_from, email_to, subject, + body, subtype='html') + 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, 'cid:')]") + ) + # verify 1 replaced image + self.assertEqual(images_in_mail, 1) + # verify 1 attachment present + self.assertEqual([ + x.get_content_type() for x in res.walk() if x.get_content_type( + ).startswith('image/')], ['image/png']) From bddec110b5008c33ada62a7602fb8ef28f408100 Mon Sep 17 00:00:00 2001 From: Giovanni Francesco Capalbo Date: Thu, 9 Jan 2020 17:46:47 +0100 Subject: [PATCH 04/19] [FIX] --- mail_embed_image/tests/test_mail_embed_image.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mail_embed_image/tests/test_mail_embed_image.py b/mail_embed_image/tests/test_mail_embed_image.py index 9d70dde23f..c76b4f753c 100644 --- a/mail_embed_image/tests/test_mail_embed_image.py +++ b/mail_embed_image/tests/test_mail_embed_image.py @@ -38,7 +38,7 @@ def test_mail_embed_image(self): # END DATA res = self.env['ir.mail_server'].build_email( email_from, email_to, subject, - body, subtype='html') + body, subtype='html', subtype_alternative='plain') images_in_mail = 0 for part in res.walk(): if part.get_content_type() == 'text/html': From d509290c7b984eff05071e7accd54b7ae5bc4478 Mon Sep 17 00:00:00 2001 From: Giovanni Francesco Capalbo Date: Thu, 9 Jan 2020 18:00:55 +0100 Subject: [PATCH 05/19] [FIX] --- mail_embed_image/models/ir_mail_server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mail_embed_image/models/ir_mail_server.py b/mail_embed_image/models/ir_mail_server.py index 7010bdae3b..39d8e199c8 100644 --- a/mail_embed_image/models/ir_mail_server.py +++ b/mail_embed_image/models/ir_mail_server.py @@ -61,7 +61,7 @@ def build_email( message_id=None, references=None, object_id=None, - subtype='plain', + subtype='html', headers=None, body_alternative=None, subtype_alternative='plain'): From 1b895a4d326af201f386bd0ed85ff071838f0d59 Mon Sep 17 00:00:00 2001 From: Giovanni Francesco Capalbo Date: Thu, 9 Jan 2020 18:34:01 +0100 Subject: [PATCH 06/19] [add] debug feedback --- mail_embed_image/models/ir_mail_server.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mail_embed_image/models/ir_mail_server.py b/mail_embed_image/models/ir_mail_server.py index 39d8e199c8..279ba1562a 100644 --- a/mail_embed_image/models/ir_mail_server.py +++ b/mail_embed_image/models/ir_mail_server.py @@ -109,6 +109,10 @@ def _build_email_process_img_body(self, root, email): with self._fetch_image(image_path) as (endpoint, arguments): # now go ahead and call the endpoint and fetch the data response = endpoint.method(**arguments) + if str(response.status_code)[0] == '4': + logger.warning( + 'Could not fetch image for CID, code %s' + ) % str(response.status_code) if not response: logger.warning('Could not get %s', img.get('src')) continue From f9fb3e88e985fd970920b7ebe2ad17a328c50a0b Mon Sep 17 00:00:00 2001 From: Giovanni Francesco Capalbo Date: Thu, 9 Jan 2020 18:35:06 +0100 Subject: [PATCH 07/19] f --- mail_embed_image/models/ir_mail_server.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mail_embed_image/models/ir_mail_server.py b/mail_embed_image/models/ir_mail_server.py index 279ba1562a..100c5ae7f1 100644 --- a/mail_embed_image/models/ir_mail_server.py +++ b/mail_embed_image/models/ir_mail_server.py @@ -111,8 +111,8 @@ def _build_email_process_img_body(self, root, email): response = endpoint.method(**arguments) if str(response.status_code)[0] == '4': logger.warning( - 'Could not fetch image for CID, code %s' - ) % str(response.status_code) + 'Could not fetch image for CID, code %s' % str( + response.status_code)) if not response: logger.warning('Could not get %s', img.get('src')) continue From 23297a13e83f772994604b750e71eb0f668b1d11 Mon Sep 17 00:00:00 2001 From: Holger Brunn Date: Mon, 13 Jan 2020 13:34:27 +0100 Subject: [PATCH 08/19] [FIX] exacly reproduce super's default values --- mail_embed_image/models/ir_mail_server.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/mail_embed_image/models/ir_mail_server.py b/mail_embed_image/models/ir_mail_server.py index 100c5ae7f1..484e55c01b 100644 --- a/mail_embed_image/models/ir_mail_server.py +++ b/mail_embed_image/models/ir_mail_server.py @@ -56,15 +56,16 @@ def build_email( body, email_cc=None, email_bcc=None, - reply_to=None, + reply_to=False, attachments=None, message_id=None, references=None, - object_id=None, - subtype='html', + object_id=False, + subtype='plain', headers=None, body_alternative=None, - subtype_alternative='plain'): + subtype_alternative='plain', + ): result = super(IrMailServer, self).build_email( email_from=email_from, email_to=email_to, From 73faa846b7eb303e903541d3b098905060fde5f6 Mon Sep 17 00:00:00 2001 From: Holger Brunn Date: Mon, 13 Jan 2020 13:34:56 +0100 Subject: [PATCH 09/19] [IMP] depend on base --- mail_embed_image/__manifest__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mail_embed_image/__manifest__.py b/mail_embed_image/__manifest__.py index f92233a299..39c6cd709f 100644 --- a/mail_embed_image/__manifest__.py +++ b/mail_embed_image/__manifest__.py @@ -9,7 +9,7 @@ "category": "Social", "summary": "Replace img.src's which start with http with inline cids", "depends": [ - 'mail', + 'web', ], "installable": True, "application": False, From 5237964201396937a232e450cc832f6a69c46416 Mon Sep 17 00:00:00 2001 From: Holger Brunn Date: Tue, 14 Jan 2020 15:00:22 +0100 Subject: [PATCH 10/19] [FIX] run tests at_install --- mail_embed_image/tests/test_mail_embed_image.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/mail_embed_image/tests/test_mail_embed_image.py b/mail_embed_image/tests/test_mail_embed_image.py index c76b4f753c..7e4b03c701 100644 --- a/mail_embed_image/tests/test_mail_embed_image.py +++ b/mail_embed_image/tests/test_mail_embed_image.py @@ -8,9 +8,6 @@ class TestMailEmbedImage(common.TransactionCase): - - post_install = True - def test_mail_embed_image(self): """We pass a mail with tags to build_email, and then look into the result, check there were attachments From 6bb70b21eaea3cdda14e8903de6a030df1d29f8a Mon Sep 17 00:00:00 2001 From: Holger Brunn Date: Tue, 14 Jan 2020 20:02:49 +0100 Subject: [PATCH 11/19] [FIX] improve error handling --- mail_embed_image/models/ir_mail_server.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/mail_embed_image/models/ir_mail_server.py b/mail_embed_image/models/ir_mail_server.py index 484e55c01b..e7074b5fda 100644 --- a/mail_embed_image/models/ir_mail_server.py +++ b/mail_embed_image/models/ir_mail_server.py @@ -110,11 +110,7 @@ def _build_email_process_img_body(self, root, email): with self._fetch_image(image_path) as (endpoint, arguments): # now go ahead and call the endpoint and fetch the data response = endpoint.method(**arguments) - if str(response.status_code)[0] == '4': - logger.warning( - 'Could not fetch image for CID, code %s' % str( - response.status_code)) - if not response: + if not response or response.status_code != 200: logger.warning('Could not get %s', img.get('src')) continue cid = uuid.uuid4().hex From d8fe9ed20911ba99c39c5691890112e782c13d8f Mon Sep 17 00:00:00 2001 From: Holger Brunn Date: Tue, 14 Jan 2020 20:03:08 +0100 Subject: [PATCH 12/19] [FIX] make tests more resilient against different testing envs --- mail_embed_image/tests/test_mail_embed_image.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/mail_embed_image/tests/test_mail_embed_image.py b/mail_embed_image/tests/test_mail_embed_image.py index 7e4b03c701..18c5b9a7c0 100644 --- a/mail_embed_image/tests/test_mail_embed_image.py +++ b/mail_embed_image/tests/test_mail_embed_image.py @@ -5,6 +5,7 @@ from odoo.tests import common from lxml import html from requests import get +from ..models.ir_mail_server import IrMailServer class TestMailEmbedImage(common.TransactionCase): @@ -25,17 +26,26 @@ def test_mail_embed_image(self):
""" % ( + # won't be hit because we ignore embedded images b64encode(image), + # dito, not uploaded content image_url, - '/web/image/res.partner/1/image', + # this we may read with the share we create below + '/web/image/res.partner/%d/image' % ( + self.env.ref('base.public_partner').id + ), ))) email_from = 'test@example.com' email_to = 'test@example.com' subject = 'test mail' # END DATA - res = self.env['ir.mail_server'].build_email( + # given mail tests patch this method and don't restore it, we need + # to call our function somewhat clumsily + res = IrMailServer.build_email.__func__( + self.env['ir.mail_server'], email_from, email_to, subject, - body, subtype='html', subtype_alternative='plain') + body, subtype='html', subtype_alternative='plain', + ) images_in_mail = 0 for part in res.walk(): if part.get_content_type() == 'text/html': From 03204cafcb956978c09206e13764d2c931f43a56 Mon Sep 17 00:00:00 2001 From: oca-travis Date: Fri, 23 Apr 2021 21:25:26 +0000 Subject: [PATCH 13/19] [UPD] Update mail_embed_image.pot --- mail_embed_image/i18n/mail_embed_image.pot | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 mail_embed_image/i18n/mail_embed_image.pot diff --git a/mail_embed_image/i18n/mail_embed_image.pot b/mail_embed_image/i18n/mail_embed_image.pot new file mode 100644 index 0000000000..061376b78a --- /dev/null +++ b/mail_embed_image/i18n/mail_embed_image.pot @@ -0,0 +1,20 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * mail_embed_image +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: mail_embed_image +#: model:ir.model,name:mail_embed_image.model_ir_mail_server +msgid "ir.mail_server" +msgstr "" + From 8aa44550af6720908c794c2175396137c70592a9 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Fri, 23 Apr 2021 21:57:59 +0000 Subject: [PATCH 14/19] [UPD] README.rst --- mail_embed_image/static/description/index.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mail_embed_image/static/description/index.html b/mail_embed_image/static/description/index.html index a926ae04e9..a94162404a 100644 --- a/mail_embed_image/static/description/index.html +++ b/mail_embed_image/static/description/index.html @@ -3,7 +3,7 @@ - + Mail Embed Image