Skip to content
Open
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
113 changes: 113 additions & 0 deletions mail_company_aware_sender/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
=========================
Mail Sender Company Aware
=========================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:7ee2897c3172b5b4d4927dbf7ec1e94e1c71bc5602f7bdf85b3ac0cae33481d0
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |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/14.0/mail_company_aware_sender
:alt: OCA/social
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/social-14-0/social-14-0-mail_company_aware_sender
: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/social&target_branch=14.0
:alt: Try me on Runboat

|badge1| |badge2| |badge3| |badge4| |badge5|

This module allows to send out mails using a company aware email address.
Suppose we have a user Charles the Magnificent with email address
[email protected]. However this user works for two companies, one
for the kingdom of France, with email address [email protected], and
one for the Roman Empire with email address [email protected].

Now when sending out mail, we want to make clear from what active company the
mail is sent, but also want to keep the name of the active user in the
email from address, so when sending from the kingdom, the email from will
be [email protected], but when sending from the empire, the email will
be [email protected].

Note that after installing this module the system parameter mail.default.from
will no longer be used to set the from address.

This module can also be used to send company aware emails from templates.
For instance with this formula for the email_from field:
{{ user.get_company_aware_email(object) }}
In this example the company defined in the object will be used instead of the current
company.

**Table of contents**

.. contents::
:local:

Configuration
=============

To send out mails with company aware from addresses, three things are needed:
* The company partner needs to have an email address;
* The company must be enabled for it's domain being used in from addresses;
* The company email domain must be defined on a domain whitelist in one
or more of the outgoing mail servers.

On the company you can also set whether email from should include the name
of the sender or not. This will only affect emails that are modified to use
the company address.

For particular users/partners there can be an opt-out for using company aware
emails. This can be configured right under the email field in the partner form.

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/social/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 <https://github.com/OCA/social/issues/new?body=module:%20mail_company_aware_sender%0Aversion:%2014.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

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

Credits
=======

Authors
~~~~~~~

* Therp BV

Contributors
~~~~~~~~~~~~

* `Therp BV <https://therp.nl>`_:

* Ronald Portier (NL66278)

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 <https://github.com/OCA/social/tree/14.0/mail_company_aware_sender>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
3 changes: 3 additions & 0 deletions mail_company_aware_sender/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from . import models
22 changes: 22 additions & 0 deletions mail_company_aware_sender/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Copyright 2025 Therp BV <https://therp.nl>.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

{
"name": "Mail Sender Company Aware",
"summary": "Send emails with company specific mail domain",
"version": "14.0.1.0.0",
"category": "Social Network",
"website": "https://github.com/OCA/social",
"author": ("Therp BV, " "Odoo Community Association (OCA)"),
"license": "AGPL-3",
"application": False,
"installable": True,
"depends": [
"mail",
"mail_outbound_static", # Need the domain whitelist on outgoing server.
],
"data": [
"views/res_company_view.xml",
"views/res_partner_view.xml",
],
}
7 changes: 7 additions & 0 deletions mail_company_aware_sender/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from . import ir_mail_server
from . import mail_thread
from . import res_company
from . import res_partner
from . import res_users
50 changes: 50 additions & 0 deletions mail_company_aware_sender/models/ir_mail_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Copyright 2025 Therp BV <https://therp.nl>.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo import _, api, models
from odoo.exceptions import ValidationError
from odoo.tools import email_domain_extract


class IrMailServer(models.Model):

_inherit = "ir.mail_server"

@api.model
def _is_domain_whitelisted(self, domain):
"""Check whether domain has been whitelisted for sending."""
whitelist_servers = self.search([]).filtered("domain_whitelist")
for server in whitelist_servers:
if domain in self._get_domain_whitelist(server.domain_whitelist):
return True
return False

def _get_test_email_addresses(self):
self.ensure_one()
email_to = "[email protected]"
# if server forces a sender, use it.
if self.smtp_from:
return self.smtp_from, email_to
if not self.env.user.email:
return super()._get_test_email_addresses()
email_from = self.env.user.company_aware_email()
email_domain = email_domain_extract(email_from)
valid_domains = self._get_domain_whitelist(self.domain_whitelist)
if email_domain not in valid_domains:
raise ValidationError(
_("Domain %s not whitelisted on this server") % email_domain
)
return email_from, email_to

def build_email(self, *args, **kwargs):
"""Provide a valid return address when using company aware From."""
if self.env.company.use_email_domain and self.env.company.reply_to:
kwargs["reply_to"] = self.env.company.reply_to
return super().build_email(*args, **kwargs)

@api.model
def _get_default_from_address(self):
"""Prevent overwrite of email_from if not desired for company."""
if self.env.company.use_email_domain:
return None
return super()._get_default_from_address()
24 changes: 24 additions & 0 deletions mail_company_aware_sender/models/mail_thread.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copyright 2025 Therp BV <https://therp.nl>.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import models


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

