Search in sources :

Example 1 with DeliveryServiceException

use of com.zimbra.common.service.DeliveryServiceException in project zm-mailbox by Zimbra.

the class ErejectTest method testThatSenderRcdUnDeliveredEmail.

/*
     * applyRulesToIncomingMessage() should throw an exception to cancel the message delivery.
     * No message is delivered.
     *
     * The following error will be logged:
     * ERROR - Evaluation failed. Reason: 'ereject' action refuses delivery of a message. Sieve rule evaluation is cancelled
     */
@Test
public void testThatSenderRcdUnDeliveredEmail() {
    Account acct1 = null;
    Mailbox mbox1 = null;
    Account acct2 = null;
    Mailbox mbox2 = null;
    try {
        acct1 = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com");
        mbox1 = MailboxManager.getInstance().getMailboxByAccount(acct1);
        RuleManager.clearCachedRules(acct1);
        acct2 = Provisioning.getInstance().get(Key.AccountBy.name, "test2@zimbra.com");
        mbox2 = MailboxManager.getInstance().getMailboxByAccount(acct2);
        LmtpEnvelope env = new LmtpEnvelope();
        LmtpAddress sender = new LmtpAddress("<test2@zimbra.com>", new String[] { "BODY", "SIZE" }, null);
        LmtpAddress recipient = new LmtpAddress("<test@zimbra.com>", null, null);
        env.setSender(sender);
        env.addLocalRecipient(recipient);
        acct1.setMailSieveScript(filterScript);
        RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox1), mbox1, new ParsedMessage(sampleBaseMsg.getBytes(), false), 0, acct1.getName(), env, new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true);
    } catch (DeliveryServiceException e) {
        if (e.getCause() instanceof ErejectException) {
            try {
                List<Integer> items = mbox1.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(MailItem.Type.MESSAGE);
                Assert.assertEquals(null, items);
            } catch (Exception ex) {
                ex.printStackTrace();
                fail("No exception should be thrown: " + ex.getMessage());
            }
        } else {
            fail("No exception other than DeliveryServiceException/ErejectException should be thrown: " + e.getMessage());
        }
    } catch (Exception e) {
        fail("No exception should be thrown: " + e.getMessage());
    }
}
Also used : OperationContext(com.zimbra.cs.mailbox.OperationContext) Account(com.zimbra.cs.account.Account) Mailbox(com.zimbra.cs.mailbox.Mailbox) ParsedMessage(com.zimbra.cs.mime.ParsedMessage) LmtpAddress(com.zimbra.cs.lmtpserver.LmtpAddress) List(java.util.List) LmtpEnvelope(com.zimbra.cs.lmtpserver.LmtpEnvelope) DeliveryContext(com.zimbra.cs.mailbox.DeliveryContext) ErejectException(com.zimbra.cs.filter.jsieve.ErejectException) DeliveryServiceException(com.zimbra.common.service.DeliveryServiceException) ServiceException(com.zimbra.common.service.ServiceException) ErejectException(com.zimbra.cs.filter.jsieve.ErejectException) DeliveryServiceException(com.zimbra.common.service.DeliveryServiceException) Test(org.junit.Test)

Example 2 with DeliveryServiceException

use of com.zimbra.common.service.DeliveryServiceException in project zm-mailbox by Zimbra.

the class ZimbraLmtpBackend method deliverMessageToLocalMailboxes.

