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
129 changes: 129 additions & 0 deletions mass_mailing_disable_tracking/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
=============================
Mass Mailing Disable Tracking
=============================

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

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

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

This module allows to disable open and link click tracking in mass
mailing messages.

Odoo Mass Mailing (aka Email Marketing) includes 2 ways of tracking
(spying on, invade the privacy of) the recipients:

1. Tracking the “opening” of the email message by including a 1-pixel
transparent GIF image at the bottom of the message, using a URL to
the Odoo instance that uniquely identifies that message sent to that
recipient. As soon as the recipient displays the remote images of the
message, their email client downloads the tracking image and the Odoo
instance knows that that particular recipient opened that particular
message.
2. Tracking the “clicks” on the links included in the message by
converting all links of the message to a tracking URL to the Odoo
instance. As soon as the recipient clicks one of those links, their
browser will make a request to the Odoo instance, which will record
that click on that particular link for that particular recipient
before redirecting the browser to the original link address.

This module allows to disable both of these mechanisms by preventing the
original email message to be modified by Odoo to include these tracking
mechanisms.

Another issue that link click tracking causes is that recipients are
unable to inspect the links: they cannot know on which website they will
land before clicking on them. This, and the fact that they are tracked,
can cause some recipients to not click the links, making the mass
mailing actually less effective.

Statistics can be useful, but respecting your recipients’ privacy is
important.

**Table of contents**

.. contents::
:local:

Usage
=====

By default, just by installing this module, open and link click tracking
is disabled for new mass mailings.

It is still possible to enable each one separately by going to
**Settings** > **Email Marketing** and checking the corresponding
checkboxes.

.. note::

This module is incompatible with the ``mail_tracking`` module.

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:%20mass_mailing_disable_tracking%0Aversion:%2018.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
-------

* hugues de keyzer

Contributors
------------

- hugues de keyzer

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.

.. |maintainer-huguesdk| image:: https://github.com/huguesdk.png?size=40px
:target: https://github.com/huguesdk
:alt: huguesdk

Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:

|maintainer-huguesdk|

