diff --git a/mail_autogenerated_header/README.rst b/mail_autogenerated_header/README.rst new file mode 100644 index 00000000..702d4124 --- /dev/null +++ b/mail_autogenerated_header/README.rst @@ -0,0 +1,61 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :target: https://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +===================== +Autogenerated headers +===================== + +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 autogenerated incoming e-mails. + +The combination of both avoids possible mail loops with misconfigured or broken email servers on the opposite side. + +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_drop_autoreply`` to fine tune dropping autogenerated mails per model. + +Known issues / Roadmap +====================== + +* a configuration of this per message subtype would be nice + +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. + +Credits +======= + +Images +------ + +* Odoo Community Association: `Icon `_. + +Contributors +------------ + +* Holger Brunn + +Do not contact contributors directly about help with questions or problems concerning this addon, but use the `community mailing list `_ or the `appropriate specialized mailinglist `_ for help, and the bug tracker linked in `Bug Tracker`_ above for technical issues. + +Maintainer +---------- + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +This module is maintained by the OCA. + +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. + +To contribute to this module, please visit https://odoo-community.org. diff --git a/mail_autogenerated_header/__init__.py b/mail_autogenerated_header/__init__.py new file mode 100644 index 00000000..24223449 --- /dev/null +++ b/mail_autogenerated_header/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 Therp 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 00000000..064256be --- /dev/null +++ b/mail_autogenerated_header/__manifest__.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 Therp BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +{ + "name": "Autogenerated headers", + "version": "10.0.1.0.0", + "author": "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/models/__init__.py b/mail_autogenerated_header/models/__init__.py new file mode 100644 index 00000000..a459005a --- /dev/null +++ b/mail_autogenerated_header/models/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 Therp BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from . import ir_mail_server +from . import mail_thread 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 00000000..7dfb6fa1 --- /dev/null +++ b/mail_autogenerated_header/models/ir_mail_server.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +# © 2018 Therp 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 + ): + 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, + ): + # 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, + ) + + @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 + ): + """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 00000000..fe5f1ea6 --- /dev/null +++ b/mail_autogenerated_header/models/mail_thread.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +# © 2018 Therp 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( + self, message, message_dict, model=None, thread_id=None, + custom_values=None + ): + if message['Auto-Submitted'] and message['Auto-Submitted'] != 'no': + if self._message_route_drop_autoreply( + message, message_dict, model=model, thread_id=thread_id, + custom_values=custom_values + ): + return [] + return super(MailThread, self).message_route( + message, message_dict, model=model, thread_id=thread_id, + custom_values=custom_values + ) + + @api.model + def _message_route_drop_autoreply( + self, message, message_dict, model=None, thread_id=None, + custom_values=None + ): + """React on an autoreply, return True if the mail should be dropped, + False otherwise""" + _logger.info( + 'ignoring email %s from %s because it seems to be an auto ' + 'reply', message.get('Message-ID'), message.get('From'), + ) + return True diff --git a/mail_autogenerated_header/static/description/icon.png b/mail_autogenerated_header/static/description/icon.png new file mode 100644 index 00000000..3a0328b5 Binary files /dev/null and b/mail_autogenerated_header/static/description/icon.png differ diff --git a/mail_autogenerated_header/tests/__init__.py b/mail_autogenerated_header/tests/__init__.py new file mode 100644 index 00000000..a1c34a83 --- /dev/null +++ b/mail_autogenerated_header/tests/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 Therp 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 00000000..d5dbfc0f --- /dev/null +++ b/mail_autogenerated_header/tests/test_mail_autogenerated_header.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 Therp BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from openerp.tests.common import TransactionCase + + +class TestMailAutogeneratedHeader(TransactionCase): + def test_mail_autogenerated_header(self): + # sending + mail = self.env['mail.mail'].create({ + 'subject': 'testmessage', + 'email_from': 'test@test.com', + 'email_to': 'test@test.com', + 'message_id': 'message_id', + }) + message = self.env['ir.mail_server'].build_email( + [mail.email_from], [mail.email_to], mail.subject, '', + message_id=mail.message_id, + ) + self.env['ir.mail_server'].send_email(message) + self.assertEqual(message['Auto-Submitted'], 'auto-generated') + + # receiving + message.replace_header('Message-Id', 'message_id2') + thread_id = self.env['mail.thread'].message_process( + 'res.partner', message.as_string(), + ) + self.assertFalse(thread_id) + del message['Auto-Submitted'] + thread_id = self.env['mail.thread'].message_process( + 'res.partner', message.as_string(), + ) + self.assertTrue(thread_id)