private void deliverMessageToLocalMailboxes(Blob blob, BlobInputStream bis, byte[] data, MimeMessage mm, LmtpEnvelope env) throws ServiceException, IOException {
    List<LmtpAddress> recipients = env.getLocalRecipients();
    String envSender = env.getSender().getEmailAddress();
    boolean shared = recipients.size() > 1;
    List<Integer> targetMailboxIds = new ArrayList<Integer>(recipients.size());
    Map<LmtpAddress, RecipientDetail> rcptMap = new HashMap<LmtpAddress, RecipientDetail>(recipients.size());
    try {
        // Examine attachments indexing option for all recipients and
        // prepare ParsedMessage versions needed.  Parsing is done before
        // attempting delivery to any recipient.  Therefore, parse error
        // will result in non-delivery to all recipients.
        // ParsedMessage for users with attachments indexing
        ParsedMessage pmAttachIndex = null;
        // ParsedMessage for users without attachments indexing
        ParsedMessage pmNoAttachIndex = null;
        // message id for logging
        String msgId = null;
        for (LmtpAddress recipient : recipients) {
            String rcptEmail = recipient.getEmailAddress();
            Account account;
            Mailbox mbox;
            boolean attachmentsIndexingEnabled;
            try {
                account = Provisioning.getInstance().get(AccountBy.name, rcptEmail);
                if (account == null) {
                    ZimbraLog.mailbox.warn("No account found delivering mail to " + rcptEmail);
                    continue;
                }
                mbox = MailboxManager.getInstance().getMailboxByAccount(account);
                if (mbox == null) {
                    ZimbraLog.mailbox.warn("No mailbox found delivering mail to " + rcptEmail);
                    continue;
                }
                attachmentsIndexingEnabled = mbox.attachmentsIndexingEnabled();
            } catch (ServiceException se) {
                if (se.isReceiversFault()) {
                    ZimbraLog.mailbox.info("Recoverable exception getting mailbox for " + rcptEmail, se);
                    rcptMap.put(recipient, new RecipientDetail(null, null, null, false, DeliveryAction.defer));
                } else {
                    ZimbraLog.mailbox.warn("Unrecoverable exception getting mailbox for " + rcptEmail, se);
                }
                continue;
            }
            if (account != null && mbox != null) {
                ParsedMessageOptions pmo;
                if (mm != null) {
                    pmo = new ParsedMessageOptions().setContent(mm).setDigest(blob.getDigest()).setSize(blob.getRawSize());
                } else {
                    pmo = new ParsedMessageOptions(blob, data);
                }
                ParsedMessage pm;
                if (attachmentsIndexingEnabled) {
                    if (pmAttachIndex == null) {
                        pmo.setAttachmentIndexing(true);
                        ZimbraLog.lmtp.debug("Creating ParsedMessage from %s with attachment indexing enabled", data == null ? "file" : "memory");
                        pmAttachIndex = new ParsedMessage(pmo);
                    }
                    pm = pmAttachIndex;
                } else {
                    if (pmNoAttachIndex == null) {
                        pmo.setAttachmentIndexing(false);
                        ZimbraLog.lmtp.debug("Creating ParsedMessage from %s with attachment indexing disabled", data == null ? "file" : "memory");
                        pmNoAttachIndex = new ParsedMessage(pmo);
                    }
                    pm = pmNoAttachIndex;
                }
                msgId = pm.getMessageID();
                if (account.isPrefMailLocalDeliveryDisabled()) {
                    ZimbraLog.lmtp.debug("Local delivery disabled for account %s", rcptEmail);
                    rcptMap.put(recipient, new RecipientDetail(account, mbox, pm, false, DeliveryAction.discard));
                    continue;
                }
                // For non-shared delivery (i.e. only one recipient),
                // always deliver regardless of backup mode.
                DeliveryAction da = DeliveryAction.deliver;
                boolean endSharedDelivery = false;
                if (shared) {
                    if (mbox.beginSharedDelivery()) {
                        endSharedDelivery = true;
                    } else {
                        // Skip delivery to mailboxes in backup mode.
                        da = DeliveryAction.defer;
                    }
                }
                rcptMap.put(recipient, new RecipientDetail(account, mbox, pm, endSharedDelivery, da));
                if (da == DeliveryAction.deliver) {
                    targetMailboxIds.add(mbox.getId());
                }
            }
        }
        ZimbraLog.removeAccountFromContext();
        if (ZimbraLog.lmtp.isInfoEnabled()) {
            ZimbraLog.lmtp.info("Delivering message: size=%s, nrcpts=%d, sender=%s, msgid=%s", env.getSize() == 0 ? "unspecified" : Integer.toString(env.getSize()) + " bytes", recipients.size(), env.getSender(), msgId == null ? "" : msgId);
        }
        DeliveryContext sharedDeliveryCtxt = new DeliveryContext(shared, targetMailboxIds);
        sharedDeliveryCtxt.setIncomingBlob(blob);
        // version each recipient needs.  Deliver!
        for (LmtpAddress recipient : recipients) {
            String rcptEmail = recipient.getEmailAddress();
            LmtpReply reply = LmtpReply.TEMPORARY_FAILURE;
            RecipientDetail rd = rcptMap.get(recipient);
            if (rd == null) {
                // Account or mailbox not found.
                ZimbraLog.lmtp.info("rejecting message from=%s,to=%s: account or mailbox not found", envSender, rcptEmail);
                recipient.setDeliveryStatus(LmtpReply.PERMANENT_FAILURE);
                continue;
            }
            if (rd.account != null) {
                ZimbraLog.addAccountNameToContext(rd.account.getName());
            }
            if (rd.mbox != null) {
                ZimbraLog.addMboxToContext(rd.mbox.getId());
            }
            boolean success = false;
            try {
                switch(rd.action) {
                    case discard:
                        ZimbraLog.lmtp.info("accepted and discarded message from=%s,to=%s: local delivery is disabled", envSender, rcptEmail);
                        if (rd.account.getPrefMailForwardingAddress() != null) {
                            // mail forwarding is set up
                            for (LmtpCallback callback : callbacks) {
                                ZimbraLog.lmtp.debug("Executing callback %s", callback.getClass().getName());
                                callback.forwardWithoutDelivery(rd.account, rd.mbox, envSender, rcptEmail, rd.pm);
                            }
                        }
                        reply = LmtpReply.DELIVERY_OK;
                        break;
                    case deliver:
                        Account account = rd.account;
                        Mailbox mbox = rd.mbox;
                        ParsedMessage pm = rd.pm;
                        List<ItemId> addedMessageIds = null;
                        ReentrantLock lock = mailboxDeliveryLocks.get(mbox.getId());
                        boolean acquiredLock;
                        try {
                            // Wait for the lock, up to the timeout
                            acquiredLock = lock.tryLock(LC.zimbra_mailbox_lock_timeout.intValue(), TimeUnit.SECONDS);
                        } catch (InterruptedException e) {
                            acquiredLock = false;
                        }
                        if (!acquiredLock) {
                            ZimbraLog.lmtp.info("try again for message from=%s,to=%s: another mail delivery in progress.", envSender, rcptEmail);
                            reply = LmtpReply.TEMPORARY_FAILURE;
                            break;
                        }
                        try {
                            if (dedupe(pm, mbox)) {
                                // message was already delivered to this mailbox
                                ZimbraLog.lmtp.info("Not delivering message with duplicate Message-ID %s", pm.getMessageID());
                            } else if (mbox.dedupeForSelfMsg(pm)) {
                                ZimbraLog.mailbox.info("not delivering message, because it is a duplicate of sent message %s", pm.getMessageID());
                            } else if (recipient.getSkipFilters()) {
                                msgId = pm.getMessageID();
                                int folderId = Mailbox.ID_FOLDER_INBOX;
                                if (recipient.getFolder() != null) {
                                    try {
                                        Folder folder = mbox.getFolderByPath(null, recipient.getFolder());
                                        folderId = folder.getId();
                                    } catch (ServiceException se) {
                                        if (se.getCode().equals(MailServiceException.NO_SUCH_FOLDER)) {
                                            Folder folder = mbox.createFolder(null, recipient.getFolder(), new Folder.FolderOptions().setDefaultView(MailItem.Type.MESSAGE));
                                            folderId = folder.getId();
                                        } else {
                                            throw se;
                                        }
                                    }
                                }
                                int flags = Flag.BITMASK_UNREAD;
                                if (recipient.getFlags() != null) {
                                    flags = Flag.toBitmask(recipient.getFlags());
                                }
                                DeliveryOptions dopt = new DeliveryOptions().setFolderId(folderId);
                                dopt.setFlags(flags).setTags(recipient.getTags()).setRecipientEmail(rcptEmail);
                                Message msg = mbox.addMessage(null, pm, dopt, sharedDeliveryCtxt);
                                addedMessageIds = Lists.newArrayList(new ItemId(msg));
                            } else if (!DebugConfig.disableIncomingFilter) {
                                // Get msgid first, to avoid having to reopen and reparse the blob
                                // file if Mailbox.addMessageInternal() closes it.
                                pm.getMessageID();
                                addedMessageIds = RuleManager.applyRulesToIncomingMessage(null, mbox, pm, (int) blob.getRawSize(), rcptEmail, env, sharedDeliveryCtxt, Mailbox.ID_FOLDER_INBOX, false, true);
                            } else {
                                pm.getMessageID();
                                DeliveryOptions dopt = new DeliveryOptions().setFolderId(Mailbox.ID_FOLDER_INBOX);
                                dopt.setFlags(Flag.BITMASK_UNREAD).setRecipientEmail(rcptEmail);
                                Message msg = mbox.addMessage(null, pm, dopt, sharedDeliveryCtxt);
                                addedMessageIds = Lists.newArrayList(new ItemId(msg));
                            }
                            success = true;
                            if (addedMessageIds != null && addedMessageIds.size() > 0) {
                                addToDedupeCache(pm, mbox);
                            }
                        } finally {
                            lock.unlock();
                        }
                        if (addedMessageIds != null && addedMessageIds.size() > 0) {
                            // Execute callbacks
                            for (LmtpCallback callback : callbacks) {
                                for (ItemId id : addedMessageIds) {
                                    if (id.belongsTo(mbox)) {
                                        // Message was added to the local mailbox, as opposed to a mountpoint.
                                        ZimbraLog.lmtp.debug("Executing callback %s", callback.getClass().getName());
                                        try {
                                            Message msg = mbox.getMessageById(null, id.getId());
                                            callback.afterDelivery(account, mbox, envSender, rcptEmail, msg);
                                        } catch (OutOfMemoryError oome) {
                                            Zimbra.halt("LMTP callback failed", oome);
                                        } catch (Throwable t) {
                                            ZimbraLog.lmtp.warn("LMTP callback threw an exception", t);
                                        }
                                    }
                                }
                            }
                        }
                        reply = LmtpReply.DELIVERY_OK;
                        break;
                    case defer:
                        // Delivery to mailbox skipped.  Let MTA retry again later.
                        // This case happens for shared delivery to a mailbox in
                        // backup mode.
                        ZimbraLog.lmtp.info("try again for message from=%s,to=%s: mailbox skipped", envSender, rcptEmail);
                        reply = LmtpReply.TEMPORARY_FAILURE;
                        break;
                }
            } catch (DeliveryServiceException e) {
                ZimbraLog.lmtp.info("rejecting message from=%s,to=%s: sieve filter rule", envSender, rcptEmail);
                reply = LmtpReply.PERMANENT_MESSAGE_REFUSED;
            } catch (ServiceException e) {
                if (e.getCode().equals(MailServiceException.QUOTA_EXCEEDED)) {
                    ZimbraLog.lmtp.info("rejecting message from=%s,to=%s: overquota", envSender, rcptEmail);
                    if (config.isPermanentFailureWhenOverQuota()) {
                        reply = LmtpReply.PERMANENT_FAILURE_OVER_QUOTA;
                    } else {
                        reply = LmtpReply.TEMPORARY_FAILURE_OVER_QUOTA;
                    }
                } else if (e.isReceiversFault()) {
                    ZimbraLog.lmtp.info("try again for message from=%s,to=%s", envSender, rcptEmail, e);
                    reply = LmtpReply.TEMPORARY_FAILURE;
                } else {
                    ZimbraLog.lmtp.info("rejecting message from=%s,to=%s", envSender, rcptEmail, e);
                    reply = LmtpReply.PERMANENT_FAILURE;
                }
            } catch (Exception e) {
                reply = LmtpReply.TEMPORARY_FAILURE;
                ZimbraLog.lmtp.warn("try again for message from=%s,to=%s", envSender, rcptEmail, e);
            } finally {
                if (rd.action == DeliveryAction.deliver && !success) {
                    // Message was not delivered.  Remove it from the dedupe
                    // cache so we don't dedupe it on LMTP retry.
                    removeFromDedupeCache(msgId, rd.mbox);
                }
                recipient.setDeliveryStatus(reply);
                if (shared && rd != null && rd.esd) {
                    rd.mbox.endSharedDelivery();
                    rd.esd = false;
                }
            }
        }
        // If this message is being streamed from disk, cache it
        ParsedMessage mimeSource = pmAttachIndex != null ? pmAttachIndex : pmNoAttachIndex;
        MailboxBlob mblob = sharedDeliveryCtxt.getMailboxBlob();
        if (mblob != null && mimeSource != null) {
            if (bis == null) {
                bis = mimeSource.getBlobInputStream();
            }
            if (bis != null) {
                try {
                    // Update the MimeMessage with the blob that's stored inside the mailbox,
                    // since the incoming blob will be deleted.
                    Blob storedBlob = mblob.getLocalBlob();
                    bis.fileMoved(storedBlob.getFile());
                    MessageCache.cacheMessage(mblob.getDigest(), mimeSource.getOriginalMessage(), mimeSource.getMimeMessage());
                } catch (IOException e) {
                    ZimbraLog.lmtp.warn("Unable to cache message for " + mblob, e);
                }
            }
        }
    } finally {
        // called, we check and fix those here.
        if (shared) {
            for (RecipientDetail rd : rcptMap.values()) {
                if (rd.esd && rd.mbox != null)
                    rd.mbox.endSharedDelivery();
            }
        }
    }
}
Also used : Account(com.zimbra.cs.account.Account) ParsedMessage(com.zimbra.cs.mime.ParsedMessage) Message(com.zimbra.cs.mailbox.Message) MimeMessage(javax.mail.internet.MimeMessage) HashMap(java.util.HashMap) CopyOnWriteArrayList(java.util.concurrent.CopyOnWriteArrayList) ArrayList(java.util.ArrayList) Folder(com.zimbra.cs.mailbox.Folder) ItemId(com.zimbra.cs.service.util.ItemId) DeliveryServiceException(com.zimbra.common.service.DeliveryServiceException) Mailbox(com.zimbra.cs.mailbox.Mailbox) DeliveryContext(com.zimbra.cs.mailbox.DeliveryContext) DeliveryOptions(com.zimbra.cs.mailbox.DeliveryOptions) ReentrantLock(java.util.concurrent.locks.ReentrantLock) Blob(com.zimbra.cs.store.Blob) MailboxBlob(com.zimbra.cs.store.MailboxBlob) ParsedMessageOptions(com.zimbra.cs.mime.ParsedMessageOptions) MailboxBlob(com.zimbra.cs.store.MailboxBlob) ParsedMessage(com.zimbra.cs.mime.ParsedMessage) IOException(java.io.IOException) MessagingException(javax.mail.MessagingException) LmtpProtocolException(com.zimbra.common.lmtp.LmtpProtocolException) ServiceException(com.zimbra.common.service.ServiceException) IOException(java.io.IOException) DeliveryServiceException(com.zimbra.common.service.DeliveryServiceException) MailServiceException(com.zimbra.cs.mailbox.MailServiceException) ServiceException(com.zimbra.common.service.ServiceException) DeliveryServiceException(com.zimbra.common.service.DeliveryServiceException) MailServiceException(com.zimbra.cs.mailbox.MailServiceException)