This module is part of the `OCA/social <https://github.com/OCA/social/tree/18.0/mass_mailing_disable_tracking>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
5 changes: 5 additions & 0 deletions mass_mailing_disable_tracking/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# SPDX-FileCopyrightText: 2025 hugues de keyzer
#
# SPDX-License-Identifier: AGPL-3.0-or-later

from . import models
23 changes: 23 additions & 0 deletions mass_mailing_disable_tracking/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# SPDX-FileCopyrightText: 2025 hugues de keyzer
#
# SPDX-License-Identifier: AGPL-3.0-or-later

{
"name": "Mass Mailing Disable Tracking",
"summary": "Allow to disable open and link click tracking in mass mailing messages",
"version": "18.0.1.0.0",
"category": "Marketing/Email Marketing",
"website": "https://github.com/OCA/social",
"author": "hugues de keyzer, Odoo Community Association (OCA)",
"maintainers": ["huguesdk"],
"license": "AGPL-3",
"depends": [
"mass_mailing",
],
"excludes": [
"mail_tracking",
],
"data": [
"views/res_config_settings_view.xml",
],
}
60 changes: 60 additions & 0 deletions mass_mailing_disable_tracking/i18n/it.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * mass_mailing_disable_tracking
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-04-30 10:45+0000\n"
"Last-Translator: mymage <stefano.consolaro@mymage.it>\n"
"Language-Team: none\n"
"Language: it\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.15.2\n"

#. module: mass_mailing_disable_tracking
#: model_terms:ir.ui.view,arch_db:mass_mailing_disable_tracking.res_config_settings_view_form
msgid ""
"Add an invisible tracking image to mass mailing messages to track their "
"opening by the recipient"
msgstr ""
"Aggiungere un'immagine di tracciamento invisibile ai messaggi di posta "
"elettronica inviati in massa per monitorare l'apertura da parte del "
"destinatario"

#. module: mass_mailing_disable_tracking
#: model:ir.model,name:mass_mailing_disable_tracking.model_res_config_settings
msgid "Config Settings"
msgstr "Impostazioni configurazione"

#. module: mass_mailing_disable_tracking
#: model_terms:ir.ui.view,arch_db:mass_mailing_disable_tracking.res_config_settings_view_form
msgid ""
"Convert links in mass mailing messages to track link clicks by the recipient"
msgstr ""
"Convertire i link nei messaggi di posta elettronica inviati in massa per "
"monitorare i clic sui link da parte del destinatario"

#. module: mass_mailing_disable_tracking
#: model:ir.model,name:mass_mailing_disable_tracking.model_mail_render_mixin
msgid "Mail Render Mixin"
msgstr "Mixin resa posta"

#. module: mass_mailing_disable_tracking
#: model:ir.model,name:mass_mailing_disable_tracking.model_mail_mail
msgid "Outgoing Mails"
msgstr "E-mail in uscita"

#. module: mass_mailing_disable_tracking
#: model:ir.model.fields,field_description:mass_mailing_disable_tracking.field_res_config_settings__mailing_track_links
msgid "Track Link Clicks"
msgstr "Traccia clic link"

#. module: mass_mailing_disable_tracking
#: model:ir.model.fields,field_description:mass_mailing_disable_tracking.field_res_config_settings__mailing_track_open
msgid "Track Open"
msgstr "Traccia apertura"
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * mass_mailing_disable_tracking
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \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: mass_mailing_disable_tracking
#: model_terms:ir.ui.view,arch_db:mass_mailing_disable_tracking.res_config_settings_view_form
msgid ""
"Add an invisible tracking image to mass mailing messages to track their "
"opening by the recipient"
msgstr ""

#. module: mass_mailing_disable_tracking
#: model:ir.model,name:mass_mailing_disable_tracking.model_res_config_settings
msgid "Config Settings"
msgstr ""

#. module: mass_mailing_disable_tracking
#: model_terms:ir.ui.view,arch_db:mass_mailing_disable_tracking.res_config_settings_view_form
msgid ""
"Convert links in mass mailing messages to track link clicks by the recipient"
msgstr ""

#. module: mass_mailing_disable_tracking
#: model:ir.model,name:mass_mailing_disable_tracking.model_mail_render_mixin
msgid "Mail Render Mixin"
msgstr ""

#. module: mass_mailing_disable_tracking
#: model:ir.model,name:mass_mailing_disable_tracking.model_mail_mail
msgid "Outgoing Mails"
msgstr ""

#. module: mass_mailing_disable_tracking
#: model:ir.model.fields,field_description:mass_mailing_disable_tracking.field_res_config_settings__mailing_track_links
msgid "Track Link Clicks"
msgstr ""

#. module: mass_mailing_disable_tracking
#: model:ir.model.fields,field_description:mass_mailing_disable_tracking.field_res_config_settings__mailing_track_open
msgid "Track Open"
msgstr ""
7 changes: 7 additions & 0 deletions mass_mailing_disable_tracking/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# SPDX-FileCopyrightText: 2025 hugues de keyzer
#
# SPDX-License-Identifier: AGPL-3.0-or-later

from . import mail_mail
from . import mail_render_mixin
from . import res_config_settings
86 changes: 86 additions & 0 deletions mass_mailing_disable_tracking/models/mail_mail.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# SPDX-FileCopyrightText: 2025 hugues de keyzer
#
# SPDX-License-Identifier: AGPL-3.0-or-later

import re

import werkzeug.urls
from markupsafe import Markup

from odoo import api, models, tools

from .res_config_settings import TRACK_LINKS_PARAMETER, TRACK_OPEN_PARAMETER

TRACKING_LINK_PREFIX = "/r/"
DO_NOT_REPLACE_PLACEHOLDER = "/__do_not_replace__/"
DUMMY_TRACKING_URL = "https://this.is.a.dummy.tracking.url/"


class MailMail(models.Model):
_inherit = "mail.mail"

def _replace_in_html(self, html, to_replace, value):
# this comes from mail.render.mixin._replace_local_links() from the
# mail module.
if not html:
return html
wrapper = Markup if isinstance(html, Markup) else str
html = str(html or "")
return wrapper(html.replace(to_replace, value))

@api.model
def _replace_tracking_like_links(self, body, to_replace, value):
# this is the same mechanism to find and replace links as used in the
# _prepare_outgoing_body() method from the mass_mailing module.
for match in set(re.findall(tools.mail.URL_REGEX, body)):
href = match[0]
url = match[1]
parsed = werkzeug.urls.url_parse(url, scheme="http")
if parsed.scheme.startswith("http") and parsed.path.startswith(to_replace):
new_href = href.replace(url, url.replace(to_replace, value))
body = self._replace_in_html(body, href, new_href)
return body

def _get_tracking_url(self):
if self.env["ir.config_parameter"].sudo().get_param(TRACK_OPEN_PARAMETER):
return super()._get_tracking_url()
# return a dummy tracking url that can be replaced afterwards. it must
# be a full url, otherwise it will be considered as a local url and
# converted.
return DUMMY_TRACKING_URL

def _prepare_outgoing_body(self):
# mail.mail._prepare_outgoing_body() in the mass_mailing module does 2
# things:
# 1. convert tracking links by appending a mailing.trace id to them.
# 2. add an tracking image at the end of the html body.
# it does these things only if its mailing_id and mailing_trace_ids
# fields are set.
self.ensure_one()
ir_config_parameter_model = self.env["ir.config_parameter"].sudo()
track_open = ir_config_parameter_model.get_param(TRACK_OPEN_PARAMETER)
track_links = ir_config_parameter_model.get_param(TRACK_LINKS_PARAMETER)
if (
not self.mailing_id
or not self.mailing_trace_ids
or (track_open and track_links)
):
return super()._prepare_outgoing_body()
body_html = self.body_html
if not track_links:
# ensure that there are no links that look like tracking links to
# avoid them being replaced.
self.body_html = self._replace_tracking_like_links(
self.body_html, TRACKING_LINK_PREFIX, DO_NOT_REPLACE_PLACEHOLDER
)
body = super()._prepare_outgoing_body()
if not track_links:
self.body_html = body_html
body = self._replace_tracking_like_links(
body, DO_NOT_REPLACE_PLACEHOLDER, TRACKING_LINK_PREFIX
)
if not track_open:
body = self._replace_in_html(
body, f'\n<img src="{DUMMY_TRACKING_URL}"/>\n', ""
)
return body
27 changes: 27 additions & 0 deletions mass_mailing_disable_tracking/models/mail_render_mixin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# SPDX-FileCopyrightText: 2025 hugues de keyzer
#
# SPDX-License-Identifier: AGPL-3.0-or-later

from odoo import api, models

from .res_config_settings import TRACK_LINKS_PARAMETER


class MailRenderMixin(models.AbstractModel):
_inherit = "mail.render.mixin"

@api.model
def _shorten_links(self, html, link_tracker_vals, blacklist=None, base_url=None):
if self.env["ir.config_parameter"].sudo().get_param(TRACK_LINKS_PARAMETER):
return super()._shorten_links(html, link_tracker_vals, blacklist, base_url)
return html

@api.model
def _shorten_links_text(
self, content, link_tracker_vals, blacklist=None, base_url=None
):
if self.env["ir.config_parameter"].sudo().get_param(TRACK_LINKS_PARAMETER):
return super()._shorten_links_text(
content, link_tracker_vals, blacklist, base_url
)
return content
Loading
Loading