Skip to content

Commit 0c6ba0a

Browse files
davejamesrichard-willdooit
authored andcommitted
allow setting a mail server for local development
1 parent 8764430 commit 0c6ba0a

File tree

2 files changed

+54
-15
lines changed

2 files changed

+54
-15
lines changed

addons/mail/models/mail_mail.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@
1616

1717
from odoo import _, api, fields, models
1818
from odoo import tools
19-
from odoo.addons.base.models.ir_mail_server import MailDeliveryException
20-
from odoo.addons.base.models.ir_cron import db_whitelisted
19+
from odoo.addons.base.models.ir_mail_server import MailDeliveryException, MailDeliveryWhitelistException
2120

2221
_logger = logging.getLogger(__name__)
2322

@@ -429,15 +428,12 @@ def send(self, auto_commit=False, raise_exception=False):
429428
:return: True
430429
"""
431430

432-
# Return out of send() if db not in whitelist
433-
if not db_whitelisted(self.env.cr.dbname):
434-
_logger.warning('Database cannot send emails as it is not on the whitelist.')
435-
return
436-
437431
for mail_server_id, smtp_from, batch_ids in self._split_by_mail_configuration():
438432
smtp_session = None
439433
try:
440434
smtp_session = self.env['ir.mail_server'].connect(mail_server_id=mail_server_id, smtp_from=smtp_from)
435+
except MailDeliveryWhitelistException:
436+
pass
441437
except Exception as exc:
442438
if raise_exception:
443439
# To be consistent and backward compatible with mail_mail.send() raised

odoo/addons/base/models/ir_mail_server.py

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import ssl
1515
import sys
1616
import threading
17+
import os
1718

1819
from socket import gaierror, timeout
1920
from OpenSSL import crypto as SSLCrypto
@@ -38,6 +39,10 @@ class MailDeliveryException(Exception):
3839
"""Specific exception subclass for mail delivery errors"""
3940

4041

42+
class MailDeliveryWhitelistException(MailDeliveryException):
43+
"""Specific exception subclass for non whitelisted mail delivery attempts"""
44+
45+
4146
def make_wrap_property(name):
4247
return property(
4348
lambda self: getattr(self.__obj__, name),
@@ -406,6 +411,8 @@ def connect(self, host=None, port=None, user=None, password=None, encryption=Non
406411
_("Please define at least one SMTP server, "
407412
"or provide the SMTP parameters explicitly.")))
408413

414+
self._is_allowed_to_send(smtp_server, raise_exception=True)
415+
409416
if smtp_encryption == 'ssl':
410417
if 'SMTP_SSL' not in smtplib.__all__:
411418
raise UserError(
@@ -710,14 +717,6 @@ def send_email(self, message, mail_server_id=None, smtp_server=None, smtp_port=N
710717
_test_logger.info("skip sending email in test mode")
711718
return message['Message-Id']
712719

713-
# Some odoo tests in base explicitly patch ir.mail_server to return False from _is_test_mode()
714-
if (
715-
not db_whitelisted(self.env.cr.dbname)
716-
and not isinstance(self.connect, MagicMock)
717-
and smtp.__class__.__name__ != "FakeSMTP"
718-
):
719-
raise UserError(_("Whitelist Error") + "\n" + _("Database cannot send emails as it is not on the whitelist."))
720-
721720
try:
722721
message_id = message['Message-Id']
723722

@@ -741,6 +740,8 @@ def send_email(self, message, mail_server_id=None, smtp_server=None, smtp_port=N
741740
smtp.quit()
742741
except smtplib.SMTPServerDisconnected:
743742
raise
743+
except MailDeliveryWhitelistException:
744+
raise
744745
except Exception as e:
745746
params = (ustr(smtp_server), e.__class__.__name__, e)
746747
msg = _("Mail delivery failed via SMTP server '%s'.\n%s: %s", *params)
@@ -855,3 +856,45 @@ def _is_test_mode(self):
855856
outgoing mail server.
856857
"""
857858
return getattr(threading.current_thread(), 'testing', False) or self.env.registry.in_test_mode()
859+
860+
def _is_allowed_to_send(self, smtp_server: str = None, raise_exception: bool = False) -> bool:
861+
"""
862+
Return True if the database is allowed to send email.
863+
864+
Emails are not allowed unless the database is whitelisted by using the
865+
`db_cron_whitelist` option in the odoo config file.
866+
867+
During development, we don't want to enable this option, and we do not want
868+
to send emails to real users, but we do want to test emails using local
869+
development mail servers such as MailHog.
870+
871+
To avoid accidentally allowing real local email servers such as postfix
872+
to send emails, the mail server must be explicitly configured with the
873+
environment variable `ODOO_DEV_SMTP_SERVER` if the database is not
874+
whitelisted.
875+
"""
876+
877+
if db_whitelisted(self.env.cr.dbname):
878+
return True
879+
880+
# Some odoo tests in base explicitly patch ir.mail_server to return False from
881+
# _is_test_mode() in which case we want to allow sending mails.
882+
if isinstance(self.connect, MagicMock):
883+
return True
884+
885+
dev_smtp_server = os.environ.get("ODOO_DEV_SMTP_SERVER")
886+
if dev_smtp_server in ["localhost", "127.0.0.1"] and (
887+
(smtp_server and smtp_server == dev_smtp_server)
888+
or
889+
(len(self) <= 1 and self.smtp_host == dev_smtp_server)
890+
):
891+
_logger.info("Allowing local development SMTP server: %s", smtp_server)
892+
return True
893+
894+
msg = _("Database cannot send emails as it is not on the whitelist.")
895+
_logger.warning(msg)
896+
897+
if raise_exception:
898+
raise MailDeliveryWhitelistException(msg)
899+
900+
return False

0 commit comments

Comments
 (0)