Merge PR #598 into 13.0

Signed-off-by rafaelbn
pull/647/head
OCA-git-bot 2020-12-09 23:35:33 +00:00
commit 08017188ab
12 changed files with 564 additions and 46 deletions

View File

@ -26,8 +26,29 @@ Mail Outbound Static
|badge1| |badge2| |badge3| |badge4| |badge5| |badge1| |badge2| |badge3| |badge4| |badge5|
This module brings Odoo outbound emails in to strict compliance with RFC-2822 This module brings Odoo outbound emails in to strict compliance with RFC-2822
by allowing for a statically configured From header, with the sender's e-mail by allowing for a dynamically configured From header, with the sender's e-mail
being appended into the proper Sender header instead. being appended into the proper Sender header instead. To accomplish this we:
* Add a domain whitelist field in the mail server model. This one represent an
allowed Domains list separated by commas. If there is not given SMTP server
it will let us to search the proper mail server to be used to send the messages
where the message 'From' email domain match with the domain whitelist. If
there is not mail server that matches then will use the default mail server to
send the message.
* Add a Email From field that will let us to email from a specific address taking
into account this conditions:
1) If the sender domain match with the domain whitelist then the original
message's 'From' will remain as it is and will not be changed because the
mail server is able to send in the name of the sender domain.
2) If the original message's 'From' does not match with the domain whitelist
then the email From is replaced with the Email From field value.
* Add compatibility to define the smtp information in Odoo config file. Both
smtp_from and smtp_whitelist_domain values will be used if there is not mail
server configured in the system.
**Table of contents** **Table of contents**
@ -39,11 +60,7 @@ Usage
* Navigate to an Outbound Email Server * Navigate to an Outbound Email Server
* Set the `Email From` option to an email address * Set the `Email From` option to an email address
* Set the `Domain Whitelist` option with the domain whitelist
Known issues / Roadmap
======================
* Allow for domain-based whitelist that will not be manipulated
Bug Tracker Bug Tracker
=========== ===========
@ -63,6 +80,7 @@ Authors
* brain-tec AG * brain-tec AG
* LasLabs * LasLabs
* Adhoc SA
Contributors Contributors
~~~~~~~~~~~~ ~~~~~~~~~~~~
@ -70,6 +88,8 @@ Contributors
* Frédéric Garbely <frederic.garbely@braintec-group.com> * Frédéric Garbely <frederic.garbely@braintec-group.com>
* Dave Lasley <dave@laslabs.com> * Dave Lasley <dave@laslabs.com>
* Lorenzo Battistini <https://github.com/eLBati> * Lorenzo Battistini <https://github.com/eLBati>
* Katherine Zaoral <kz@adhoc.com.ar>
* Juan José Scarafía <jjs@adhoc.com.ar>
Maintainers Maintainers
~~~~~~~~~~~ ~~~~~~~~~~~

View File

@ -7,7 +7,7 @@
"version": "13.0.1.0.1", "version": "13.0.1.0.1",
"category": "Discuss", "category": "Discuss",
"website": "https://github.com/OCA/social", "website": "https://github.com/OCA/social",
"author": "brain-tec AG, LasLabs, Odoo Community Association (OCA)", "author": "brain-tec AG, LasLabs, Adhoc SA, Odoo Community Association (OCA)",
"license": "LGPL-3", "license": "LGPL-3",
"application": False, "application": False,
"installable": True, "installable": True,

View File

