JAMES-1877 Finish flatten DeliveryRunnable
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/3b02d3f3 Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/3b02d3f3 Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/3b02d3f3 Branch: refs/heads/master Commit: 3b02d3f32f7d69593593acdb7c6a2ea4f7bcd386 Parents: 5742cbf Author: Benoit Tellier <btell...@linagora.com> Authored: Thu Dec 1 15:46:40 2016 +0700 Committer: Benoit Tellier <btell...@linagora.com> Committed: Tue Jan 10 15:12:49 2017 +0700 ---------------------------------------------------------------------- .../remoteDelivery/DeliveryRunnable.java | 282 ++++++++++--------- 1 file changed, 144 insertions(+), 138 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/3b02d3f3/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java index c917f19..9c31696 100644 --- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java +++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DeliveryRunnable.java @@ -53,6 +53,7 @@ import org.apache.mailet.MailAddress; import org.apache.mailet.MailetContext; import org.slf4j.Logger; +import com.google.common.base.Optional; import com.sun.mail.smtp.SMTPTransport; @SuppressWarnings("deprecation") @@ -167,17 +168,14 @@ public class DeliveryRunnable implements Runnable { */ private boolean deliver(Mail mail, Session session) { try { - Boolean host = tryDeliver(mail, session); - if (host != null) { - return host; - } + return Optional.fromNullable(tryDeliver(mail, session)) + .or(failMessage(mail, new MessagingException("No mail server(s) available at this time."), false)); /* * If we get here, we've exhausted the loop of servers without sending * the message or throwing an exception. One case where this might * happen is if we get a MessagingException on each transport.connect(), * e.g., if there is only one server and we get a connect exception. */ - return failMessage(mail, new MessagingException("No mail server(s) available at this time."), false); } catch (SendFailedException sfe) { return handleSenderFailedException(mail, sfe); } catch (MessagingException ex) { @@ -197,6 +195,124 @@ public class DeliveryRunnable implements Runnable { } } + private Boolean tryDeliver(Mail mail, Session session) throws MessagingException { + if (mail.getRecipients().isEmpty()) { + logger.info("No recipients specified... not sure how this could have happened."); + return true; + } + if (configuration.isDebug()) { + logger.debug("Attempting to deliver " + mail.getName()); + } + + // Figure out which servers to try to send to. This collection + // will hold all the possible target servers + Iterator<HostAddress> targetServers; + if (configuration.getGatewayServer().isEmpty()) { + MailAddress rcpt = mail.getRecipients().iterator().next(); + String host = rcpt.getDomain(); + + // Lookup the possible targets + try { + targetServers = new MXHostAddressIterator(dnsServer.findMXRecords(host).iterator(), dnsServer, false, logger); + } catch (TemporaryResolutionException e) { + return handleTemporaryResolutionException(mail, host); + } + if (!targetServers.hasNext()) { + return handleNoTargetServer(mail, host); + } + } else { + targetServers = getGatewaySMTPHostAddresses(configuration.getGatewayServer()); + } + + return doDeliver(mail, session, mail.getMessage(), convertToInetAddr(mail.getRecipients()), targetServers); + } + + private Boolean doDeliver(Mail mail, Session session, MimeMessage message, InternetAddress[] addr, Iterator<HostAddress> targetServers) throws MessagingException { + MessagingException lastError = null; + + while (targetServers.hasNext()) { + try { + if (tryDeliveryToHost(mail, session, message, addr, targetServers.next())) { + return true; + } + } catch (SendFailedException sfe) { + lastError = handleSendFailException(mail, sfe); + } catch (MessagingException me) { + lastError = handleMessagingException(mail, me); + } + } // end while + // If we encountered an exception while looping through, + // throw the last MessagingException we caught. We only + // do this if we were unable to send the message to any + // server. If sending eventually succeeded, we exit + // deliver() though the return at the end of the try + // block. + if (lastError != null) { + throw lastError; + } + return null; + } + + private boolean tryDeliveryToHost(Mail mail, Session session, MimeMessage message, InternetAddress[] addr, HostAddress outgoingMailServer) throws MessagingException { + boolean success = false; + Properties props = session.getProperties(); + if (mail.getSender() == null) { + props.put("mail.smtp.from", "<>"); + } else { + String sender = mail.getSender().toString(); + props.put("mail.smtp.from", sender); + } + logger.debug("Attempting delivery of " + mail.getName() + " to host " + outgoingMailServer.getHostName() + + " at " + outgoingMailServer.getHost() + " from " + props.get("mail.smtp.from")); + + // Many of these properties are only in later JavaMail versions + // "mail.smtp.ehlo" //default true + // "mail.smtp.auth" //default false + // "mail.smtp.dsn.ret" //default to nothing... appended as + // RET= after MAIL FROM line. + // "mail.smtp.dsn.notify" //default to nothing...appended as + // NOTIFY= after RCPT TO line. + + SMTPTransport transport = null; + try { + transport = (SMTPTransport) session.getTransport(outgoingMailServer); + transport.setLocalHost( props.getProperty("mail.smtp.localhost", configuration.getHeloNameProvider().getHeloName()) ); + if (!connect(outgoingMailServer, transport)) { + success = false; + } + transport.sendMessage(adaptToTransport(message, transport), addr); + success = true; + logger.debug("Mail (" + mail.getName() + ") sent successfully to " + outgoingMailServer.getHostName() + + " at " + outgoingMailServer.getHost() + " from " + props.get("mail.smtp.from") + " for " + mail.getRecipients()); + outgoingMailsMetric.increment(); + } finally { + closeTransport(mail, outgoingMailServer, transport); + } + return success; + } + + private MessagingException handleMessagingException(Mail mail, MessagingException me) throws MessagingException { + MessagingException lastError;// MessagingException are horribly difficult to figure out what actually happened. + logger.debug("Exception delivering message (" + mail.getName() + ") - " + me.getMessage()); + if ((me.getNextException() != null) && (me.getNextException() instanceof IOException)) { + // This is more than likely a temporary failure + + // If it's an IO exception with no nested exception, it's probably + // some socket or weird I/O related problem. + lastError = me; + } else { + // This was not a connection or I/O error particular to one + // SMTP server of an MX set. Instead, it is almost certainly + // a protocol level error. In this case we assume that this + // is an error we'd encounter with any of the SMTP servers + // associated with this MX record, and we pass the exception + // to the code in the outer block that determines its + // severity. + throw me; + } + return lastError; + } + private boolean handleSenderFailedException(Mail mail, SendFailedException sfe) { logSendFailedException(sfe); @@ -313,112 +429,40 @@ public class DeliveryRunnable implements Runnable { return deleteMessage; } - private Boolean tryDeliver(Mail mail, Session session) throws MessagingException { - if (mail.getRecipients().isEmpty()) { - logger.info("No recipients specified... not sure how this could have happened."); - return true; - } - if (configuration.isDebug()) { - logger.debug("Attempting to deliver " + mail.getName()); - } - - // Figure out which servers to try to send to. This collection - // will hold all the possible target servers - Iterator<HostAddress> targetServers; - if (configuration.getGatewayServer().isEmpty()) { - MailAddress rcpt = mail.getRecipients().iterator().next(); - String host = rcpt.getDomain(); + private MessagingException handleSendFailException(Mail mail, SendFailedException sfe) throws SendFailedException { + logSendFailedException(sfe); - // Lookup the possible targets - try { - targetServers = new MXHostAddressIterator(dnsServer.findMXRecords(host).iterator(), dnsServer, false, logger); - } catch (TemporaryResolutionException e) { - return handleTemporaryResolutionException(mail, host); + if (sfe.getValidSentAddresses() != null) { + Address[] validSent = sfe.getValidSentAddresses(); + if (validSent.length > 0) { + logger.debug( "Mail (" + mail.getName() + ") sent successfully for " + Arrays.asList(validSent)); } - if (!targetServers.hasNext()) { - return handleNoTargetServer(mail, host); - } - } else { - targetServers = getGatewaySMTPHostAddresses(configuration.getGatewayServer()); } - return doDeliver(mail, session, mail.getMessage(), convertToInetAddr(mail.getRecipients()), targetServers); - } - - private Boolean doDeliver(Mail mail, Session session, MimeMessage message, InternetAddress[] addr, Iterator<HostAddress> targetServers) throws MessagingException { - MessagingException lastError = null; - - while (targetServers.hasNext()) { - HostAddress outgoingMailServer = targetServers.next(); - try { - if (tryDeliveryToHost(mail, session, message, addr, outgoingMailServer)) { - return true; - } - } catch (SendFailedException sfe) { - logSendFailedException(sfe); - - if (sfe.getValidSentAddresses() != null) { - Address[] validSent = sfe.getValidSentAddresses(); - if (validSent.length > 0) { - logger.debug( "Mail (" + mail.getName() + ") sent successfully for " + Arrays.asList(validSent)); - } - } - /* * SMTPSendFailedException introduced in JavaMail 1.3.2, and * provides detailed protocol reply code for the operation */ - if (sfe.getClass().getName().endsWith(".SMTPSendFailedException")) { - try { - int returnCode = (Integer) invokeGetter(sfe, "getReturnCode"); - // if 5xx, terminate this delivery attempt by - // re-throwing the exception. - if (returnCode >= 500 && returnCode <= 599) - throw sfe; - } catch (ClassCastException cce) { - } catch (IllegalArgumentException iae) { - } - } - - if (sfe.getValidUnsentAddresses() != null && sfe.getValidUnsentAddresses().length > 0) { - if (configuration.isDebug()) - logger.debug("Send failed, " + sfe.getValidUnsentAddresses().length + " valid addresses remain, continuing with any other servers"); - lastError = sfe; - } else { - // There are no valid addresses left to send, so rethrow + if (sfe.getClass().getName().endsWith(".SMTPSendFailedException")) { + try { + int returnCode = (Integer) invokeGetter(sfe, "getReturnCode"); + // if 5xx, terminate this delivery attempt by + // re-throwing the exception. + if (returnCode >= 500 && returnCode <= 599) throw sfe; - } - } catch (MessagingException me) { - // MessagingException are horribly difficult to figure out what actually happened. - logger.debug("Exception delivering message (" + mail.getName() + ") - " + me.getMessage()); - if ((me.getNextException() != null) && (me.getNextException() instanceof IOException)) { - // This is more than likely a temporary failure - - // If it's an IO exception with no nested exception, it's probably - // some socket or weird I/O related problem. - lastError = me; - } else { - // This was not a connection or I/O error particular to one - // SMTP server of an MX set. Instead, it is almost certainly - // a protocol level error. In this case we assume that this - // is an error we'd encounter with any of the SMTP servers - // associated with this MX record, and we pass the exception - // to the code in the outer block that determines its - // severity. - throw me; - } + } catch (ClassCastException cce) { + } catch (IllegalArgumentException iae) { } - } // end while - // If we encountered an exception while looping through, - // throw the last MessagingException we caught. We only - // do this if we were unable to send the message to any - // server. If sending eventually succeeded, we exit - // deliver() though the return at the end of the try - // block. - if (lastError != null) { - throw lastError; } - return null; + + if (sfe.getValidUnsentAddresses() != null && sfe.getValidUnsentAddresses().length > 0) { + if (configuration.isDebug()) + logger.debug("Send failed, " + sfe.getValidUnsentAddresses().length + " valid addresses remain, continuing with any other servers"); + return sfe; + } else { + // There are no valid addresses left to send, so rethrow + throw sfe; + } } private InternetAddress[] convertToInetAddr(Collection<MailAddress> recipients) { @@ -431,44 +475,6 @@ public class DeliveryRunnable implements Runnable { return addr; } - private boolean tryDeliveryToHost(Mail mail, Session session, MimeMessage message, InternetAddress[] addr, HostAddress outgoingMailServer) throws MessagingException { - boolean success = false; - Properties props = session.getProperties(); - if (mail.getSender() == null) { - props.put("mail.smtp.from", "<>"); - } else { - String sender = mail.getSender().toString(); - props.put("mail.smtp.from", sender); - } - logger.debug("Attempting delivery of " + mail.getName() + " to host " + outgoingMailServer.getHostName() - + " at " + outgoingMailServer.getHost() + " from " + props.get("mail.smtp.from")); - - // Many of these properties are only in later JavaMail versions - // "mail.smtp.ehlo" //default true - // "mail.smtp.auth" //default false - // "mail.smtp.dsn.ret" //default to nothing... appended as - // RET= after MAIL FROM line. - // "mail.smtp.dsn.notify" //default to nothing...appended as - // NOTIFY= after RCPT TO line. - - SMTPTransport transport = null; - try { - transport = (SMTPTransport) session.getTransport(outgoingMailServer); - transport.setLocalHost( props.getProperty("mail.smtp.localhost", configuration.getHeloNameProvider().getHeloName()) ); - if (!connect(outgoingMailServer, transport)) { - success = false; - } - transport.sendMessage(adaptToTransport(message, transport), addr); - success = true; - logger.debug("Mail (" + mail.getName() + ") sent successfully to " + outgoingMailServer.getHostName() + - " at " + outgoingMailServer.getHost() + " from " + props.get("mail.smtp.from") + " for " + mail.getRecipients()); - outgoingMailsMetric.increment(); - } finally { - closeTransport(mail, outgoingMailServer, transport); - } - return success; - } - private MimeMessage adaptToTransport(MimeMessage message, SMTPTransport transport) throws MessagingException { // if the transport is a SMTPTransport (from sun) some // performance enhancement can be done. --------------------------------------------------------------------- To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org For additional commands, e-mail: server-dev-h...@james.apache.org