Skip to content

[19.0] mail_composer_cc_bcc: Migration to 19.0 - #104

Open
cyrilmanuel wants to merge 38 commits into
OCA:19.0from
camptocamp:19.0-mail_composer_cc_bcc
Open

[19.0] mail_composer_cc_bcc: Migration to 19.0#104
cyrilmanuel wants to merge 38 commits into
OCA:19.0from
camptocamp:19.0-mail_composer_cc_bcc

Conversation

@cyrilmanuel

Copy link
Copy Markdown

No description provided.

hailangvn and others added 30 commits November 3, 2025 09:50
Currently translated at 83.3% (15 of 18 strings)

Translation: social-16.0/social-16.0-mail_composer_cc_bcc
Translate-URL: https://translation.odoo-community.org/projects/social-16-0/social-16-0-mail_composer_cc_bcc/es/
Currently translated at 100.0% (18 of 18 strings)

Translation: social-16.0/social-16.0-mail_composer_cc_bcc
Translate-URL: https://translation.odoo-community.org/projects/social-16-0/social-16-0-mail_composer_cc_bcc/es/
Currently translated at 100.0% (18 of 18 strings)

Translation: social-16.0/social-16.0-mail_composer_cc_bcc
Translate-URL: https://translation.odoo-community.org/projects/social-16-0/social-16-0-mail_composer_cc_bcc/it/
Updated by "Update PO files to match POT (msgmerge)" hook in Weblate.

Translation: social-17.0/social-17.0-mail_composer_cc_bcc
Translate-URL: https://translation.odoo-community.org/projects/social-17-0/social-17-0-mail_composer_cc_bcc/
Currently translated at 100.0% (17 of 17 strings)

Translation: social-17.0/social-17.0-mail_composer_cc_bcc
Translate-URL: https://translation.odoo-community.org/projects/social-17-0/social-17-0-mail_composer_cc_bcc/it/
…onstraint "unique_mail_message_id_res_partner_id_if_set" when adding the same user to CC field that is already set as a follower
### This changes

1. Refactor _generate_template_recipients

2. Fix invalid-email-address for Bcc
   - In standard, Bcc key in dict message was stripped in
https://github.com/odoo/odoo/blob/4394940a09900aa5b42cbc05355880598608d1b6/odoo/addons/base/models/ir_mail_server.py#L676
   - Duplicate the key to retain for later assertion
@imlopes
imlopes force-pushed the 19.0-mail_composer_cc_bcc branch 2 times, most recently from c0cbcf5 to 60c3aa7 Compare November 19, 2025 11:15
@yankinmax
yankinmax force-pushed the 19.0-mail_composer_cc_bcc branch from b2a4020 to 3877021 Compare November 20, 2025 18:26
@bosd

bosd commented Nov 21, 2025

Copy link
Copy Markdown
Contributor

@etobella Can you please merge?

@tuffstuff9

Copy link
Copy Markdown

LGTM

@visionsrlsolution

Copy link
Copy Markdown

When merge? any ETA? thx

@StefanRijnhart StefanRijnhart changed the title 19.0 mail composer cc bcc 19.0 mail_composer_cc_bcc Jan 28, 2026
@StefanRijnhart StefanRijnhart changed the title 19.0 mail_composer_cc_bcc [19.0] mail_composer_cc_bcc: Migration to 19.0 Jan 28, 2026
@StefanRijnhart

Copy link
Copy Markdown
Member

/ocabot migration mail_composer_cc_bcc

@OCA-git-bot OCA-git-bot added this to the 19.0 milestone Jan 28, 2026
@OCA-git-bot OCA-git-bot mentioned this pull request Jan 28, 2026
37 tasks
class IrMailServer(models.Model):
_inherit = "ir.mail_server"

def _prepare_email_message(self, message, smtp_session):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@davidepedraii

Copy link
Copy Markdown