def _message_compute_author(self, author_id, email_from, raise_exception=True):
"""Set email from using company email domain.

We will NOT override an explicitly passed email_from.

Check for current company to see whether we should try to override
the email_from domain.
"""
email_passed = bool(email_from)
author_id, email_from = super()._message_compute_author(
author_id, email_from, raise_exception=raise_exception
)
if (not email_passed) and author_id:
author = self.env["res.partner"].browse(author_id)
email_from = author.company_aware_email(default_email=email_from)
return author_id, email_from
29 changes: 29 additions & 0 deletions mail_company_aware_sender/models/res_company.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Copyright 2025 Therp BV <https://therp.nl>.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo import fields, models
from odoo.tools import email_domain_extract


class ResCompany(models.Model):
_inherit = "res.company"

use_email_domain = fields.Boolean(
help="Use domain part of company for sender email address",
)
format_email = fields.Boolean(
default=True, # As this is what Odoo standard does.
help='Format email_from with name "John Smith" <[email protected]>'
" or use plain email address",
)
reply_to = fields.Char(
help="reply_to address to use, if not filled, fallback to mail.default.from",
)

def _override_email_domain(self):
"""Check whether company email domain can and should be used."""
self.ensure_one()
if not (self.use_email_domain and self.email):
return False
email_domain = email_domain_extract(self.email)
return self.env["ir.mail_server"].sudo()._is_domain_whitelisted(email_domain)
28 changes: 28 additions & 0 deletions mail_company_aware_sender/models/res_partner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Copyright 2025 Therp BV <https://therp.nl>.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo import fields, models
from odoo.tools import formataddr


class ResPartner(models.Model):
_inherit = "res.partner"

fixed_email = fields.Boolean(
help="Email for partner will not be influenced by company",
)

def company_aware_email(self, company=None, default_email=None):
"""Set email using company email domain if configured."""
self.ensure_one()
result_email = default_email or self.email
if not self.fixed_email:
company = company or self.env.company
if company._override_email_domain():
before_at = self.email.split("@")[0]
after_at = company.email.split("@")[1]
result_email = f"{before_at}@{after_at}"
if company.format_email:
# formataddr wants a tuple with name (or False) and email.
result_email = formataddr((self.name, result_email))
return result_email
28 changes: 28 additions & 0 deletions mail_company_aware_sender/models/res_users.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Copyright 2025 Therp BV <https://therp.nl>.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo import models


class ResUsers(models.Model):
_inherit = "res.users"

def company_aware_email(self, company=None, default_email=None):
"""Set email using company email domain if configured."""
self.ensure_one()
return self.partner_id.company_aware_email(
company=company, default_email=default_email
)

def get_company_aware_email(self, record):
"""Get company aware email_from related to Odoo record.

Can be used on email_from field of template like so:
{{ user.get_company_aware_email(object) }}
"""
record.ensure_one() # Must be recordlist with exactly one member.
user = record.user_id if "user_id" in record._fields else self.env.user
company = (
record.company_id if "company_id" in record._fields else self.env.company
)
return user.company_aware_email(company=company)
12 changes: 12 additions & 0 deletions mail_company_aware_sender/readme/CONFIGURE.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
To send out mails with company aware from addresses, three things are needed:
* The company partner needs to have an email address;
* The company must be enabled for it's domain being used in from addresses;
* The company email domain must be defined on a domain whitelist in one
or more of the outgoing mail servers.

On the company you can also set whether email from should include the name
of the sender or not. This will only affect emails that are modified to use
the company address.

For particular users/partners there can be an opt-out for using company aware
emails. This can be configured right under the email field in the partner form.
3 changes: 3 additions & 0 deletions mail_company_aware_sender/readme/CONTRIBUTORS.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
* `Therp BV <https://therp.nl>`_:

* Ronald Portier (NL66278)
20 changes: 20 additions & 0 deletions mail_company_aware_sender/readme/DESCRIPTION.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
This module allows to send out mails using a company aware email address.
Suppose we have a user Charles the Magnificent with email address
[email protected]. However this user works for two companies, one
for the kingdom of France, with email address [email protected], and
one for the Roman Empire with email address [email protected].

Now when sending out mail, we want to make clear from what active company the
mail is sent, but also want to keep the name of the active user in the
email from address, so when sending from the kingdom, the email from will
be [email protected], but when sending from the empire, the email will
be [email protected].

Note that after installing this module the system parameter mail.default.from
will no longer be used to set the from address.

This module can also be used to send company aware emails from templates.
For instance with this formula for the email_from field:
{{ user.get_company_aware_email(object) }}
In this example the company defined in the object will be used instead of the current
company.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading