diff --git a/src/backend/core/mda/inbound.py b/src/backend/core/mda/inbound.py index 42ce9638..f013f367 100644 --- a/src/backend/core/mda/inbound.py +++ b/src/backend/core/mda/inbound.py @@ -630,8 +630,10 @@ def deliver_inbound_message( # pylint: disable=too-many-branches, too-many-stat models.Contact(email=email).full_clean( exclude=["mailbox", "name"] ) # Validate + recipient_contact, created = models.Contact.objects.get_or_create( email=email, + name=name or email.split("@")[0], mailbox=mailbox, # Associate contact with the recipient mailbox defaults={"name": name or email.split("@")[0], "email": email}, ) diff --git a/src/backend/core/migrations/0010_alter_contact_unique_together.py b/src/backend/core/migrations/0010_alter_contact_unique_together.py new file mode 100644 index 00000000..129797da --- /dev/null +++ b/src/backend/core/migrations/0010_alter_contact_unique_together.py @@ -0,0 +1,17 @@ +# Generated by Django 5.1.12 on 2025-10-03 11:53 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0009_messagetemplate_blob_maildomain_alter_blob_mailbox_and_more'), + ] + + operations = [ + migrations.AlterUniqueTogether( + name='contact', + unique_together={('email', 'mailbox', 'name')}, + ), + ] diff --git a/src/backend/core/models.py b/src/backend/core/models.py index c65554c0..2e002088 100644 --- a/src/backend/core/models.py +++ b/src/backend/core/models.py @@ -1126,7 +1126,7 @@ class Meta: db_table = "messages_contact" verbose_name = _("contact") verbose_name_plural = _("contacts") - unique_together = ("email", "mailbox") + unique_together = ("email", "mailbox", "name") def __str__(self): if self.name: diff --git a/src/backend/core/tests/importer/test_imap_import.py b/src/backend/core/tests/importer/test_imap_import.py index 0558ba62..451f507f 100644 --- a/src/backend/core/tests/importer/test_imap_import.py +++ b/src/backend/core/tests/importer/test_imap_import.py @@ -67,6 +67,7 @@ def email_with_duplicate_recipients(): msg["From"] = "sender@example.com" msg["To"] = "recipient@example.com, recipient@example.com" # Duplicate TO msg["Cc"] = "cc@example.com, cc@example.com" # Duplicate CC + msg["Bcc"] = "Jean BCC , Marie BCC , bcc@example.com" # Duplicate BCC msg["Subject"] = "Test Subject with Duplicates" msg["Message-ID"] = "" msg["Date"] = "Thu, 1 Jan 2024 12:00:00 +0000" @@ -442,9 +443,6 @@ def test_imap_import_task_duplicate_recipients( recipients = message.recipients.all() recipient_emails = [r.contact.email for r in recipients] - # Should have unique recipients (no duplicates) - assert len(recipient_emails) == len(set(recipient_emails)) - # Should have the expected recipients assert "recipient@example.com" in recipient_emails assert "cc@example.com" in recipient_emails @@ -456,9 +454,13 @@ def test_imap_import_task_duplicate_recipients( cc_recipients = message.recipients.filter( type=enums.MessageRecipientTypeChoices.CC ) + bcc_recipients = message.recipients.filter( + type=enums.MessageRecipientTypeChoices.BCC + ) assert to_recipients.count() == 1 # Only one TO recipient (duplicate removed) assert cc_recipients.count() == 1 # Only one CC recipient (duplicate removed) + assert bcc_recipients.count() == 3 # There is differents names for the same email so 3 contacts are created # Verify the content assert (