@ -0,0 +1,73 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * mail_outbound_static
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 13.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-03 12:53+0000\n"
"PO-Revision-Date: 2020-09-03 12:53+0000\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_outbound_static
#: code:addons/mail_outbound_static/models/ir_mail_server.py:0
#, python-format
msgid ""
"%s is not a valid domain. Please define a list of valid domains separated by"
" comma"
msgstr ""
"%s no es un dominio válido. Por favor defina una lista de dominios validos separados por"
" comas"
#. module: mail_outbound_static
#: model:ir.model.fields,help:mail_outbound_static.field_ir_mail_server__domain_whitelist
msgid ""
"Allowed Domains list separated by commas. If there is not given SMTP server "
"it will let us to search the proper mail server to be used to sent the "
"messages where the message 'From' email domain match with the domain "
"whitelist."
msgstr ""
"Lista de dominios permitidos separados por comas. Si no se ha seleccionado "
"un servidor SMTP nos permitirá seleccionar el servidor de mail apropiado "
"para enviar los mensajes donde el dominio del email del 'De' coincida con la"
" lista blanca de dominios."
#. module: mail_outbound_static
#: model:ir.model.fields,field_description:mail_outbound_static.field_ir_mail_server__domain_whitelist
msgid "Domain Whitelist"
msgstr "Lista blanca de dominios"
#. module: mail_outbound_static
#: model:ir.model.fields,field_description:mail_outbound_static.field_ir_mail_server__smtp_from
msgid "Email From"
msgstr "Email De"
#. module: mail_outbound_static
#: model:ir.model,name:mail_outbound_static.model_ir_mail_server
msgid "Mail Server"
msgstr "Servidor de correo"
#. module: mail_outbound_static
#: code:addons/mail_outbound_static/models/ir_mail_server.py:0
#, python-format
msgid "Not a valid Email From"
msgstr "No es un Email De válido"
#. module: mail_outbound_static
#: model:ir.model.fields,help:mail_outbound_static.field_ir_mail_server__smtp_from
msgid ""
"Set this in order to email from a specific address. If the original "
"message's 'From' does not match with the domain whitelist then it is "
"replaced with this value. If does match with the domain whitelist then the "
"original message's 'From' will not change"
msgstr ""
"Definalo para usar un dirección de correo 'De' especifica. Si el 'De' del "
"mensaje original no coincide con la lista blanca de dominios entonces este "
"será remplazado con este valor. Si coincide con la lista blanca de dominios "
"entonces el 'De' del mensajee original no cambiará"

View File

@ -6,6 +6,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Odoo Server 13.0\n" "Project-Id-Version: Odoo Server 13.0\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-09-03 12:53+0000\n"
"PO-Revision-Date: 2020-09-03 12:53+0000\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: \n" "Language-Team: \n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
@ -13,6 +15,28 @@ msgstr ""
"Content-Transfer-Encoding: \n" "Content-Transfer-Encoding: \n"
"Plural-Forms: \n" "Plural-Forms: \n"
#. module: mail_outbound_static
#: code:addons/mail_outbound_static/models/ir_mail_server.py:0
#, python-format
msgid ""
"%s is not a valid domain. Please define a list of valid domains separated by"
" comma"
msgstr ""
#. module: mail_outbound_static
#: model:ir.model.fields,help:mail_outbound_static.field_ir_mail_server__domain_whitelist
msgid ""
"Allowed Domains list separated by commas. If there is not given SMTP server "
"it will let us to search the proper mail server to be used to sent the "
"messages where the message 'From' email domain match with the domain "
"whitelist."
msgstr ""
#. module: mail_outbound_static
#: model:ir.model.fields,field_description:mail_outbound_static.field_ir_mail_server__domain_whitelist
msgid "Domain Whitelist"
msgstr ""
#. module: mail_outbound_static #. module: mail_outbound_static
#: model:ir.model.fields,field_description:mail_outbound_static.field_ir_mail_server__smtp_from #: model:ir.model.fields,field_description:mail_outbound_static.field_ir_mail_server__smtp_from
msgid "Email From" msgid "Email From"
@ -24,6 +48,16 @@ msgid "Mail Server"
msgstr "" msgstr ""
#. module: mail_outbound_static #. module: mail_outbound_static
#: model:ir.model.fields,help:mail_outbound_static.field_ir_mail_server__smtp_from #: code:addons/mail_outbound_static/models/ir_mail_server.py:0
msgid "Set this in order to email from a specific address." #, python-format
msgid "Not a valid Email From"
msgstr ""
#. module: mail_outbound_static
#: model:ir.model.fields,help:mail_outbound_static.field_ir_mail_server__smtp_from
msgid ""
"Set this in order to email from a specific address. If the original "
"message's 'From' does not match with the domain whitelist then it is "
"replaced with this value. If does match with the domain whitelist then the "
"original message's 'From' will not change"
msgstr "" msgstr ""

View File

