From 4af8bdec2f43b232297764485aa83af90c89c611 Mon Sep 17 00:00:00 2001 From: Holger Brunn Date: Thu, 1 Mar 2018 16:50:54 +0100 Subject: [PATCH 1/9] [ADD] mail_autogenerated_header --- mail_autogenerated_header/README.rst | 87 ++++ mail_autogenerated_header/__init__.py | 4 + mail_autogenerated_header/__manifest__.py | 14 + .../i18n/mail_autogenerated_header.pot | 30 ++ mail_autogenerated_header/models/__init__.py | 6 + .../models/ir_mail_server.py | 55 +++ .../models/mail_thread.py | 34 ++ .../models/res_partner.py | 24 + .../readme/CONTRIBUTORS.rst | 1 + .../readme/DESCRIPTION.rst | 5 + mail_autogenerated_header/readme/USAGE.rst | 5 + .../readme/newsfragments/.gitkeep | 0 .../static/description/icon.png | Bin 0 -> 9455 bytes .../static/description/index.html | 431 ++++++++++++++++++ mail_autogenerated_header/tests/__init__.py | 4 + .../tests/test_mail_autogenerated_header.py | 63 +++ 16 files changed, 763 insertions(+) create mode 100644 mail_autogenerated_header/README.rst create mode 100644 mail_autogenerated_header/__init__.py create mode 100644 mail_autogenerated_header/__manifest__.py create mode 100644 mail_autogenerated_header/i18n/mail_autogenerated_header.pot create mode 100644 mail_autogenerated_header/models/__init__.py create mode 100644 mail_autogenerated_header/models/ir_mail_server.py create mode 100644 mail_autogenerated_header/models/mail_thread.py create mode 100644 mail_autogenerated_header/models/res_partner.py create mode 100644 mail_autogenerated_header/readme/CONTRIBUTORS.rst create mode 100644 mail_autogenerated_header/readme/DESCRIPTION.rst create mode 100644 mail_autogenerated_header/readme/USAGE.rst create mode 100644 mail_autogenerated_header/readme/newsfragments/.gitkeep create mode 100644 mail_autogenerated_header/static/description/icon.png create mode 100644 mail_autogenerated_header/static/description/index.html create mode 100644 mail_autogenerated_header/tests/__init__.py create mode 100644 mail_autogenerated_header/tests/test_mail_autogenerated_header.py diff --git a/mail_autogenerated_header/README.rst b/mail_autogenerated_header/README.rst new file mode 100644 index 000000000..d0d6f1055 --- /dev/null +++ b/mail_autogenerated_header/README.rst @@ -0,0 +1,87 @@ +===================== +Autogenerated headers +===================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! 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/12.0/mail_autogenerated_header + :alt: OCA/social +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/social-12-0/social-12-0-mail_autogenerated_header + :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/12.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module was written to mark Odoo's emails as being autogenerated according to `RFC 3834 `_, section 5. This allows receiving mail servers to act accordingly by for example not sending a vacation autoreply. + +On the receiving side, this module drops all notifications for autogenerated incoming e-mails. + +The combination of both avoids possible mail loops with misconfigured or broken email servers on the opposite side. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +There's nothing the user has to do. Developers can set the context flag +``mail_autogenerated_header_disable`` in calls to ``send_email`` in order to +suppress adding any headers at all, and override +``_message_route_process_autoreply`` to fine tune dropping autogenerated mails +per model. + +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 +~~~~~~~ + +* Hunki Enterprises BV +* Therp BV + +Contributors +~~~~~~~~~~~~ + +* Holger Brunn (https://hunki-enterprises.com) + +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_autogenerated_header/__init__.py b/mail_autogenerated_header/__init__.py new file mode 100644 index 000000000..ffe1a38a3 --- /dev/null +++ b/mail_autogenerated_header/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2018 Therp BV +# Copyright 2022 Hunki Enterprises BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from . import models diff --git a/mail_autogenerated_header/__manifest__.py b/mail_autogenerated_header/__manifest__.py new file mode 100644 index 000000000..b79adfa47 --- /dev/null +++ b/mail_autogenerated_header/__manifest__.py @@ -0,0 +1,14 @@ +# Copyright 2018 Therp BV +# Copyright 2022 Hunki Enterprises BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +{ + "name": "Autogenerated headers", + "version": "12.0.1.0.0", + "author": "Hunki Enterprises BV, Therp BV,Odoo Community Association (OCA)", + "license": "AGPL-3", + "category": "Tools", + "summary": "Add headers to Odoo's mails indicating they are autogenerated", + "depends": [ + 'mail', + ], +} diff --git a/mail_autogenerated_header/i18n/mail_autogenerated_header.pot b/mail_autogenerated_header/i18n/mail_autogenerated_header.pot new file mode 100644 index 000000000..af06f59b2 --- /dev/null +++ b/mail_autogenerated_header/i18n/mail_autogenerated_header.pot @@ -0,0 +1,30 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * mail_autogenerated_header +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.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_autogenerated_header +#: model:ir.model,name:mail_autogenerated_header.model_res_partner +msgid "Contact" +msgstr "" + +#. module: mail_autogenerated_header +#: model:ir.model,name:mail_autogenerated_header.model_mail_thread +msgid "Email Thread" +msgstr "" + +#. module: mail_autogenerated_header +#: model:ir.model,name:mail_autogenerated_header.model_ir_mail_server +msgid "Mail Server" +msgstr "" + diff --git a/mail_autogenerated_header/models/__init__.py b/mail_autogenerated_header/models/__init__.py new file mode 100644 index 000000000..af47c23c8 --- /dev/null +++ b/mail_autogenerated_header/models/__init__.py @@ -0,0 +1,6 @@ +# Copyright 2018 Therp BV +# Copyright 2022 Hunki Enterprises BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from . import ir_mail_server +from . import mail_thread +from . import res_partner diff --git a/mail_autogenerated_header/models/ir_mail_server.py b/mail_autogenerated_header/models/ir_mail_server.py new file mode 100644 index 000000000..badde4408 --- /dev/null +++ b/mail_autogenerated_header/models/ir_mail_server.py @@ -0,0 +1,55 @@ +# Copyright 2018 Therp BV +# Copyright 2022 Hunki Enterprises BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from odoo import api, models + + +class IrMailServer(models.Model): + _inherit = 'ir.mail_server' + + @api.model + def send_email( + self, message, mail_server_id=None, smtp_server=None, smtp_port=None, + smtp_user=None, smtp_password=None, smtp_encryption=None, + smtp_debug=False, smtp_session=None, + ): + """ Inject autogenerated header for autogoing mails """ + + if not self.env.context.get('mail_autogenerated_header_disable') and\ + self._send_email_set_autogenerated( + message, mail_server_id=mail_server_id, + smtp_server=smtp_server, smtp_port=smtp_port, + smtp_user=smtp_user, smtp_password=smtp_password, + smtp_encryption=smtp_encryption, smtp_debug=smtp_debug, + smtp_session=smtp_session, + ): + # MS Exchange's broken version as of + # http://blogs.technet.com/b/exchange/archive/2006/10/06/ + # 3395024.aspx + message['Precedence'] = 'bulk' + message['X-Auto-Response-Suppress'] = 'OOF' + # The right way to do it as of + # https://tools.ietf.org/html/rfc3834 + message['Auto-Submitted'] = 'auto-generated' + + return super(IrMailServer, self).send_email( + message, mail_server_id=mail_server_id, smtp_server=smtp_server, + smtp_port=smtp_port, smtp_user=smtp_user, + smtp_password=smtp_password, smtp_encryption=smtp_encryption, + smtp_debug=smtp_debug, smtp_session=smtp_session, + ) + + @api.model + def _send_email_set_autogenerated( + self, message, mail_server_id=None, smtp_server=None, smtp_port=None, + smtp_user=None, smtp_password=None, smtp_encryption=None, + smtp_debug=False, smtp_session=None, + ): + """Determine if some mail should have the autogenerated headers""" + + mail = self.env['mail.mail'].search([ + ('message_id', '=', message['Message-Id']), + ]) + if not mail: + return False + return mail.subtype_id != self.env.ref('mail.mt_comment') diff --git a/mail_autogenerated_header/models/mail_thread.py b/mail_autogenerated_header/models/mail_thread.py new file mode 100644 index 000000000..0fc5c6a87 --- /dev/null +++ b/mail_autogenerated_header/models/mail_thread.py @@ -0,0 +1,34 @@ +# Copyright 2018 Therp BV +# Copyright 2022 Hunki Enterprises BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +import logging +from odoo import api, models +_logger = logging.getLogger(__name__) + + +class MailThread(models.AbstractModel): + _inherit = 'mail.thread' + + @api.model + def message_route_process(self, message, message_dict, routes): + """ Set context key to suppress notification for autogenerated incoming + mails """ + if self._message_route_process_autoreply(message, message_dict, routes): + _logger.info( + 'Ignoring email %s from %s because it seems to be an auto ' + 'reply', message.get('Message-ID'), message.get('From'), + ) + self = self.with_context(mail_autogenerated_header=message) + return super(MailThread, self).message_route_process( + message, message_dict, routes, + ) + + @api.model + def _message_route_process_autoreply(self, message, message_dict, routes): + """ Determine if some message is an autoreply """ + return ( + message['Auto-Submitted'] and message['Auto-Submitted'] != 'no' or + message['X-Auto-Response-Suppress'] and set( + message['X-Auto-Response-Suppress'].split(', ') + ) & set('AutoReply', 'All') + ) diff --git a/mail_autogenerated_header/models/res_partner.py b/mail_autogenerated_header/models/res_partner.py new file mode 100644 index 000000000..ff276ca67 --- /dev/null +++ b/mail_autogenerated_header/models/res_partner.py @@ -0,0 +1,24 @@ +# Copyright 2022 Hunki Enterprises BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from odoo import api, models + + +class ResPartner(models.Model): + _inherit = 'res.partner' + + @api.model + def _notify( + self, message, rdata, record, force_send=False, + send_after_commit=True, model_description=False, + mail_auto_delete=True, + ): + """ Inhibit notifications if this is the notification for an incoming + autogenerated mail from another system """ + if self.env.context.get('mail_autogenerated_header'): + return True + return super()._notify( + message, rdata, record, force_send=force_send, + send_after_commit=send_after_commit, + model_description=model_description, + mail_auto_delete=mail_auto_delete, + ) diff --git a/mail_autogenerated_header/readme/CONTRIBUTORS.rst b/mail_autogenerated_header/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..33b6eb2c3 --- /dev/null +++ b/mail_autogenerated_header/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Holger Brunn (https://hunki-enterprises.com) diff --git a/mail_autogenerated_header/readme/DESCRIPTION.rst b/mail_autogenerated_header/readme/DESCRIPTION.rst new file mode 100644 index 000000000..bda994624 --- /dev/null +++ b/mail_autogenerated_header/readme/DESCRIPTION.rst @@ -0,0 +1,5 @@ +This module was written to mark Odoo's emails as being autogenerated according to `RFC 3834 `_, section 5. This allows receiving mail servers to act accordingly by for example not sending a vacation autoreply. + +On the receiving side, this module drops all notifications for autogenerated incoming e-mails. + +The combination of both avoids possible mail loops with misconfigured or broken email servers on the opposite side. diff --git a/mail_autogenerated_header/readme/USAGE.rst b/mail_autogenerated_header/readme/USAGE.rst new file mode 100644 index 000000000..8412aba96 --- /dev/null +++ b/mail_autogenerated_header/readme/USAGE.rst @@ -0,0 +1,5 @@ +There's nothing the user has to do. Developers can set the context flag +``mail_autogenerated_header_disable`` in calls to ``send_email`` in order to +suppress adding any headers at all, and override +``_message_route_process_autoreply`` to fine tune dropping autogenerated mails +per model. diff --git a/mail_autogenerated_header/readme/newsfragments/.gitkeep b/mail_autogenerated_header/readme/newsfragments/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/mail_autogenerated_header/static/description/icon.png b/mail_autogenerated_header/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_autogenerated_header/static/description/index.html b/mail_autogenerated_header/static/description/index.html new file mode 100644 index 000000000..f4263373b --- /dev/null +++ b/mail_autogenerated_header/static/description/index.html @@ -0,0 +1,431 @@ + + + + + + +Autogenerated headers + + + +
+

Autogenerated headers

+ + +

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

+

This module was written to mark Odoo’s emails as being autogenerated according to RFC 3834, section 5. This allows receiving mail servers to act accordingly by for example not sending a vacation autoreply.

+

On the receiving side, this module drops all notifications for autogenerated incoming e-mails.

+

The combination of both avoids possible mail loops with misconfigured or broken email servers on the opposite side.

+

Table of contents

+ +
+

Usage

+

There’s nothing the user has to do. Developers can set the context flag +mail_autogenerated_header_disable in calls to send_email in order to +suppress adding any headers at all, and override +_message_route_process_autoreply to fine tune dropping autogenerated mails +per model.

+
+
+

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

+
    +
  • Hunki Enterprises BV
  • +
  • Therp BV
  • +
+
+ +
+

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_autogenerated_header/tests/__init__.py b/mail_autogenerated_header/tests/__init__.py new file mode 100644 index 000000000..b707cdfc9 --- /dev/null +++ b/mail_autogenerated_header/tests/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2018 Therp BV +# Copyright 2022 Hunki Enterprises BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from . import test_mail_autogenerated_header diff --git a/mail_autogenerated_header/tests/test_mail_autogenerated_header.py b/mail_autogenerated_header/tests/test_mail_autogenerated_header.py new file mode 100644 index 000000000..5754e87d7 --- /dev/null +++ b/mail_autogenerated_header/tests/test_mail_autogenerated_header.py @@ -0,0 +1,63 @@ +# Copyright 2018 Therp BV +# Copyright 2022 Hunki Enterprises BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from odoo.tests.common import TransactionCase +from odoo.tools.mail import generate_tracking_message_id + + +class TestMailAutogeneratedHeader(TransactionCase): + def setUp(self): + super().setUp() + self.mail = self.env['mail.mail'].create({ + 'subject': 'testmessage', + 'email_from': 'test@test.com', + 'email_to': 'test@test.com', + 'message_id': 'message_id', + }) + self.message = self.env['ir.mail_server'].build_email( + [self.mail.email_from], [self.mail.email_to], self.mail.subject, '', + message_id=self.mail.message_id, + ) + + def test_sending(self): + """ Test that sending a mail has the Auto-Submitted header """ + self.env['ir.mail_server'].send_email(self.message) + self.assertEqual(self.message['Auto-Submitted'], 'auto-generated') + + def test_receiving(self): + """ Test that receiving mails with some auto submitted marker won't + cause new notifications being sent """ + demo_user = self.env.ref('base.user_demo') + self.message.replace_header( + 'Message-Id', generate_tracking_message_id(42), + ) + partner_id = self.env['mail.thread'].message_process( + 'res.partner', self.message.as_string(), + ) + partner = self.env['res.partner'].browse(partner_id) + partner.message_subscribe(partner_ids=demo_user.partner_id.ids) + reply = self.message + reply['References'] = self.message['Message-Id'] + reply.replace_header('Message-Id', 'message_id3') + thread_id = self.env['mail.thread'].message_process( + 'res.partner', reply.as_string(), + ) + self.assertEqual(thread_id, partner.id) + notifications = self.env['mail.notification'].search([ + ('res_partner_id', '=', demo_user.partner_id.id) + ]) + # mail is not autogenerated, should have generated mails + self.assertTrue(notifications.is_email) + notifications.unlink() + + reply.replace_header('Message-Id', 'message_id4') + reply['Auto-Submitted'] = 'auto-generated' + thread_id = self.env['mail.thread'].message_process( + 'res.partner', reply.as_string(), + ) + self.assertEqual(thread_id, partner.id) + notifications = self.env['mail.notification'].search([ + ('res_partner_id', '=', demo_user.partner_id.id) + ]) + # mail is autogenerated, shouldn't have generated mails + self.assertFalse(notifications.is_email) From d8dee53bc5522c95011300cdccf0d181fa27cfa7 Mon Sep 17 00:00:00 2001 From: Tom Blauwendraat Date: Tue, 8 Nov 2022 09:29:21 +0100 Subject: [PATCH 2/9] [FIX] pre-commit --- mail_autogenerated_header/README.rst | 15 +++++--- mail_autogenerated_header/__manifest__.py | 1 + .../static/description/index.html | 38 ++++++++++--------- 3 files changed, 30 insertions(+), 24 deletions(-) diff --git a/mail_autogenerated_header/README.rst b/mail_autogenerated_header/README.rst index d0d6f1055..7d27426fc 100644 --- a/mail_autogenerated_header/README.rst +++ b/mail_autogenerated_header/README.rst @@ -2,10 +2,13 @@ Autogenerated headers ===================== -.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:c85cef2766e4f4e18f525f38d82ccee67b9e934eee4ca3cccd9ae68783d11a26 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png :target: https://odoo-community.org/page/development-status @@ -19,11 +22,11 @@ Autogenerated headers .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png :target: https://translation.odoo-community.org/projects/social-12-0/social-12-0-mail_autogenerated_header :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/12.0 - :alt: Try me on Runbot +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/social&target_branch=12.0 + :alt: Try me on Runboat -|badge1| |badge2| |badge3| |badge4| |badge5| +|badge1| |badge2| |badge3| |badge4| |badge5| This module was written to mark Odoo's emails as being autogenerated according to `RFC 3834 `_, section 5. This allows receiving mail servers to act accordingly by for example not sending a vacation autoreply. @@ -50,7 +53,7 @@ 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 +If you spotted it first, help us to smash it by providing a detailed and welcomed `feedback `_. Do not contact contributors directly about support or help with technical issues. diff --git a/mail_autogenerated_header/__manifest__.py b/mail_autogenerated_header/__manifest__.py index b79adfa47..69b104fc6 100644 --- a/mail_autogenerated_header/__manifest__.py +++ b/mail_autogenerated_header/__manifest__.py @@ -5,6 +5,7 @@ "name": "Autogenerated headers", "version": "12.0.1.0.0", "author": "Hunki Enterprises BV, Therp BV,Odoo Community Association (OCA)", + "website": "https://github.com/OCA/social", "license": "AGPL-3", "category": "Tools", "summary": "Add headers to Odoo's mails indicating they are autogenerated", diff --git a/mail_autogenerated_header/static/description/index.html b/mail_autogenerated_header/static/description/index.html index f4263373b..0ae309162 100644 --- a/mail_autogenerated_header/static/description/index.html +++ b/mail_autogenerated_header/static/description/index.html @@ -1,20 +1,20 @@ - + - + Autogenerated headers -
-

Autogenerated headers

+
+ + +Odoo Community Association + +
+

Autogenerated headers

-

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

+

Beta License: AGPL-3 OCA/mail Translate me on Weblate Try me on Runboat

This module was written to mark Odoo’s emails as being autogenerated according to RFC 3834, section 5. This allows receiving mail servers to act accordingly by for example @@ -392,7 +397,7 @@

Autogenerated headers

-

Usage

+

Usage

There’s nothing the user has to do. Developers can set the context flag mail_autogenerated_header_disable in calls to send_email in order to suppress adding any headers at all, and override @@ -400,31 +405,31 @@

Usage

mails per model.

-

Bug Tracker

-

Bugs are tracked on GitHub Issues. +

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 to smash it by providing a detailed and welcomed -feedback.

+feedback.

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

-

Credits

+

Credits

-

Authors

+

Authors

  • Hunki Enterprises BV
  • Therp BV
-

Maintainers

+

Maintainers

This module is maintained by the OCA.

Odoo Community Association @@ -432,10 +437,11 @@

Maintainers

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.

+

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

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

+
diff --git a/mail_autogenerated_header/tests/test_mail_autogenerated_header.py b/mail_autogenerated_header/tests/test_mail_autogenerated_header.py index f018da2ba..7a03fc3fe 100644 --- a/mail_autogenerated_header/tests/test_mail_autogenerated_header.py +++ b/mail_autogenerated_header/tests/test_mail_autogenerated_header.py @@ -1,14 +1,16 @@ # Copyright 2018 Therp BV # Copyright 2022 Hunki Enterprises BV # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). -from odoo.tests.common import TransactionCase from odoo.tools.mail import generate_tracking_message_id +from odoo.addons.base.tests.common import BaseCommon -class TestMailAutogeneratedHeader(TransactionCase): - def setUp(self): - super().setUp() - self.mail = self.env["mail.mail"].create( + +class TestMailAutogeneratedHeader(BaseCommon): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.mail = cls.env["mail.mail"].create( { "subject": "testmessage", "email_from": "test@test.com", @@ -16,12 +18,12 @@ def setUp(self): "message_id": "message_id", } ) - self.message = self.env["ir.mail_server"].build_email( - [self.mail.email_from], - [self.mail.email_to], - self.mail.subject, + cls.message = cls.env["ir.mail_server"].build_email( + [cls.mail.email_from], + [cls.mail.email_to], + cls.mail.subject, "", - message_id=self.mail.message_id, + message_id=cls.mail.message_id, ) def test_sending(self): From ae52d3d238ede5fe1fb8e208091769c832e19df3 Mon Sep 17 00:00:00 2001 From: LauraCForgeFlow Date: Fri, 4 Jul 2025 14:33:52 +0200 Subject: [PATCH 7/9] [IMP] mail_autogenerated_header: system parameter to allow autogenerated outgoing mails --- mail_autogenerated_header/README.rst | 17 +++-- mail_autogenerated_header/__manifest__.py | 7 +- .../data/ir_config_parameter.xml | 7 ++ .../models/ir_mail_server.py | 66 ++++++++++--------- .../readme/DESCRIPTION.md | 7 +- mail_autogenerated_header/readme/USAGE.md | 15 +++-- .../static/description/index.html | 16 +++-- .../tests/test_mail_autogenerated_header.py | 28 ++++---- 8 files changed, 96 insertions(+), 67 deletions(-) create mode 100644 mail_autogenerated_header/data/ir_config_parameter.xml diff --git a/mail_autogenerated_header/README.rst b/mail_autogenerated_header/README.rst index 3e7935db2..9f592d172 100644 --- a/mail_autogenerated_header/README.rst +++ b/mail_autogenerated_header/README.rst @@ -11,7 +11,7 @@ Autogenerated headers !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:591306323a242f6435b223e7ce1e718218d0db0b0fd45c776fa0e6715d168207 + !! source digest: sha256:0dd822572bebd34c9e428fe8f7cd191012396cd99b1655fa61c5cbd8dd572bf8 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png @@ -33,9 +33,9 @@ Autogenerated headers |badge1| |badge2| |badge3| |badge4| |badge5| This module was written to mark Odoo's emails as being autogenerated -according to `RFC 3834 `__, section -5. This allows receiving mail servers to act accordingly by for example -not sending a vacation autoreply. +according to ``RFC 3834 ``\ \_, +section 5. This allows receiving mail servers to act accordingly by for +example not sending a vacation autoreply. On the receiving side, this module drops all notifications for autogenerated incoming e-mails. @@ -51,9 +51,14 @@ broken email servers on the opposite side. Usage ===== -There's nothing the user has to do. Developers can set the context flag +For sending outgoing emails, users can change the config parameter +``mail_autogenerated_header.allow_autogenerated_outgoing`` to ``False`` +to avoid any outgoing emails being marked as autogenerated. For only +avoiding in certain cases, developers can set the context flag ``mail_autogenerated_header_disable`` in calls to ``send_email`` in -order to suppress adding any headers at all, and override +order to suppress adding any autogenerated headers. + +For receiving incoming emails, developers can override the method ``_message_route_process_autoreply`` to fine tune dropping autogenerated mails per model. diff --git a/mail_autogenerated_header/__manifest__.py b/mail_autogenerated_header/__manifest__.py index 2a6118158..947876d36 100644 --- a/mail_autogenerated_header/__manifest__.py +++ b/mail_autogenerated_header/__manifest__.py @@ -3,13 +3,12 @@ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). { "name": "Autogenerated headers", - "version": "18.0.1.0.0", + "version": "18.0.1.1.0", "author": "Hunki Enterprises BV, Therp BV,Odoo Community Association (OCA)", "website": "https://github.com/OCA/mail", "license": "AGPL-3", "category": "Tools", "summary": "Add headers to Odoo's mails indicating they are autogenerated", - "depends": [ - "mail", - ], + "depends": ["mail"], + "data": ["data/ir_config_parameter.xml"], } diff --git a/mail_autogenerated_header/data/ir_config_parameter.xml b/mail_autogenerated_header/data/ir_config_parameter.xml new file mode 100644 index 000000000..8d4cfc3e6 --- /dev/null +++ b/mail_autogenerated_header/data/ir_config_parameter.xml @@ -0,0 +1,7 @@ + + + + mail_autogenerated_header.allow_autogenerated_outgoing + True + + diff --git a/mail_autogenerated_header/models/ir_mail_server.py b/mail_autogenerated_header/models/ir_mail_server.py index eb387f9c3..e6031ca30 100644 --- a/mail_autogenerated_header/models/ir_mail_server.py +++ b/mail_autogenerated_header/models/ir_mail_server.py @@ -22,31 +22,40 @@ def send_email( smtp_debug=False, smtp_session=None, ): - # Inject autogenerated header for autogoing mails - - if not self.env.context.get( - "mail_autogenerated_header_disable" - ) and self._send_email_set_autogenerated( - message, - mail_server_id=mail_server_id, - smtp_server=smtp_server, - smtp_port=smtp_port, - smtp_user=smtp_user, - smtp_password=smtp_password, - smtp_encryption=smtp_encryption, - smtp_ssl_certificate=smtp_ssl_certificate, - smtp_ssl_private_key=smtp_ssl_private_key, - smtp_debug=smtp_debug, - smtp_session=smtp_session, - ): - # MS Exchange's broken version as of - # http://blogs.technet.com/b/exchange/archive/2006/10/06/ - # 3395024.aspx - message["Precedence"] = "bulk" - message["X-Auto-Response-Suppress"] = "OOF" - # The right way to do it as of - # https://tools.ietf.org/html/rfc3834 - message["Auto-Submitted"] = "auto-generated" + # Inject autogenerated header for outgoing mails + allow_autogenerated_outgoing = ( + self.env["ir.config_parameter"] + .sudo() + .get_param("mail_autogenerated_header.allow_autogenerated_outgoing", False) + ) + if allow_autogenerated_outgoing: + mail_autogenerated_header_disable = self.env.context.get( + "mail_autogenerated_header_disable" + ) + if ( + not mail_autogenerated_header_disable + and self._send_email_set_autogenerated( + message, + mail_server_id=mail_server_id, + smtp_server=smtp_server, + smtp_port=smtp_port, + smtp_user=smtp_user, + smtp_password=smtp_password, + smtp_encryption=smtp_encryption, + smtp_ssl_certificate=smtp_ssl_certificate, + smtp_ssl_private_key=smtp_ssl_private_key, + smtp_debug=smtp_debug, + smtp_session=smtp_session, + ) + ): + # MS Exchange's broken version as of + # http://blogs.technet.com/b/exchange/archive/2006/10/06/ + # 3395024.aspx + message["Precedence"] = "bulk" + message["X-Auto-Response-Suppress"] = "OOF" + # The right way to do it as of + # https://tools.ietf.org/html/rfc3834 + message["Auto-Submitted"] = "auto-generated" return super().send_email( message, @@ -77,12 +86,9 @@ def _send_email_set_autogenerated( smtp_debug=False, smtp_session=None, ): - """Determine if some mail should have the autogenerated headers""" - + # Determine if some mail should have the autogenerated headers mail = self.env["mail.mail"].search( - [ - ("message_id", "=", message["Message-Id"]), - ] + [("message_id", "=", message["Message-Id"])] ) if not mail: return False diff --git a/mail_autogenerated_header/readme/DESCRIPTION.md b/mail_autogenerated_header/readme/DESCRIPTION.md index 3e17a4d4f..9f26a0b86 100644 --- a/mail_autogenerated_header/readme/DESCRIPTION.md +++ b/mail_autogenerated_header/readme/DESCRIPTION.md @@ -1,7 +1,6 @@ -This module was written to mark Odoo's emails as being autogenerated -according to [RFC 3834](https://tools.ietf.org/html/rfc3834), section 5. -This allows receiving mail servers to act accordingly by for example not -sending a vacation autoreply. +This module was written to mark Odoo's emails as being autogenerated according +to `RFC 3834 `_, section 5. This allows +receiving mail servers to act accordingly by for example not sending a vacation autoreply. On the receiving side, this module drops all notifications for autogenerated incoming e-mails. diff --git a/mail_autogenerated_header/readme/USAGE.md b/mail_autogenerated_header/readme/USAGE.md index 34380206c..d0e8e8885 100644 --- a/mail_autogenerated_header/readme/USAGE.md +++ b/mail_autogenerated_header/readme/USAGE.md @@ -1,5 +1,10 @@ -There's nothing the user has to do. Developers can set the context flag -`mail_autogenerated_header_disable` in calls to `send_email` in order to -suppress adding any headers at all, and override -`_message_route_process_autoreply` to fine tune dropping autogenerated -mails per model. +For sending outgoing emails, users can change the config parameter +``mail_autogenerated_header.allow_autogenerated_outgoing`` to ``False`` to +avoid any outgoing emails being marked as autogenerated. For only avoiding +in certain cases, developers can set the context flag +``mail_autogenerated_header_disable`` in calls to ``send_email`` in order to +suppress adding any autogenerated headers. + +For receiving incoming emails, developers can override the method +``_message_route_process_autoreply`` to fine tune dropping autogenerated mails +per model. diff --git a/mail_autogenerated_header/static/description/index.html b/mail_autogenerated_header/static/description/index.html index 443b39a36..d5520f1a0 100644 --- a/mail_autogenerated_header/static/description/index.html +++ b/mail_autogenerated_header/static/description/index.html @@ -372,13 +372,13 @@

Autogenerated headers

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:591306323a242f6435b223e7ce1e718218d0db0b0fd45c776fa0e6715d168207 +!! source digest: sha256:0dd822572bebd34c9e428fe8f7cd191012396cd99b1655fa61c5cbd8dd572bf8 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Beta License: AGPL-3 OCA/mail Translate me on Weblate Try me on Runboat

This module was written to mark Odoo’s emails as being autogenerated -according to RFC 3834, section -5. This allows receiving mail servers to act accordingly by for example -not sending a vacation autoreply.

+according to RFC 3834 <https://tools.ietf.org/html/rfc3834>_, +section 5. This allows receiving mail servers to act accordingly by for +example not sending a vacation autoreply.

On the receiving side, this module drops all notifications for autogenerated incoming e-mails.

The combination of both avoids possible mail loops with misconfigured or @@ -398,9 +398,13 @@

Autogenerated headers

Usage

-

There’s nothing the user has to do. Developers can set the context flag +

For sending outgoing emails, users can change the config parameter +mail_autogenerated_header.allow_autogenerated_outgoing to False +to avoid any outgoing emails being marked as autogenerated. For only +avoiding in certain cases, developers can set the context flag mail_autogenerated_header_disable in calls to send_email in -order to suppress adding any headers at all, and override +order to suppress adding any autogenerated headers.

+

For receiving incoming emails, developers can override the method _message_route_process_autoreply to fine tune dropping autogenerated mails per model.

diff --git a/mail_autogenerated_header/tests/test_mail_autogenerated_header.py b/mail_autogenerated_header/tests/test_mail_autogenerated_header.py index 7a03fc3fe..2e6039435 100644 --- a/mail_autogenerated_header/tests/test_mail_autogenerated_header.py +++ b/mail_autogenerated_header/tests/test_mail_autogenerated_header.py @@ -1,6 +1,8 @@ # Copyright 2018 Therp BV # Copyright 2022 Hunki Enterprises BV # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +import copy + from odoo.tools.mail import generate_tracking_message_id from odoo.addons.base.tests.common import BaseCommon @@ -18,7 +20,7 @@ def setUpClass(cls): "message_id": "message_id", } ) - cls.message = cls.env["ir.mail_server"].build_email( + cls.base_message = cls.env["ir.mail_server"].build_email( [cls.mail.email_from], [cls.mail.email_to], cls.mail.subject, @@ -28,25 +30,29 @@ def setUpClass(cls): def test_sending(self): """Test that sending a mail has the Auto-Submitted header""" + self.message = copy.deepcopy(self.base_message) self.env["ir.mail_server"].send_email(self.message) self.assertEqual(self.message["Auto-Submitted"], "auto-generated") + # Test that the header is not set when the parameter is disabled + self.env["ir.config_parameter"].sudo().set_param( + "mail_autogenerated_header.allow_autogenerated_outgoing", False + ) + self.message = copy.deepcopy(self.base_message) + self.env["ir.mail_server"].send_email(self.message) + self.assertNotIn("Auto-Submitted", self.message) def test_receiving(self): """Test that receiving mails with some auto submitted marker won't cause new notifications being sent""" + self.message = copy.deepcopy(self.base_message) demo_user = self.env.ref("base.user_demo") - self.message.replace_header( - "Message-Id", - generate_tracking_message_id(42), - ) - + self.message.replace_header("Message-Id", generate_tracking_message_id(42)) self.env["mail.notification"].search( [("res_partner_id", "=", demo_user.partner_id.id)] ).unlink() partner_id = self.env["mail.thread"].message_process( - "res.partner", - self.message.as_string(), + "res.partner", self.message.as_string() ) partner = self.env["res.partner"].browse(partner_id) partner.message_subscribe(partner_ids=demo_user.partner_id.ids) @@ -54,8 +60,7 @@ def test_receiving(self): reply["References"] = self.message["Message-Id"] reply.replace_header("Message-Id", "message_id3") thread_id = self.env["mail.thread"].message_process( - "res.partner", - reply.as_string(), + "res.partner", reply.as_string() ) self.assertEqual(thread_id, partner.id) notifications = self.env["mail.notification"].search( @@ -68,8 +73,7 @@ def test_receiving(self): reply.replace_header("Message-Id", "message_id4") reply["Auto-Submitted"] = "auto-generated" thread_id = self.env["mail.thread"].message_process( - "res.partner", - reply.as_string(), + "res.partner", reply.as_string() ) self.assertEqual(thread_id, partner.id) notifications = self.env["mail.notification"].search( From ca57cffcc1160a8be07ad5fb7ebab45dbfbb63e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Paradis?= Date: Wed, 15 Apr 2026 14:42:21 +0000 Subject: [PATCH 8/9] [IMP] mail_autogenerated_header: pre-commit auto fixes --- mail_autogenerated_header/models/mail_thread.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mail_autogenerated_header/models/mail_thread.py b/mail_autogenerated_header/models/mail_thread.py index dbc85e557..7b6338b2c 100644 --- a/mail_autogenerated_header/models/mail_thread.py +++ b/mail_autogenerated_header/models/mail_thread.py @@ -16,7 +16,7 @@ def _message_route_process(self, message, message_dict, routes): # Set context key to suppress notification for autogenerated incoming mails if self._message_route_process_autoreply(message, message_dict, routes): _logger.info( - "Ignoring email %s from %s because it seems to be an auto " "reply", + "Ignoring email %s from %s because it seems to be an auto reply", message.get("Message-ID"), message.get("From"), ) From 785a5e0caed3725f006fb8fff37e97212e0c3688 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Paradis?= Date: Wed, 15 Apr 2026 14:42:21 +0000 Subject: [PATCH 9/9] [MIG] mail_autogenerated_header: Migration to 19.0 --- mail_autogenerated_header/README.rst | 10 ++-- mail_autogenerated_header/__manifest__.py | 2 +- .../models/ir_mail_server.py | 3 +- .../static/description/index.html | 6 +-- .../tests/test_mail_autogenerated_header.py | 46 ++++++++++++++++--- 5 files changed, 51 insertions(+), 16 deletions(-) diff --git a/mail_autogenerated_header/README.rst b/mail_autogenerated_header/README.rst index 9f592d172..d7c1a6739 100644 --- a/mail_autogenerated_header/README.rst +++ b/mail_autogenerated_header/README.rst @@ -21,13 +21,13 @@ Autogenerated headers :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fmail-lightgray.png?logo=github - :target: https://github.com/OCA/mail/tree/18.0/mail_autogenerated_header + :target: https://github.com/OCA/mail/tree/19.0/mail_autogenerated_header :alt: OCA/mail .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/mail-18-0/mail-18-0-mail_autogenerated_header + :target: https://translation.odoo-community.org/projects/mail-19-0/mail-19-0-mail_autogenerated_header :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png - :target: https://runboat.odoo-community.org/builds?repo=OCA/mail&target_branch=18.0 + :target: https://runboat.odoo-community.org/builds?repo=OCA/mail&target_branch=19.0 :alt: Try me on Runboat |badge1| |badge2| |badge3| |badge4| |badge5| @@ -68,7 +68,7 @@ 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 to smash it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -100,6 +100,6 @@ 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/mail `_ project on GitHub. +This module is part of the `OCA/mail `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/mail_autogenerated_header/__manifest__.py b/mail_autogenerated_header/__manifest__.py index 947876d36..9ec9b6ab6 100644 --- a/mail_autogenerated_header/__manifest__.py +++ b/mail_autogenerated_header/__manifest__.py @@ -3,7 +3,7 @@ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). { "name": "Autogenerated headers", - "version": "18.0.1.1.0", + "version": "19.0.1.0.0", "author": "Hunki Enterprises BV, Therp BV,Odoo Community Association (OCA)", "website": "https://github.com/OCA/mail", "license": "AGPL-3", diff --git a/mail_autogenerated_header/models/ir_mail_server.py b/mail_autogenerated_header/models/ir_mail_server.py index e6031ca30..08dfcb4ff 100644 --- a/mail_autogenerated_header/models/ir_mail_server.py +++ b/mail_autogenerated_header/models/ir_mail_server.py @@ -2,6 +2,7 @@ # Copyright 2022 Hunki Enterprises BV # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). from odoo import api, models +from odoo.fields import Domain class IrMailServer(models.Model): @@ -88,7 +89,7 @@ def _send_email_set_autogenerated( ): # Determine if some mail should have the autogenerated headers mail = self.env["mail.mail"].search( - [("message_id", "=", message["Message-Id"])] + Domain("message_id", "=", message["Message-Id"]) ) if not mail: return False diff --git a/mail_autogenerated_header/static/description/index.html b/mail_autogenerated_header/static/description/index.html index d5520f1a0..4a62c4fb3 100644 --- a/mail_autogenerated_header/static/description/index.html +++ b/mail_autogenerated_header/static/description/index.html @@ -374,7 +374,7 @@

Autogenerated headers

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! source digest: sha256:0dd822572bebd34c9e428fe8f7cd191012396cd99b1655fa61c5cbd8dd572bf8 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

Beta License: AGPL-3 OCA/mail Translate me on Weblate Try me on Runboat

+

Beta License: AGPL-3 OCA/mail Translate me on Weblate Try me on Runboat

This module was written to mark Odoo’s emails as being autogenerated according to RFC 3834 <https://tools.ietf.org/html/rfc3834>_, section 5. This allows receiving mail servers to act accordingly by for @@ -413,7 +413,7 @@

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 to smash it by providing a detailed and welcomed -feedback.

+feedback.

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

@@ -441,7 +441,7 @@

Maintainers

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/mail project on GitHub.

+

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

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

diff --git a/mail_autogenerated_header/tests/test_mail_autogenerated_header.py b/mail_autogenerated_header/tests/test_mail_autogenerated_header.py index 2e6039435..2f297c1bd 100644 --- a/mail_autogenerated_header/tests/test_mail_autogenerated_header.py +++ b/mail_autogenerated_header/tests/test_mail_autogenerated_header.py @@ -3,6 +3,7 @@ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). import copy +from odoo.fields import Command from odoo.tools.mail import generate_tracking_message_id from odoo.addons.base.tests.common import BaseCommon @@ -20,7 +21,7 @@ def setUpClass(cls): "message_id": "message_id", } ) - cls.base_message = cls.env["ir.mail_server"].build_email( + cls.base_message = cls.env["ir.mail_server"]._build_email__( [cls.mail.email_from], [cls.mail.email_to], cls.mail.subject, @@ -28,6 +29,40 @@ def setUpClass(cls): message_id=cls.mail.message_id, ) + cls.partner = cls.env["res.partner"].create( + { + "name": "Marc Demo", + "company_id": cls.env.ref("base.main_company").id, + "company_name": "YourCompany", + "street": "3575 Buena Vista Avenue", + "city": "Eugene", + "state_id": cls.env.ref("base.state_us_32").id, + "zip": "97401", + "country_id": cls.env.ref("base.us").id, + "tz": "Europe/Brussels", + "email": "mark.brown23@example.com", + "phone": "(441)-695-2334", + } + ) + cls.user = cls.env["res.users"].create( + { + "partner_id": cls.partner.id, + "login": "demo", + "password": "demo", + "signature": "--
Mr Demo
", + "company_id": cls.env.ref("base.main_company").id, + "group_ids": [ + Command.set( + [ + cls.env.ref("base.group_user").id, + cls.env.ref("base.group_partner_manager").id, + cls.env.ref("base.group_allow_export").id, + ] + ) + ], + } + ) + def test_sending(self): """Test that sending a mail has the Auto-Submitted header""" self.message = copy.deepcopy(self.base_message) @@ -45,17 +80,16 @@ def test_receiving(self): """Test that receiving mails with some auto submitted marker won't cause new notifications being sent""" self.message = copy.deepcopy(self.base_message) - demo_user = self.env.ref("base.user_demo") self.message.replace_header("Message-Id", generate_tracking_message_id(42)) self.env["mail.notification"].search( - [("res_partner_id", "=", demo_user.partner_id.id)] + [("res_partner_id", "=", self.user.partner_id.id)] ).unlink() partner_id = self.env["mail.thread"].message_process( "res.partner", self.message.as_string() ) partner = self.env["res.partner"].browse(partner_id) - partner.message_subscribe(partner_ids=demo_user.partner_id.ids) + partner.message_subscribe(partner_ids=self.user.partner_id.ids) reply = self.message reply["References"] = self.message["Message-Id"] reply.replace_header("Message-Id", "message_id3") @@ -64,7 +98,7 @@ def test_receiving(self): ) self.assertEqual(thread_id, partner.id) notifications = self.env["mail.notification"].search( - [("res_partner_id", "=", demo_user.partner_id.id)] + [("res_partner_id", "=", self.user.partner_id.id)] ) # mail is not autogenerated, should have generated mails self.assertTrue(notifications.notification_type == "email") @@ -77,7 +111,7 @@ def test_receiving(self): ) self.assertEqual(thread_id, partner.id) notifications = self.env["mail.notification"].search( - [("res_partner_id", "=", demo_user.partner_id.id)] + [("res_partner_id", "=", self.user.partner_id.id)] ) # mail is autogenerated, shouldn't have generated mails self.assertFalse(notifications.notification_type == "email")