Search in sources :

Example 16 with SendFailedException

use of javax.mail.SendFailedException in project zm-mailbox by Zimbra.

the class MailSender method sendMessage.

/**
 * @return a Collection of successfully sent recipient Addresses
 */
protected Collection<Address> sendMessage(Mailbox mbox, final MimeMessage mm, Collection<RollbackData> rollbacks) throws SafeMessagingException, IOException {
    // send the message via SMTP
    HashSet<Address> sentAddresses = new HashSet<Address>();
    mCurrentHostIndex = 0;
    String hostname = getNextHost();
    try {
        // Initialize recipient addresses
        Address[] rcptAddresses = getRecipients(mm);
        if (rcptAddresses == null || rcptAddresses.length == 0)
            throw new SendFailedException("No recipient addresses");
        while (true) {
            try {
                logMessage(mm, rcptAddresses, mEnvelopeFrom, hostname, null != mOriginalMessageId ? mOriginalMessageId.toString() : null, mUploads, mReplyType, null);
                if (hostname != null) {
                    sendMessageToHost(hostname, mm, rcptAddresses);
                } else {
                    Transport.send(mm, rcptAddresses);
                }
                Collections.addAll(sentAddresses, rcptAddresses);
                break;
            } catch (SendFailedException sfe) {
                throw sfe;
            } catch (MessagingException e) {
                Exception chained = e.getNextException();
                if (chained instanceof SocketException || chained instanceof UnknownHostException) {
                    String hostString = (hostname != null ? " " + hostname : "");
                    ZimbraLog.smtp.warn("Unable to connect to SMTP server%s: %s.", hostString, chained.toString());
                    if (mTrackBadHosts) {
                        JMSession.markSmtpHostBad(hostname);
                    }
                    hostname = getNextHost();
                    if (hostname == null) {
                        throw e;
                    }
                    ZimbraLog.smtp.info("Attempting to send to %s.", hostname);
                } else {
                    throw e;
                }
            }
        }
    } catch (SendFailedException e) {
        // skip roll backs for partial send failure cases!
        if (isSendPartial())
            throw new SafeSendFailedException(e);
        for (RollbackData rdata : rollbacks) {
            if (rdata != null) {
                rdata.rollback();
            }
        }
        throw new SafeSendFailedException(e);
    } catch (MessagingException e) {
        for (RollbackData rdata : rollbacks) {
            if (rdata != null) {
                rdata.rollback();
            }
        }
        throw new SafeMessagingException(e);
    } catch (RuntimeException e) {
        for (RollbackData rdata : rollbacks) {
            if (rdata != null) {
                rdata.rollback();
            }
        }
        throw e;
    }
    return sentAddresses;
}
Also used : SocketException(java.net.SocketException) SendFailedException(javax.mail.SendFailedException) Address(javax.mail.Address) InternetAddress(javax.mail.internet.InternetAddress) JavaMailInternetAddress(com.zimbra.common.mime.shim.JavaMailInternetAddress) UnknownHostException(java.net.UnknownHostException) MessagingException(javax.mail.MessagingException) MessagingException(javax.mail.MessagingException) NoSuchItemException(com.zimbra.cs.mailbox.MailServiceException.NoSuchItemException) SendFailedException(javax.mail.SendFailedException) ServiceException(com.zimbra.common.service.ServiceException) SocketException(java.net.SocketException) IOException(java.io.IOException) UnknownHostException(java.net.UnknownHostException) HashSet(java.util.HashSet)

Example 17 with SendFailedException

use of javax.mail.SendFailedException in project zm-mailbox by Zimbra.

the class SmtpTransport method notify.

private void notify(Exception ex, Message msg, Address[] addrs) throws SendFailedException {
    Set<String> validRcpts = connection.getValidRecipients();
    Set<String> invalidRcpts = connection.getInvalidRecipients();
    List<Address> validAddrs = new ArrayList<Address>(validRcpts.size());
    List<Address> invalidAddrs = new ArrayList<Address>(invalidRcpts.size());
    for (Address addr : addrs) {
        if (addr instanceof InternetAddress) {
            InternetAddress iaddr = (InternetAddress) addr;
            if (validRcpts.contains(iaddr.getAddress())) {
                validAddrs.add(iaddr);
            } else if (invalidRcpts.contains(iaddr.getAddress())) {
                invalidAddrs.add(iaddr);
            }
        }
    }
    Address[] validSent = Iterables.toArray(validAddrs, Address.class);
    Address[] validUnsent = new Address[0];
    Address[] invalid = Iterables.toArray(invalidAddrs, Address.class);
    int notify = ex != null ? TransportEvent.MESSAGE_NOT_DELIVERED : invalid.length > 0 ? TransportEvent.MESSAGE_PARTIALLY_DELIVERED : TransportEvent.MESSAGE_DELIVERED;
    notifyTransportListeners(notify, validSent, validUnsent, invalid, msg);
    switch(notify) {
        case TransportEvent.MESSAGE_NOT_DELIVERED:
            throw new SendFailedException("MESSAGE_NOT_DELIVERED", ex, validSent, validUnsent, invalid);
        case TransportEvent.MESSAGE_PARTIALLY_DELIVERED:
            throw new SendFailedException("MESSAGE_PARTIALLY_DELIVERED", ex, validSent, validUnsent, invalid);
    }
}
Also used : InternetAddress(javax.mail.internet.InternetAddress) SendFailedException(javax.mail.SendFailedException) Address(javax.mail.Address) InternetAddress(javax.mail.internet.InternetAddress) ArrayList(java.util.ArrayList)

Example 18 with SendFailedException

use of javax.mail.SendFailedException in project zm-mailbox by Zimbra.

the class CalendarRequest method sendCalendarMessageInternal.

/**
 * Send an iCalendar email message and optionally create/update/cancel
 * corresponding appointment/invite in sender's calendar.
 * @param zsc
 * @param apptFolderId
 * @param acct
 * @param mbox
 * @param csd
 * @param response
 * @param updateOwnAppointment if true, corresponding change is made to
 *                             sender's calendar
 * @param forceSend
 * @param sendQueue
 * @param updatePrevFolders if true, updates prevFolders field with Trash in database
 * @return
 * @throws ServiceException
 */
private static Element sendCalendarMessageInternal(ZimbraSoapContext zsc, OperationContext octxt, int apptFolderId, Account acct, Mailbox mbox, CalSendData csd, Element response, boolean updateOwnAppointment, boolean forceSend, MailSendQueue sendQueue, boolean updatePrevFolders) throws ServiceException {
    boolean onBehalfOf = isOnBehalfOfRequest(zsc);
    boolean notifyOwner = onBehalfOf && acct.getBooleanAttr(Provisioning.A_zimbraPrefCalendarNotifyDelegatedChanges, false);
    if (notifyOwner) {
        try {
            InternetAddress addr = AccountUtil.getFriendlyEmailAddress(acct);
            csd.mMm.addRecipient(javax.mail.Message.RecipientType.TO, addr);
        } catch (MessagingException e) {
            throw ServiceException.FAILURE("count not add calendar owner to recipient list", e);
        }
    }
    // in a non-delegated request.
    if (!onBehalfOf) {
        String[] aliases = acct.getMailAlias();
        String[] addrs;
        if (aliases != null && aliases.length > 0) {
            addrs = new String[aliases.length + 1];
            addrs[0] = acct.getAttr(Provisioning.A_mail);
            for (int i = 0; i < aliases.length; i++) {
                addrs[i + 1] = aliases[i];
            }
        } else {
            addrs = new String[1];
            addrs[0] = acct.getAttr(Provisioning.A_mail);
        }
        try {
            Mime.removeRecipients(csd.mMm, addrs);
        } catch (MessagingException e) {
        }
    }
    ParsedMessage pm = new ParsedMessage(csd.mMm, false);
    if (csd.mInvite.getFragment() == null || csd.mInvite.getFragment().equals("")) {
        csd.mInvite.setFragment(pm.getFragment(acct.getLocale()));
    }
    boolean willNotify = false;
    if (!csd.mDontNotifyAttendees) {
        try {
            Address[] rcpts = csd.mMm.getAllRecipients();
            willNotify = rcpts != null && rcpts.length > 0;
        } catch (MessagingException e) {
            throw ServiceException.FAILURE("Checking recipients of outgoing msg ", e);
        }
    }
    // Validate the addresses first.
    if (!csd.mInvite.isCancel() && !forceSend && willNotify) {
        try {
            MailUtil.validateRcptAddresses(JMSession.getSmtpSession(mbox.getAccount()), csd.mMm.getAllRecipients());
        } catch (MessagingException mex) {
            if (mex instanceof SendFailedException) {
                SendFailedException sfex = (SendFailedException) mex;
                throw MailServiceException.SEND_ABORTED_ADDRESS_FAILURE("invalid addresses", sfex, sfex.getInvalidAddresses(), sfex.getValidUnsentAddresses());
            }
        }
    }
    AddInviteData aid = null;
    File tempMmFile = null;
    boolean queued = false;
    try {
        if (willNotify) {
            // Write out the MimeMessage to a temp file and create a new MimeMessage from the file.
            // If we don't do this, we get into trouble during modify appointment call.  If the blob
            // is bigger than the streaming threshold (e.g. appointment has a big attachment), the
            // MimeMessage object is attached to the current blob file.  But the Mailbox.addInvite()
            // call below updates the blob to a new mod_content (hence new path).  The attached blob
            // thus having been deleted, the MainSender.sendMimeMessage() call that follows will attempt
            // to read from a non-existent file and fail.  We can avoid this situation by writing the
            // to-be-emailed mime message to a temp file, thus detaching it from the appointment's
            // current blob file.  This is inefficient, but safe.
            OutputStream os = null;
            InputStream is = null;
            try {
                tempMmFile = File.createTempFile("zcal", "tmp");
                os = new FileOutputStream(tempMmFile);
                csd.mMm.writeTo(os);
                ByteUtil.closeStream(os);
                os = null;
                is = new ZSharedFileInputStream(tempMmFile);
                csd.mMm = new FixedMimeMessage(JMSession.getSmtpSession(acct), is);
            } catch (IOException e) {
                if (tempMmFile != null)
                    tempMmFile.delete();
                throw ServiceException.FAILURE("error creating calendar message content", e);
            } catch (MessagingException e) {
                if (tempMmFile != null)
                    tempMmFile.delete();
                throw ServiceException.FAILURE("error creating calendar message content", e);
            } finally {
                ByteUtil.closeStream(os);
                ByteUtil.closeStream(is);
            }
        }
        // because email send will delete uploaded attachments as a side-effect.
        if (updateOwnAppointment) {
            aid = mbox.addInvite(octxt, csd.mInvite, apptFolderId, pm, updatePrevFolders);
        }
        // Next, notify any attendees.
        if (willNotify) {
            MailSendQueueEntry entry = new MailSendQueueEntry(octxt, mbox, csd, tempMmFile);
            sendQueue.add(entry);
            queued = true;
        }
    } finally {
        // Delete the temp file if it wasn't queued.
        if (tempMmFile != null && !queued) {
            tempMmFile.delete();
        }
    }
    if (updateOwnAppointment && response != null && aid != null) {
        csd.mAddInvData = aid;
        ItemIdFormatter ifmt = new ItemIdFormatter(zsc);
        String id = ifmt.formatItemId(aid.calItemId);
        response.addAttribute(MailConstants.A_CAL_ID, id);
        if (csd.mInvite.isEvent())
            // for backward compat
            response.addAttribute(MailConstants.A_APPT_ID_DEPRECATE_ME, id);
        response.addAttribute(MailConstants.A_CAL_INV_ID, ifmt.formatItemId(aid.calItemId, aid.invId));
        if (Invite.isOrganizerMethod(csd.mInvite.getMethod())) {
            response.addAttribute(MailConstants.A_MODIFIED_SEQUENCE, aid.modSeq);
            response.addAttribute(MailConstants.A_REVISION, aid.rev);
        }
    }
    return response;
}
Also used : InternetAddress(javax.mail.internet.InternetAddress) SendFailedException(javax.mail.SendFailedException) Address(javax.mail.Address) InternetAddress(javax.mail.internet.InternetAddress) MessagingException(javax.mail.MessagingException) ItemIdFormatter(com.zimbra.cs.service.util.ItemIdFormatter) ParsedMessage(com.zimbra.cs.mime.ParsedMessage) AddInviteData(com.zimbra.cs.mailbox.Mailbox.AddInviteData) ZSharedFileInputStream(com.zimbra.common.zmime.ZSharedFileInputStream) InputStream(java.io.InputStream) OutputStream(java.io.OutputStream) FileOutputStream(java.io.FileOutputStream) FixedMimeMessage(com.zimbra.cs.mime.Mime.FixedMimeMessage) IOException(java.io.IOException) ZSharedFileInputStream(com.zimbra.common.zmime.ZSharedFileInputStream) FileOutputStream(java.io.FileOutputStream) File(java.io.File)

Example 19 with SendFailedException

use of javax.mail.SendFailedException in project zm-mailbox by Zimbra.

the class SmtpTransportTest method mailFromError.

@Test(timeout = 3000)
public void mailFromError() throws Exception {
    server = MockTcpServer.scenario().sendLine("220 test ready").recvLine().sendLine("250 OK").recvLine().sendLine("451 error").recvLine().build().start(PORT);
    Session session = JMSession.getSession();
    Transport transport = session.getTransport("smtp");
    transport.connect("localhost", PORT, null, null);
    String raw = "From: sender@zimbra.com\nTo: rcpt@zimbra.com\n" + "Subject: test\n\ntest";
    MimeMessage msg = new ZMimeMessage(session, new SharedByteArrayInputStream(raw.getBytes(Charsets.ISO_8859_1)));
    try {
        transport.sendMessage(msg, msg.getAllRecipients());
        Assert.fail();
    } catch (SendFailedException e) {
        Assert.assertEquals(0, e.getValidSentAddresses().length);
        Assert.assertEquals(0, e.getValidUnsentAddresses().length);
        Assert.assertEquals(0, e.getInvalidAddresses().length);
    } finally {
        transport.close();
    }
    server.shutdown(1000);
    Assert.assertEquals("EHLO localhost\r\n", server.replay());
    Assert.assertEquals("MAIL FROM:<sender@zimbra.com>\r\n", server.replay());
    Assert.assertEquals("QUIT\r\n", server.replay());
    Assert.assertNull(server.replay());
}
Also used : SendFailedException(javax.mail.SendFailedException) ZMimeMessage(com.zimbra.common.zmime.ZMimeMessage) ZMimeMessage(com.zimbra.common.zmime.ZMimeMessage) MimeMessage(javax.mail.internet.MimeMessage) Transport(javax.mail.Transport) JMSession(com.zimbra.cs.util.JMSession) Session(javax.mail.Session) SharedByteArrayInputStream(javax.mail.util.SharedByteArrayInputStream) Test(org.junit.Test)