@ -1,7 +1,11 @@
# Copyright 2017 LasLabs Inc. # Copyright 2017 LasLabs Inc.
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
from odoo import api, fields, models import re
from email.utils import formataddr, parseaddr
from odoo import _, api, fields, models, tools
from odoo.exceptions import ValidationError
class IrMailServer(models.Model): class IrMailServer(models.Model):
@ -9,28 +13,93 @@ class IrMailServer(models.Model):
_inherit = "ir.mail_server" _inherit = "ir.mail_server"
smtp_from = fields.Char( smtp_from = fields.Char(
string="Email From", help="Set this in order to email from a specific address." string="Email From",
help="Set this in order to email from a specific address."
" If the original message's 'From' does not match with the domain"
" whitelist then it is replaced with this value. If does match with the"
" domain whitelist then the original message's 'From' will not change",
) )
domain_whitelist = fields.Char(
help="Allowed Domains list separated by commas. If there is not given"
" SMTP server it will let us to search the proper mail server to be"
" used to sent the messages where the message 'From' email domain"
" match with the domain whitelist."
)
@api.constrains("domain_whitelist")
def check_valid_domain_whitelist(self):
if self.domain_whitelist:
domains = list(self.domain_whitelist.split(","))
for domain in domains:
if not self._is_valid_domain(domain):
raise ValidationError(
_(
"%s is not a valid domain. Please define a list of"
" valid domains separated by comma"
)
% (domain)
)
@api.constrains("smtp_from")
def check_valid_smtp_from(self):
if self.smtp_from:
match = re.match(
r"^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\."
r"[a-z]{2,4})$",
self.smtp_from,
)
if match is None:
raise ValidationError(_("Not a valid Email From"))
def _is_valid_domain(self, domain_name):
domain_regex = (
r"(([\da-zA-Z])([_\w-]{,62})\.){,127}(([\da-zA-Z])"
r"[_\w-]{,61})?([\da-zA-Z]\.((xn\-\-[a-zA-Z\d]+)|([a-zA-Z\d]{2,})))"
)
domain_regex = "{}$".format(domain_regex)
valid_domain_name_regex = re.compile(domain_regex, re.IGNORECASE)
domain_name = domain_name.lower().strip()
return True if re.match(valid_domain_name_regex, domain_name) else False
@api.model
def _get_domain_whitelist(self, domain_whitelist_string):
res = domain_whitelist_string.split(",") if domain_whitelist_string else []
res = [item.strip() for item in res]
return res
@api.model @api.model
def send_email( def send_email(
self, message, mail_server_id=None, smtp_server=None, *args, **kwargs self, message, mail_server_id=None, smtp_server=None, *args, **kwargs
): ):
# Get email_from and name_from
if message["From"].count("<") > 1:
split_from = message["From"].rsplit(" <", 1)
name_from = split_from[0]
email_from = split_from[-1].replace(">", "")
else:
name_from, email_from = parseaddr(message["From"])
email_domain = email_from.split("@")[1]
# Replicate logic from core to get mail server # Replicate logic from core to get mail server
mail_server = None # Get proper mail server to use
if not smtp_server and not mail_server_id:
mail_server_id = self._get_mail_sever(email_domain)
# If not mail sever defined use smtp_from defined in odoo config
if mail_server_id: if mail_server_id:
mail_server = self.sudo().browse(mail_server_id) mail_server = self.sudo().browse(mail_server_id)
elif not smtp_server: domain_whitelist = mail_server.domain_whitelist
mail_server = self.sudo().search([], order="sequence", limit=1) smtp_from = mail_server.smtp_from
else:
domain_whitelist = tools.config.get("smtp_domain_whitelist")
smtp_from = tools.config.get("smtp_from")
if mail_server and mail_server.smtp_from: domain_whitelist = self._get_domain_whitelist(domain_whitelist)
split_from = message["From"].rsplit(" <", 1)
if len(split_from) > 1:
email_from = "{} <{}>".format(split_from[0], mail_server.smtp_from)
else:
email_from = mail_server.smtp_from
# Replace the From only if needed
if smtp_from and (not domain_whitelist or email_domain not in domain_whitelist):
email_from = formataddr((name_from, smtp_from))
message.replace_header("From", email_from) message.replace_header("From", email_from)
bounce_alias = ( bounce_alias = (
self.env["ir.config_parameter"].sudo().get_param("mail.bounce.alias") self.env["ir.config_parameter"].sudo().get_param("mail.bounce.alias")
@ -46,3 +115,32 @@ class IrMailServer(models.Model):
return super(IrMailServer, self).send_email( return super(IrMailServer, self).send_email(
message, mail_server_id, smtp_server, *args, **kwargs message, mail_server_id, smtp_server, *args, **kwargs
) )
@tools.ormcache("email_domain")
def _get_mail_sever(self, email_domain):
""" return the mail server id that match with the domain_whitelist
If not match then return the default mail server id available one """
mail_server_id = None
for item in self.sudo().search(
[("domain_whitelist", "!=", False)], order="sequence"
):
domain_whitelist = self._get_domain_whitelist(item.domain_whitelist)
if email_domain in domain_whitelist:
mail_server_id = item.id
break
if not mail_server_id:
mail_server_id = self.sudo().search([], order="sequence", limit=1).id
return mail_server_id
@api.model
def create(self, values):
self.clear_caches()
return super().create(values)
def write(self, values):
self.clear_caches()
return super().write(values)
def unlink(self):
self.clear_caches()
return super().unlink()

View File

@ -1,3 +1,5 @@
* Frédéric Garbely <frederic.garbely@braintec-group.com> * Frédéric Garbely <frederic.garbely@braintec-group.com>
* Dave Lasley <dave@laslabs.com> * Dave Lasley <dave@laslabs.com>
* Lorenzo Battistini <https://github.com/eLBati> * Lorenzo Battistini <https://github.com/eLBati>
* Katherine Zaoral <kz@adhoc.com.ar>
* Juan José Scarafía <jjs@adhoc.com.ar>

View File

@ -1,3 +1,24 @@
This module brings Odoo outbound emails in to strict compliance with RFC-2822 This module brings Odoo outbound emails in to strict compliance with RFC-2822
by allowing for a statically configured From header, with the sender's e-mail by allowing for a dynamically configured From header, with the sender's e-mail
being appended into the proper Sender header instead. being appended into the proper Sender header instead. To accomplish this we:
* Add a domain whitelist field in the mail server model. This one represent an
allowed Domains list separated by commas. If there is not given SMTP server
it will let us to search the proper mail server to be used to send the messages
where the message 'From' email domain match with the domain whitelist. If
there is not mail server that matches then will use the default mail server to
send the message.
* Add a Email From field that will let us to email from a specific address taking
into account this conditions:
1) If the sender domain match with the domain whitelist then the original
message's 'From' will remain as it is and will not be changed because the
mail server is able to send in the name of the sender domain.
2) If the original message's 'From' does not match with the domain whitelist
then the email From is replaced with the Email From field value.
* Add compatibility to define the smtp information in Odoo config file. Both
smtp_from and smtp_whitelist_domain values will be used if there is not mail
server configured in the system.