Example 3 with DeliveryServiceException

use of com.zimbra.common.service.DeliveryServiceException in project zm-mailbox by Zimbra.

the class ErejectTest method test.

/*
     * applyRulesToIncomingMessage() should throw an exception to cancel the message delivery.
     * No message is delivered.
     *
     * The following error will be logged:
     * ERROR - Evaluation failed. Reason: 'ereject' action refuses delivery of a message. Sieve rule evaluation is cancelled
     */
@Test
public void test() {
    Account acct1 = null;
    Mailbox mbox1 = null;
    boolean isPassed = false;
    try {
        acct1 = Provisioning.getInstance().get(Key.AccountBy.name, "test@zimbra.com");
        mbox1 = MailboxManager.getInstance().getMailboxByAccount(acct1);
        RuleManager.clearCachedRules(acct1);
        LmtpEnvelope env = new LmtpEnvelope();
        LmtpAddress sender = new LmtpAddress("<test2@zimbra.com>", new String[] { "BODY", "SIZE" }, null);
        LmtpAddress recipient = new LmtpAddress("<test@zimbra.com>", null, null);
        env.setSender(sender);
        env.addLocalRecipient(recipient);
        acct1.setMailSieveScript(filterScript);
        RuleManager.applyRulesToIncomingMessage(new OperationContext(mbox1), mbox1, new ParsedMessage(sampleBaseMsg.getBytes(), false), 0, acct1.getName(), env, new DeliveryContext(), Mailbox.ID_FOLDER_INBOX, true);
    } catch (DeliveryServiceException e) {
        if (e.getCause() instanceof ErejectException) {
            try {
                List<Integer> items = mbox1.getItemIds(null, Mailbox.ID_FOLDER_INBOX).getIds(MailItem.Type.MESSAGE);
                Assert.assertEquals(null, items);
                isPassed = true;
            } catch (Exception ex) {
                fail("No exception should be thrown: " + ex.getMessage());
            }
        } else {
            fail("No exception other than DeliveryServiceException/ErejectException should be thrown: " + e.getMessage());
        }
    } catch (Exception e) {
        fail("No exception should be thrown: " + e.getMessage());
    }
    if (!isPassed) {
        fail("DeliveryServiceException/ErejectException should have been thrown, but no exception is thrown");
    }
}
Also used : OperationContext(com.zimbra.cs.mailbox.OperationContext) Account(com.zimbra.cs.account.Account) Mailbox(com.zimbra.cs.mailbox.Mailbox) ParsedMessage(com.zimbra.cs.mime.ParsedMessage) LmtpAddress(com.zimbra.cs.lmtpserver.LmtpAddress) List(java.util.List) LmtpEnvelope(com.zimbra.cs.lmtpserver.LmtpEnvelope) DeliveryContext(com.zimbra.cs.mailbox.DeliveryContext) ErejectException(com.zimbra.cs.filter.jsieve.ErejectException) DeliveryServiceException(com.zimbra.common.service.DeliveryServiceException) ServiceException(com.zimbra.common.service.ServiceException) ErejectException(com.zimbra.cs.filter.jsieve.ErejectException) DeliveryServiceException(com.zimbra.common.service.DeliveryServiceException) Test(org.junit.Test)