Example 20 with SendFailedException

use of javax.mail.SendFailedException in project zm-mailbox by Zimbra.

the class SmtpTransportTest method sendPartially.

@Test(timeout = 3000)
public void sendPartially() throws Exception {
    server = MockTcpServer.scenario().sendLine("220 test ready").recvLine().sendLine("250 OK").recvLine().sendLine("250 OK").recvLine().sendLine("250 OK").recvLine().sendLine("550 not found").recvLine().sendLine("550 not found").recvLine().sendLine("354 OK").swallowUntil("\r\n.\r\n").sendLine("250 OK").recvLine().sendLine("221 bye").build().start(PORT);
    Session session = JMSession.getSession();
    session.getProperties().setProperty("mail.smtp.sendpartial", "true");
    Transport transport = session.getTransport("smtp");
    transport.connect("localhost", PORT, null, null);
    String raw = "From: sender@zimbra.com\n" + "To: rcpt1@zimbra.com, rcpt2@zimbra.com, rcpt3@zimbra.com\nSubject: test\n\ntest";
    MimeMessage msg = new ZMimeMessage(session, new SharedByteArrayInputStream(raw.getBytes(Charsets.ISO_8859_1)));
    try {
        transport.sendMessage(msg, msg.getAllRecipients());
    } catch (SendFailedException e) {
        Assert.assertEquals(1, e.getValidSentAddresses().length);
        Assert.assertEquals(0, e.getValidUnsentAddresses().length);
        Assert.assertEquals(2, e.getInvalidAddresses().length);
    } finally {
        transport.close();
    }
    server.shutdown(1000);
    Assert.assertEquals("EHLO localhost\r\n", server.replay());
    Assert.assertEquals("MAIL FROM:<sender@zimbra.com>\r\n", server.replay());
    Assert.assertEquals("RCPT TO:<rcpt1@zimbra.com>\r\n", server.replay());
    Assert.assertEquals("RCPT TO:<rcpt2@zimbra.com>\r\n", server.replay());
    Assert.assertEquals("RCPT TO:<rcpt3@zimbra.com>\r\n", server.replay());
    Assert.assertEquals("DATA\r\n", server.replay());
    Assert.assertEquals("QUIT\r\n", server.replay());
    Assert.assertNull(server.replay());
}
Also used : SendFailedException(javax.mail.SendFailedException) ZMimeMessage(com.zimbra.common.zmime.ZMimeMessage) ZMimeMessage(com.zimbra.common.zmime.ZMimeMessage) MimeMessage(javax.mail.internet.MimeMessage) Transport(javax.mail.Transport) JMSession(com.zimbra.cs.util.JMSession) Session(javax.mail.Session) SharedByteArrayInputStream(javax.mail.util.SharedByteArrayInputStream) Test(org.junit.Test)

Aggregations

SendFailedException (javax.mail.SendFailedException)23 MimeMessage (javax.mail.internet.MimeMessage)15 Session (javax.mail.Session)14 MessagingException (javax.mail.MessagingException)13 Transport (javax.mail.Transport)11 InternetAddress (javax.mail.internet.InternetAddress)11 IOException (java.io.IOException)9 MimeBodyPart (javax.mail.internet.MimeBodyPart)8 MimeMultipart (javax.mail.internet.MimeMultipart)8 Properties (java.util.Properties)7 ZMimeMessage (com.zimbra.common.zmime.ZMimeMessage)6 JMSession (com.zimbra.cs.util.JMSession)5 Date (java.util.Date)5 DataHandler (javax.activation.DataHandler)5 Address (javax.mail.Address)5 SharedByteArrayInputStream (javax.mail.util.SharedByteArrayInputStream)5 Test (org.junit.Test)4 SMTPMessage (com.sun.mail.smtp.SMTPMessage)3 File (java.io.File)3 OutputStream (java.io.OutputStream)3