View File

@ -1 +0,0 @@
* Allow for domain-based whitelist that will not be manipulated

View File

@ -1,2 +1,3 @@
* Navigate to an Outbound Email Server * Navigate to an Outbound Email Server
* Set the `Email From` option to an email address * Set the `Email From` option to an email address
* Set the `Domain Whitelist` option with the domain whitelist

View File

@ -369,18 +369,37 @@ ul.auto-toc {
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/lgpl-3.0-standalone.html"><img alt="License: LGPL-3" src="https://img.shields.io/badge/licence-LGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/social/tree/13.0/mail_outbound_static"><img alt="OCA/social" src="https://img.shields.io/badge/github-OCA%2Fsocial-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/social-13-0/social-13-0-mail_outbound_static"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/205/13.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p> <p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/lgpl-3.0-standalone.html"><img alt="License: LGPL-3" src="https://img.shields.io/badge/licence-LGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/social/tree/13.0/mail_outbound_static"><img alt="OCA/social" src="https://img.shields.io/badge/github-OCA%2Fsocial-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/social-13-0/social-13-0-mail_outbound_static"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/205/13.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
<p>This module brings Odoo outbound emails in to strict compliance with RFC-2822 <p>This module brings Odoo outbound emails in to strict compliance with RFC-2822
by allowing for a statically configured From header, with the senders e-mail by allowing for a dynamically configured From header, with the senders e-mail
being appended into the proper Sender header instead.</p> being appended into the proper Sender header instead. To accomplish this we:</p>
<ul class="simple">
<li>Add a domain whitelist field in the mail server model. This one represent an
allowed Domains list separated by commas. If there is not given SMTP server
it will let us to search the proper mail server to be used to send the messages
where the message From email domain match with the domain whitelist. If
there is not mail server that matches then will use the default mail server to
send the message.</li>
<li>Add a Email From field that will let us to email from a specific address taking
into account this conditions:<ol class="arabic">
<li>If the sender domain match with the domain whitelist then the original
messages From will remain as it is and will not be changed because the
mail server is able to send in the name of the sender domain.</li>
<li>If the original messages From does not match with the domain whitelist
then the email From is replaced with the Email From field value.</li>
</ol>
</li>
<li>Add compatibility to define the smtp information in Odoo config file. Both
smtp_from and smtp_whitelist_domain values will be used if there is not mail
server configured in the system.</li>
</ul>
<p><strong>Table of contents</strong></p> <p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents"> <div class="contents local topic" id="contents">
<ul class="simple"> <ul class="simple">
<li><a class="reference internal" href="#usage" id="id1">Usage</a></li> <li><a class="reference internal" href="#usage" id="id1">Usage</a></li>
<li><a class="reference internal" href="#known-issues-roadmap" id="id2">Known issues / Roadmap</a></li> <li><a class="reference internal" href="#bug-tracker" id="id2">Bug Tracker</a></li>
<li><a class="reference internal" href="#bug-tracker" id="id3">Bug Tracker</a></li> <li><a class="reference internal" href="#credits" id="id3">Credits</a><ul>
<li><a class="reference internal" href="#credits" id="id4">Credits</a><ul> <li><a class="reference internal" href="#authors" id="id4">Authors</a></li>
<li><a class="reference internal" href="#authors" id="id5">Authors</a></li> <li><a class="reference internal" href="#contributors" id="id5">Contributors</a></li>
<li><a class="reference internal" href="#contributors" id="id6">Contributors</a></li> <li><a class="reference internal" href="#maintainers" id="id6">Maintainers</a></li>
<li><a class="reference internal" href="#maintainers" id="id7">Maintainers</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
@ -390,16 +409,11 @@ being appended into the proper Sender header instead.</p>
<ul class="simple"> <ul class="simple">
<li>Navigate to an Outbound Email Server</li> <li>Navigate to an Outbound Email Server</li>
<li>Set the <cite>Email From</cite> option to an email address</li> <li>Set the <cite>Email From</cite> option to an email address</li>
</ul> <li>Set the <cite>Domain Whitelist</cite> option with the domain whitelist</li>
</div>
<div class="section" id="known-issues-roadmap">
<h1><a class="toc-backref" href="#id2">Known issues / Roadmap</a></h1>
<ul class="simple">
<li>Allow for domain-based whitelist that will not be manipulated</li>
</ul> </ul>
</div> </div>
<div class="section" id="bug-tracker"> <div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#id3">Bug Tracker</a></h1> <h1><a class="toc-backref" href="#id2">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/social/issues">GitHub Issues</a>. <p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/social/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported. 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 smashing it by providing a detailed and welcomed
@ -407,24 +421,27 @@ If you spotted it first, help us smashing it by providing a detailed and welcome
<p>Do not contact contributors directly about support or help with technical issues.</p> <p>Do not contact contributors directly about support or help with technical issues.</p>
</div> </div>
<div class="section" id="credits"> <div class="section" id="credits">
<h1><a class="toc-backref" href="#id4">Credits</a></h1> <h1><a class="toc-backref" href="#id3">Credits</a></h1>
<div class="section" id="authors"> <div class="section" id="authors">
<h2><a class="toc-backref" href="#id5">Authors</a></h2> <h2><a class="toc-backref" href="#id4">Authors</a></h2>
<ul class="simple"> <ul class="simple">
<li>brain-tec AG</li> <li>brain-tec AG</li>
<li>LasLabs</li> <li>LasLabs</li>
<li>Adhoc SA</li>
</ul> </ul>
</div> </div>
<div class="section" id="contributors"> <div class="section" id="contributors">
<h2><a class="toc-backref" href="#id6">Contributors</a></h2> <h2><a class="toc-backref" href="#id5">Contributors</a></h2>
<ul class="simple"> <ul class="simple">
<li>Frédéric Garbely &lt;<a class="reference external" href="mailto:frederic.garbely&#64;braintec-group.com">frederic.garbely&#64;braintec-group.com</a>&gt;</li> <li>Frédéric Garbely &lt;<a class="reference external" href="mailto:frederic.garbely&#64;braintec-group.com">frederic.garbely&#64;braintec-group.com</a>&gt;</li>
<li>Dave Lasley &lt;<a class="reference external" href="mailto:dave&#64;laslabs.com">dave&#64;laslabs.com</a>&gt;</li> <li>Dave Lasley &lt;<a class="reference external" href="mailto:dave&#64;laslabs.com">dave&#64;laslabs.com</a>&gt;</li>
<li>Lorenzo Battistini &lt;<a class="reference external" href="https://github.com/eLBati">https://github.com/eLBati</a>&gt;</li> <li>Lorenzo Battistini &lt;<a class="reference external" href="https://github.com/eLBati">https://github.com/eLBati</a>&gt;</li>
<li>Katherine Zaoral &lt;<a class="reference external" href="mailto:kz&#64;adhoc.com.ar">kz&#64;adhoc.com.ar</a>&gt;</li>
<li>Juan José Scarafía &lt;<a class="reference external" href="mailto:jjs&#64;adhoc.com.ar">jjs&#64;adhoc.com.ar</a>&gt;</li>
</ul> </ul>
</div> </div>
<div class="section" id="maintainers"> <div class="section" id="maintainers">
<h2><a class="toc-backref" href="#id7">Maintainers</a></h2> <h2><a class="toc-backref" href="#id6">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p> <p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a> <a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose <p>OCA, or the Odoo Community Association, is a nonprofit organization whose

View File

@ -1,14 +1,19 @@
# Copyright 2017 LasLabs Inc. # Copyright 2017 LasLabs Inc.
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
import logging
import os import os
import threading import threading
from email import message_from_string from email import message_from_string
from mock import MagicMock from mock import MagicMock
import odoo.tools as tools
from odoo.exceptions import ValidationError
from odoo.tests.common import TransactionCase from odoo.tests.common import TransactionCase
_logger = logging.getLogger(__name__)
class TestIrMailServer(TransactionCase): class TestIrMailServer(TransactionCase):
def setUp(self): def setUp(self):
@ -17,6 +22,7 @@ class TestIrMailServer(TransactionCase):
self.email_from_another = "another@example.com" self.email_from_another = "another@example.com"
self.Model = self.env["ir.mail_server"] self.Model = self.env["ir.mail_server"]
self.parameter_model = self.env["ir.config_parameter"] self.parameter_model = self.env["ir.config_parameter"]
self._delete_mail_servers()
self.Model.create( self.Model.create(
{ {
"name": "localhost", "name": "localhost",
@ -30,6 +36,44 @@ class TestIrMailServer(TransactionCase):
with open(message_file, "r") as fh: with open(message_file, "r") as fh:
self.message = message_from_string(fh.read()) self.message = message_from_string(fh.read())
def _init_mail_server_domain_whilelist_based(self):
self._delete_mail_servers()
self.mail_server_domainone = self.Model.create(
{
"name": "sandbox domainone",
"smtp_host": "localhost",
"smtp_from": "notifications@domainone.com",
"domain_whitelist": "domainone.com",
}
)
self.mail_server_domaintwo = self.Model.create(
{
"name": "sandbox domaintwo",
"smtp_host": "localhost",
"smtp_from": "hola@domaintwo.com",
"domain_whitelist": "domaintwo.com",
}
)
self.mail_server_domainthree = self.Model.create(
{
"name": "sandbox domainthree",
"smtp_host": "localhost",
"smtp_from": "notifications@domainthree.com",
"domain_whitelist": "domainthree.com,domainmulti.com",
}
)
def _skip_test(self, reason):
_logger.warn(reason)
self.skipTest(reason)
def _delete_mail_servers(self):
""" Delete all available mail servers """
all_mail_servers = self.Model.search([])
if all_mail_servers:
all_mail_servers.unlink()
self.assertFalse(self.Model.search([]))
def _send_mail(self, message=None, mail_server_id=None, smtp_server=None): def _send_mail(self, message=None, mail_server_id=None, smtp_server=None):
if message is None: if message is None:
message = self.message message = self.message
@ -71,7 +115,215 @@ class TestIrMailServer(TransactionCase):
# Also check passing mail_server_id # Also check passing mail_server_id
mail_server_id = self.Model.sudo().search([], order="sequence", limit=1)[0].id mail_server_id = self.Model.sudo().search([], order="sequence", limit=1)[0].id
message = self._send_mail(mail_server_id=mail_server_id) message = self._send_mail(mail_server_id=mail_server_id)
self.assertEqual(message["From"], "{} <{}>".format(user, self.email_from)) self.assertEqual(message["From"], '"{}" <{}>'.format(user, self.email_from))
self.assertEqual( self.assertEqual(
message["Return-Path"], "{} <{}>".format(user, self.email_from) message["Return-Path"], '"{}" <{}>'.format(user, self.email_from)
) )
def test_01_from_outgoing_server_domainone(self):
self._init_mail_server_domain_whilelist_based()
domain = "domainone.com"
email_from = "Mitchell Admin <admin@%s>" % domain
expected_mail_server = self.mail_server_domainone
self.message.replace_header("From", email_from)
message = self._send_mail()
self.assertEqual(message["From"], email_from)
used_mail_server = self.Model._get_mail_sever(domain)
used_mail_server = self.Model.browse(used_mail_server)
self.assertEqual(
used_mail_server,
expected_mail_server,
"It using %s but we expect to use %s"
% (used_mail_server.name, expected_mail_server.name),
)
def test_02_from_outgoing_server_domaintwo(self):
self._init_mail_server_domain_whilelist_based()
domain = "domaintwo.com"
email_from = "Mitchell Admin <admin@%s>" % domain
expected_mail_server = self.mail_server_domaintwo
self.message.replace_header("From", email_from)
message = self._send_mail()
self.assertEqual(message["From"], email_from)
used_mail_server = self.Model._get_mail_sever(domain)
used_mail_server = self.Model.browse(used_mail_server)
self.assertEqual(
used_mail_server,
expected_mail_server,
"It using %s but we expect to use %s"
% (used_mail_server.name, expected_mail_server.name),
)
def test_03_from_outgoing_server_another(self):
self._init_mail_server_domain_whilelist_based()
domain = "example.com"
email_from = "Mitchell Admin <admin@%s>" % domain
expected_mail_server = self.mail_server_domainone
self.message.replace_header("From", email_from)
message = self._send_mail()
self.assertEqual(
message["From"], "Mitchell Admin <%s>" % expected_mail_server.smtp_from
)
used_mail_server = self.Model._get_mail_sever(domain)
used_mail_server = self.Model.browse(used_mail_server)
self.assertEqual(
used_mail_server,
expected_mail_server,
"It using %s but we expect to use %s"
% (used_mail_server.name, expected_mail_server.name),
)
def test_04_from_outgoing_server_none_use_config(self):
self._init_mail_server_domain_whilelist_based()
domain = "example.com"
email_from = "Mitchell Admin <admin@%s>" % domain
self._delete_mail_servers()
# Find config values
config_smtp_from = tools.config.get("smtp_from")
config_smtp_domain_whitelist = tools.config.get("smtp_domain_whitelist")
if not config_smtp_from or not config_smtp_domain_whitelist:
self._skip_test(
"Cannot test transactions because there is not either smtp_from"
" or smtp_domain_whitelist."
)
self.message.replace_header("From", email_from)
message = self._send_mail()
self.assertEqual(message["From"], "Mitchell Admin <%s>" % config_smtp_from)
used_mail_server = self.Model._get_mail_sever("example.com")
used_mail_server = self.Model.browse(used_mail_server)
self.assertFalse(
used_mail_server, "using this mail server %s" % (used_mail_server.name)
)
def test_05_from_outgoing_server_none_same_domain(self):
self._init_mail_server_domain_whilelist_based()
# Find config values
config_smtp_from = tools.config.get("smtp_from")
config_smtp_domain_whitelist = domain = tools.config.get(
"smtp_domain_whitelist"
)
if not config_smtp_from or not config_smtp_domain_whitelist:
self._skip_test(
"Cannot test transactions because there is not either smtp_from"
" or smtp_domain_whitelist."
)
email_from = "Mitchell Admin <admin@%s>" % domain
self._delete_mail_servers()
self.message.replace_header("From", email_from)
message = self._send_mail()
self.assertEqual(message["From"], email_from)
used_mail_server = self.Model._get_mail_sever(domain)
used_mail_server = self.Model.browse(used_mail_server)
self.assertFalse(used_mail_server)
def test_06_from_outgoing_server_no_name_from(self):
self._init_mail_server_domain_whilelist_based()
domain = "example.com"
email_from = "test@%s" % domain
expected_mail_server = self.mail_server_domainone
self.message.replace_header("From", email_from)
message = self._send_mail()
self.assertEqual(message["From"], expected_mail_server.smtp_from)
used_mail_server = self.Model._get_mail_sever(domain)
used_mail_server = self.Model.browse(used_mail_server)
self.assertEqual(
used_mail_server,
expected_mail_server,
"It using %s but we expect to use %s"
% (used_mail_server.name, expected_mail_server.name),
)
def test_07_from_outgoing_server_multidomain_1(self):
self._init_mail_server_domain_whilelist_based()
domain = "domainthree.com"
email_from = "Mitchell Admin <admin@%s>" % domain
expected_mail_server = self.mail_server_domainthree
self.message.replace_header("From", email_from)
message = self._send_mail()
self.assertEqual(message["From"], email_from)
used_mail_server = self.Model._get_mail_sever(domain)
used_mail_server = self.Model.browse(used_mail_server)
self.assertEqual(
used_mail_server,
expected_mail_server,
"It using %s but we expect to use %s"
% (used_mail_server.name, expected_mail_server.name),
)
def test_08_from_outgoing_server_multidomain_3(self):
self._init_mail_server_domain_whilelist_based()
domain = "domainmulti.com"
email_from = "test@%s" % domain
expected_mail_server = self.mail_server_domainthree
self.message.replace_header("From", email_from)
message = self._send_mail()
self.assertEqual(message["From"], email_from)
used_mail_server = self.Model._get_mail_sever(domain)
used_mail_server = self.Model.browse(used_mail_server)
self.assertEqual(
used_mail_server,
expected_mail_server,
"It using %s but we expect to use %s"
% (used_mail_server.name, expected_mail_server.name),
)
def test_09_not_valid_domain_whitelist(self):
self._init_mail_server_domain_whilelist_based()
mail_server = self.mail_server_domainone
mail_server.domain_whitelist = "example.com"
error_msg = (
"%s is not a valid domain. Please define a list of valid"
" domains separated by comma"
)
with self.assertRaisesRegex(ValidationError, error_msg % "asdasd"):
mail_server.domain_whitelist = "asdasd"
with self.assertRaisesRegex(ValidationError, error_msg % "asdasd"):
mail_server.domain_whitelist = "example.com, asdasd"
with self.assertRaisesRegex(ValidationError, error_msg % "invalid"):
mail_server.domain_whitelist = "example.com; invalid"
with self.assertRaisesRegex(ValidationError, error_msg % ";"):
mail_server.domain_whitelist = ";"
with self.assertRaisesRegex(ValidationError, error_msg % "."):
mail_server.domain_whitelist = "hola.com,."
def test_10_not_valid_smtp_from(self):
self._init_mail_server_domain_whilelist_based()
mail_server = self.mail_server_domainone
error_msg = "Not a valid Email From"
with self.assertRaisesRegex(ValidationError, error_msg):
mail_server.smtp_from = "asdasd"
with self.assertRaisesRegex(ValidationError, error_msg):
mail_server.smtp_from = "example.com"
with self.assertRaisesRegex(ValidationError, error_msg):
mail_server.smtp_from = "."
mail_server.smtp_from = "notifications@test.com"

View File

@ -13,7 +13,8 @@
<field name="inherit_id" ref="base.ir_mail_server_form" /> <field name="inherit_id" ref="base.ir_mail_server_form" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//field[@name='smtp_pass']" position="after"> <xpath expr="//field[@name='smtp_pass']" position="after">
<field name="smtp_from" /> <field name="domain_whitelist"/>
<field name="smtp_from" widget="email"/>
</xpath> </xpath>
</field> </field>
</record> </record>