Aggregations

DeliveryServiceException (com.zimbra.common.service.DeliveryServiceException)3 ServiceException (com.zimbra.common.service.ServiceException)3 Account (com.zimbra.cs.account.Account)3 DeliveryContext (com.zimbra.cs.mailbox.DeliveryContext)3 Mailbox (com.zimbra.cs.mailbox.Mailbox)3 ParsedMessage (com.zimbra.cs.mime.ParsedMessage)3 ErejectException (com.zimbra.cs.filter.jsieve.ErejectException)2 LmtpAddress (com.zimbra.cs.lmtpserver.LmtpAddress)2 LmtpEnvelope (com.zimbra.cs.lmtpserver.LmtpEnvelope)2 OperationContext (com.zimbra.cs.mailbox.OperationContext)2 List (java.util.List)2 Test (org.junit.Test)2 LmtpProtocolException (com.zimbra.common.lmtp.LmtpProtocolException)1 DeliveryOptions (com.zimbra.cs.mailbox.DeliveryOptions)1 Folder (com.zimbra.cs.mailbox.Folder)1 MailServiceException (com.zimbra.cs.mailbox.MailServiceException)1 Message (com.zimbra.cs.mailbox.Message)1 ParsedMessageOptions (com.zimbra.cs.mime.ParsedMessageOptions)1 ItemId (com.zimbra.cs.service.util.ItemId)1 Blob (com.zimbra.cs.store.Blob)1