Skip to content
This repository has been archived by the owner on Nov 22, 2024. It is now read-only.

feat: mail_no_autoresponders #22

Draft
wants to merge 2 commits into
base: 15.0
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions mail_no_autoresponders/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Mail No AutoResponders
-----------------
- [#19] - Added option to disable auto responders
2 changes: 2 additions & 0 deletions mail_no_autoresponders/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import models
from . import tests
17 changes: 17 additions & 0 deletions mail_no_autoresponders/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "Mail No Autoresponders",
"summary": """
Disable autoresponders for mail
""",
"author": "Glo Networks",
"website": "http://glodo.uk",
"category": "Discuss",
"version": "15.0.0.0.0",
"depends": ["mail"],
"data": [
],
"external_dependencies": {"python": [], "bin": []},
"application": False,
"demo": [],
"license": "Other proprietary",
}
1 change: 1 addition & 0 deletions mail_no_autoresponders/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import mail_thread
88 changes: 88 additions & 0 deletions mail_no_autoresponders/models/mail_thread.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import ast
import logging
from odoo import models, tools

AUTO_RESPOND_HEADERS = {
# header: [valuestoignore]
"X-Auto-Response-Suppress": None,
"X-Autoreply": None,
"X-Autorespond": None,
"Auto-Submitted": ["no"],
}

_logger = logging.getLogger(__name__)


class MailThread(models.AbstractModel):
_inherit = "mail.thread"

def _is_auto_response_email_message(self, message):
# Check if any auto respond headers are present in the original email.
# If they are, then we need to suppress the bounce.
for key, values_to_ignore in AUTO_RESPOND_HEADERS.items():
if key not in message:
continue

# Header was present, we need to check the value to see if it matches
# a value we can skip
if values_to_ignore and message.get(key) in values_to_ignore:
continue

# Header was present, but we don't need to check the value
return True

def _routing_create_bounce_email(
self, email_from, body_html, message, **mail_values
):
# Drop any auto responses without sending a bounce at risk of infinite
# loops

# Find where we're sending the bounce to
bounce_to = tools.decode_message_header(message, "Return-Path") or email_from

if self._is_auto_response_email_message(message):
_logger.info(
"Dropping bounce response to %s due to detected auto-response"
" header" % (bounce_to)
)
return

# Use the built in blacklist
blacklisted = self.env["mail.blacklist"].search_count(
[("email", "=", bounce_to)]
)

if blacklisted > 0:
_logger.info(
"Dropping bounce response to %s due to being on mail.blacklist"
% (bounce_to)
)
return

# We need to add some indicators to suggest this bounce shouldn't get a
# response from dumb auto responders
extra_headers = {
"X-Auto-Response-Suppress": "All",
"Auto-submitted": "auto-replied",
}

# If we've got a string headers immediately convert it to a real dict,
# if we can
if mail_values.get("headers") and isinstance(mail_values.get("headers"), str):
try:
original_headers = ast.literal_eval(mail_values["headers"])
mail_values.update(original_headers)
except Exception:
# This is safe to drop because thats what upstream does if the
# decoding fails
del mail_values["headers"]

# Now add our extra headers
if isinstance(mail_values.get("headers"), dict):
mail_values["headers"].update(extra_headers)
else:
mail_values["headers"] = extra_headers

return super()._routing_create_bounce_email(
email_from, body_html, message, **mail_values
)
1 change: 1 addition & 0 deletions mail_no_autoresponders/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import test_mail_thread
47 changes: 47 additions & 0 deletions mail_no_autoresponders/tests/test_mail_thread.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from email.mime.multipart import MIMEMultipart

from odoo.tests.common import TransactionCase, tagged
from odoo import models, tools


class TestMailThread(TransactionCase):
def setUp(self):
super(TestMailThread, self).setUp()
# Create an email_message record with headers that we can check against

self.message_body = {
"body": "This is a test email",
"subject": "Test Template",
"email_from": "[email protected]",
"author_id": self.env.user.id,
"message_type": "email",
"body_html": "<p>This is a test email</p>",
"headers": {
"X-Auto-Response-Suppress": "All",
"X-Autoreply": "yes",
"X-Autorespond": "yes",
"Auto-Submitted": "no",
},
}
self.mail = self.env["mail.mail"].create(self.message_body)

self.model_mail_thread = self.env["mail.thread"]

self.msg = MIMEMultipart()
self.msg["From"] = self.env.user.email
self.msg["To"] = self.mail.email_to
self.msg["Subject"] = "Test Template"
self.msg["X-Autoreply"] = "yes"
self.msg["X-Autorespond"] = "yes"
self.msg["X-Auto-Response-Suppress"] = "All"
self.msg["Auto-Submitted"] = "no"

# Create a mail with auto respond headers

def test_is_auto_response_email_message(self):
# Check if any auto respond headers are present in the original email.
self.mail.send()
self.assertTrue(
self.model_mail_thread._is_auto_response_email_message(self.mail.headers)
)