Hello, we are experiencing some issues in the Version 19 of Odoo.sh , the issue is that: When sending emails with the BCC Module, we found an issue that when sending an email we encountered that the destination email didnt apparently exist, even if it exist and we have control of it, moreover the email resulted sent from Microsoft Outgoing email, but never recieved from the destination.

image

@giusybloomup

giusybloomup commented Mar 12, 2026

Copy link
Copy Markdown

When merge?
LGTM
thx :-)

@StefanRijnhart

Copy link
Copy Markdown
Member

@giusybloomup When the code is fixed

@NICO-SOLUTIONS NICO-SOLUTIONS left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewing prepare_email_message_ override and updated hash

class IrMailServer(models.Model):
_inherit = "ir.mail_server"

def _prepare_email_message(self, message, smtp_session):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def _prepare_email_message(self, message, smtp_session):
def _prepare_email_message__(self, message, smtp_session):

@NICO-SOLUTIONS NICO-SOLUTIONS Apr 8, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An extra double underscore was added to the method

)

VALID_HASHES = {
"mail.composer:_compute_partner_ids": ["4e49f0d6c53f41ac24b02176e97b600a"],

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"mail.composer:_compute_partner_ids": ["4e49f0d6c53f41ac24b02176e97b600a"],
"mail.composer:_compute_partner_ids": ["c3903ab78bf2e5d9aba078ac2689d974"],

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated hash to match the current upstream _compute_partner_ids

if x_odoo_bcc_value:
message["Bcc"] = x_odoo_bcc_value

smtp_from, smtp_to_list, message = super()._prepare_email_message(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
smtp_from, smtp_to_list, message = super()._prepare_email_message(
smtp_from, smtp_to_list, message = super()._prepare_email_message__(

@NICO-SOLUTIONS NICO-SOLUTIONS Apr 8, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Call updated prepare_email_message_ method with extra double underscore

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi,
Bcc mails doesn't works, even after renaming this method.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Linekio

Could you be a bit more specific? Please describe what happens, what you expected, and what you’ve already tried.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, it seems to be working, but it's sending multiple emails.

I did this test:
image

There are three identicals emails sent to acme_corp and brandon freeman, but not colleen diaz
image

Furthermore, the X-Odoo-Bcc header should be removed before sending. Recipients should not be able to identify hidden recipients simply by reading the header.
image
See odoo/odoo@2445f9e

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Linekio
I just quickly looked over the code again, and I think you are raising a valid concern.

The X-Odoo-Bcc handling seems questionable: the code reintroduces the value as a Bcc email header (message["Bcc"] = x_odoo_bcc_value) before sending. This looks like it could reintroduce the BCC leak that was fixed in Odoo core.

The smtp_to_list = [smtp_to] handling also looks suspicious. Combined with mutating recipients via pop(0), this could be related to the reported duplicate emails.

@cyrilmanuel
Could you please have another look at this part? It seems the implementation may need another pass to align with Odoo's current BCC handling (BCC should remain only part of the SMTP recipient list and should not be exposed in the outgoing message headers).

@Borruso Borruso left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@StefanRijnhart

Copy link
Copy Markdown
Member

@Borruso if this looks good to you, then you weren't looking very closely

@Borruso

Borruso commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

@skanndar skanndar left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested this branch on a clean 19.0 database and the Bcc feature does not work at all: the Bcc recipients never receive the email. Reproduction and root cause below — sorry for the late review, and thanks for keeping this module alive.

Setup: official odoo:19 image (build 19.0.20260723), fresh database, only this module installed. The SMTP session is replaced by a stub recording exactly what Odoo hands to the server (send_message(message, smtp_from, smtp_to_list)), so the envelope and the headers below are the real ones.

Scenario: composer on a record, To = to@example.com, Cc = cc1@example.com, Bcc = bcc1@example.com + bcc2@example.com.

Result: 3 emails handed to the server, with envelopes [cc1@], [to@], [cc1@]. Neither Bcc address ever appears in an envelope, and cc1@ gets two copies.

1. The ir.mail_server override never runs on 19.0. It defines _prepare_email_message, but 19.0 renamed that method to _prepare_email_message__ (odoo/addons/base/models/ir_mail_server.py). Nothing calls the old name any more, so neither the X-Odoo-BccBcc translation nor the context['recipients'] envelope restriction ever happen. Without a Bcc header, _prepare_smtp_to_list() — which builds the envelope from To/Cc/Bcc — simply never yields the Bcc addresses, hence the silent loss.

On 19.0 the envelope is already restricted by the send_validated_to context key that MailMail._send() fills with the normalized recipient of each email, so the override can be dropped in favour of setting a real Bcc header on the Bcc recipient's own email only. _alter_message__() strips that header right after building the envelope, so it is never transmitted.

2. The headers dict is shared by every email of the batch. In _prepare_outgoing_list(), m["headers"].update({"X-Odoo-Bcc": ...}) mutates the same dict instance that all the other emails received, so after the loop every email carries the last Bcc address. In my run all four prepared emails ended up with X-Odoo-Bcc: "B2" <bcc2@example.com>. Copying instead of mutating fixes it:

m["headers"] = {**m["headers"], "Bcc": m["email_to"][0]}

3. X-Msg-To-Add (new in 19.0) puts the Cc and Bcc addresses into the To header, once delivery works. MailThread._notify_by_email_get_headers() adds every external recipient to X-Msg-To-Add, and IrMailServer._alter_message__() merges that header into To at send time to enable Reply-All. It does not show up on this branch because the Bcc emails are never sent — but as soon as point 1 is fixed it does. I verified it A/B on a fixed version: dropping the header, each email carries the intended To/Cc; keeping it, every recipient (including the plain To one) receives To: to@…, cc1@…, bcc1@…, bcc2@…. Since this module builds the whole To/Cc itself, dropping it in _prepare_outgoing_list() looks like the right call:

headers = {k: v for k, v in m["headers"].items() if k != "X-Msg-To-Add"}

A related detail: when mail.email_to is empty Odoo builds an extra Cc-only email, which is a duplicate here (this is what #233 addresses on 18.0) — that is where the second copy to cc1@ comes from.

Points 1 and 2 apply to #163 and #189 as well, since all three migrations carry the same code.

I have a 19.0 version with the three fixes and tests covering them running on a real database. Happy to push it here as commits, or to open it wherever you prefer — whatever helps this land.

@NICO-SOLUTIONS

Copy link
Copy Markdown
Member

@skanndar
Feel free to push your version as commits. We can review it directly there.

@skanndar

skanndar commented Aug 5, 2026

Copy link
Copy Markdown

Thanks @NICO-SOLUTIONS — pushed: camptocamp#2, against the branch of this PR.

It is built on top of @Borruso's camptocamp#1 (his commit is included unchanged: renaming the override to _prepare_email_message__ and copying the headers dict is what makes the Bcc emails reach the server at all). On top of that, two commits' worth of changes in one:

  • The last recipient was silently losing its email. The Cc-only entry Odoo builds when mail.email_to is empty was being dropped with if len(res) > len(recipients): res.pop(), but recipients is a set in which a Cc partner is counted once, so the count is short and pop() removes the last entry instead of the duplicate. With one To, two Cc and two Bcc: cc1@ got two copies and bcc2@ got nothing.
  • X-Msg-To-Add dropped, as described in my review: 19.0 merges it into To at send time, which puts the Cc and Bcc addresses in everyone's To.

Plus two tests that fail before and pass after, and the existing suite green. The reproduction is the same setup as my review: official odoo:19 image, fresh database, SMTP session replaced by a stub that records exactly what Odoo hands to the server.

Happy to rebase onto this branch alone if you prefer #1 to be merged separately first.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.