From 3b0efc9454b00d84eec48c70645b9696463996cb Mon Sep 17 00:00:00 2001 From: Davide Frison <36330277+frisonisland@users.noreply.github.com> Date: Wed, 3 May 2023 09:02:21 +0200 Subject: [PATCH] fix: [CO-690] delegated account sent mail always read (#209) * fix: MailSender delegated send always read status * When a delegated email is sent always set the status "read" in Sent folder. * chore: MailSender add id of item in delegated request test: add test to check delegated email is read and only in delegated user sent folder by default * chore: add bug number --- .../com/zimbra/cs/mailbox/MailSender.java | 16 +++- .../com/zimbra/cs/mailbox/MailSenderIT.java | 96 +++++++++++++++++++ 2 files changed, 108 insertions(+), 4 deletions(-) create mode 100644 store/src/test/java/com/zimbra/cs/mailbox/MailSenderIT.java diff --git a/store/src/main/java/com/zimbra/cs/mailbox/MailSender.java b/store/src/main/java/com/zimbra/cs/mailbox/MailSender.java index e52c7638f28..890ac5586e9 100644 --- a/store/src/main/java/com/zimbra/cs/mailbox/MailSender.java +++ b/store/src/main/java/com/zimbra/cs/mailbox/MailSender.java @@ -556,6 +556,14 @@ public ItemId sendMimeMessage(OperationContext octxt, Mailbox mbox, Boolean save /** * Sends a message. + * If request is delegated, save to sent behavior follows + * {@link Provisioning#A_zimbraPrefDelegatedSendSaveTarget}: + * - owner: saves the email only to delegated account, status read + * - sender: saves the email to original user account, status read + * - both: performs both above + * - none: does not save sent email + * Note: the email is sent in any case. + * */ public ItemId sendMimeMessage(OperationContext octxt, Mailbox mbox, MimeMessage mm) throws ServiceException { @@ -712,13 +720,10 @@ public ItemId sendMimeMessage(OperationContext octxt, Mailbox mbox, MimeMessage } } - // for delegated sends automatically save a copy to the "From" user's mailbox, unless we've been - // specifically requested not to do the save (for instance BES does its own save to Sent, so does'nt - // want it done here). if (allowSaveToSent && hasRecipients && !isDataSourceSender() && isDelegatedRequest && (PrefDelegatedSendSaveTarget.owner == acct.getPrefDelegatedSendSaveTarget() || PrefDelegatedSendSaveTarget.both == acct.getPrefDelegatedSendSaveTarget())) { - int flags = Flag.BITMASK_UNREAD | Flag.BITMASK_FROM_ME; + int flags = Flag.BITMASK_FROM_ME; // save the sent copy using the target's credentials, as the sender doesn't necessarily have write access OperationContext octxtTarget = new OperationContext(acct); if (pm == null || pm.isAttachmentIndexingEnabled() != mbox.attachmentsIndexingEnabled()) { @@ -734,6 +739,9 @@ public ItemId sendMimeMessage(OperationContext octxt, Mailbox mbox, MimeMessage RuleManager.applyRulesToOutgoingMessage(octxtTarget, mbox, pm, sentFolderId, true, flags, null, convId); for (ItemId itemId : addedItemIds) { rollbacks.add(new RollbackData(mbox, itemId.getId())); + if (returnItemId == null) { + returnItemId = itemId; + } } } } diff --git a/store/src/test/java/com/zimbra/cs/mailbox/MailSenderIT.java b/store/src/test/java/com/zimbra/cs/mailbox/MailSenderIT.java new file mode 100644 index 00000000000..19fc96a6aff --- /dev/null +++ b/store/src/test/java/com/zimbra/cs/mailbox/MailSenderIT.java @@ -0,0 +1,96 @@ +// SPDX-FileCopyrightText: 2023 Zextras +// +// SPDX-License-Identifier: AGPL-3.0-only + +package com.zimbra.cs.mailbox; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; + +import com.zimbra.cs.account.Account; +import com.zimbra.cs.account.Provisioning; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.UUID; +import javax.mail.Address; +import javax.mail.Session; +import javax.mail.internet.InternetAddress; +import javax.mail.internet.MimeMessage; +import javax.mail.internet.MimeMessage.RecipientType; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.mockito.Mockito; + +/** + * Bug: CO-690 + */ +public class MailSenderIT { + + private static Provisioning prov; + + @BeforeClass + public static void init() throws Exception { + MailboxTestUtil.initServer(); + prov = Provisioning.getInstance(); + } + + @Before + public void setUp() throws Exception { + MailboxTestUtil.clearData(); + } + + @Test + public void shouldSaveSentEmailInDelegatedAccountWithReadStatus() throws Exception { + + String delegatedId = UUID.randomUUID().toString(); + String delegatedEmail = delegatedId + "@test.com"; + + String userId = UUID.randomUUID().toString(); + String userEmail = userId + "@test.com"; + // create delegated account + Map delegatedAttrs = new HashMap<>(); + delegatedAttrs.put(Provisioning.A_zimbraPrefAllowAddressForDelegatedSender, userEmail); + delegatedAttrs.put(Provisioning.A_zimbraId, delegatedId); + Account delegatedAccount = prov.createAccount(delegatedEmail, "secret", delegatedAttrs); + + // create user account + Map userAttrs = new HashMap<>(); + userAttrs.put(Provisioning.A_zimbraPrefAllowAddressForDelegatedSender, userEmail); + userAttrs.put(Provisioning.A_zimbraId, userId); + Account userAccount = prov.createAccount(userEmail, "secret", userAttrs); + + final Mailbox delegatedMailbox = MailboxManager.getInstance().getMailboxByAccount(delegatedAccount); + + final MimeMessage mimeMessage = new MimeMessage(Session.getInstance(new Properties())); + + // spy MailSender to avoid sending real email + final MailSender mailSender = spy(MailSender.class); + Address[] recipients = new Address[]{new InternetAddress(userEmail)}; + doReturn(List.of(recipients)).when(mailSender).sendMessage(Mockito.any(Mailbox.class), Mockito.any(MimeMessage.class), Mockito.any( + java.util.Collection.class)); + final OperationContext operationContext = new OperationContext(userAccount); + mimeMessage.setFrom(new InternetAddress(delegatedEmail)); + mimeMessage.setRecipients(RecipientType.TO, recipients); + mimeMessage.setSubject("Test email"); + mimeMessage.setText("Hello there!"); + mimeMessage.setSender(new InternetAddress(userEmail)); + // send email logged in as user, using delegated account + mailSender.sendMimeMessage(operationContext, delegatedMailbox, mimeMessage); + + final Mailbox userMailbox = MailboxManager.getInstance().getMailboxByAccount(userAccount); + final OperationContext delegatedAccountOpCtx = new OperationContext(delegatedAccount); + // Check email is in delegated sent and read + final Folder delegatedSent = delegatedMailbox.getFolderByPath(delegatedAccountOpCtx, "sent"); + Assert.assertEquals(0, delegatedSent.getUnreadCount()); + Assert.assertEquals(1, delegatedSent.getSize()); + // Check email is in user sent and read + final Folder userSent = userMailbox.getFolderByPath(operationContext, "sent"); + Assert.assertEquals(0, userSent.getUnreadCount()); + Assert.assertEquals(0, userSent.getSize()); + } + +}