JAMES-1877 Extract delivery to single server to MailDelivrer
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/f567a5a5 Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/f567a5a5 Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/f567a5a5 Branch: refs/heads/master Commit: f567a5a5606aceb53b4bf02beb9384f0d62b31a7 Parents: a0ca1bf Author: Benoit Tellier <btell...@linagora.com> Authored: Fri Dec 2 10:20:51 2016 +0700 Committer: Benoit Tellier <btell...@linagora.com> Committed: Tue Jan 10 15:12:51 2017 +0700 ---------------------------------------------------------------------- .../remoteDelivery/DeliveryRunnable.java | 126 ++-------------- .../remoteDelivery/MailDelivrerToHost.java | 142 +++++++++++++++++++ 2 files changed, 155 insertions(+), 113 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/f567a5a5/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 d62f6f6..37ae531 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 @@ -20,20 +20,16 @@ package org.apache.james.transport.mailets.remoteDelivery; import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.Iterator; -import java.util.Properties; import java.util.concurrent.TimeUnit; import javax.mail.Address; import javax.mail.MessagingException; import javax.mail.SendFailedException; -import javax.mail.Session; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import javax.mail.internet.ParseException; @@ -51,24 +47,21 @@ 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") public class DeliveryRunnable implements Runnable { - public static final String BIT_MIME_8 = "8BITMIME"; private final MailQueue queue; private final RemoteDeliveryConfiguration configuration; private final DNSService dnsServer; private final Metric outgoingMailsMetric; private final Logger logger; private final Bouncer bouncer; + private final MailDelivrerToHost mailDelivrerToHost; private final VolatileIsDestroyed volatileIsDestroyed; private final MessageComposer messageComposer; - private final Converter7Bit converter7Bit; - public DeliveryRunnable(MailQueue queue, RemoteDeliveryConfiguration configuration, DNSService dnsServer, Metric outgoingMailsMetric, Logger logger, MailetContext mailetContext, VolatileIsDestroyed volatileIsDestroyed) { + public DeliveryRunnable(MailQueue queue, RemoteDeliveryConfiguration configuration, DNSService dnsServer, Metric outgoingMailsMetric, + Logger logger, MailetContext mailetContext, VolatileIsDestroyed volatileIsDestroyed) { this.queue = queue; this.configuration = configuration; this.dnsServer = dnsServer; @@ -76,8 +69,8 @@ public class DeliveryRunnable implements Runnable { this.logger = logger; this.volatileIsDestroyed = volatileIsDestroyed; this.messageComposer = new MessageComposer(configuration); - this.converter7Bit = new Converter7Bit(mailetContext); this.bouncer = new Bouncer(configuration, messageComposer, mailetContext, logger); + this.mailDelivrerToHost = new MailDelivrerToHost(configuration, mailetContext, logger); } /** @@ -86,7 +79,6 @@ public class DeliveryRunnable implements Runnable { */ @Override public void run() { - final Session session = obtainSession(configuration.createFinalJavaxProperties()); try { while (!Thread.interrupted() && !volatileIsDestroyed.isDestroyed()) { try { @@ -100,7 +92,7 @@ public class DeliveryRunnable implements Runnable { if (configuration.isDebug()) { logger.debug(Thread.currentThread().getName() + " will process mail " + mail.getName()); } - attemptDelivery(session, mail); + attemptDelivery(mail); LifecycleUtil.dispose(mail); mail = null; queueItem.done(true); @@ -126,8 +118,8 @@ public class DeliveryRunnable implements Runnable { } } - private void attemptDelivery(Session session, Mail mail) throws MailQueue.MailQueueException { - ExecutionResult executionResult = deliver(mail, session); + private void attemptDelivery(Mail mail) throws MailQueue.MailQueueException { + ExecutionResult executionResult = deliver(mail); switch (executionResult.getExecutionState()) { case SUCCESS: outgoingMailsMetric.increment(); @@ -182,9 +174,9 @@ public class DeliveryRunnable implements Runnable { * @return boolean Whether the delivery was successful and the message can * be deleted */ - private ExecutionResult deliver(Mail mail, Session session) { + private ExecutionResult deliver(Mail mail) { try { - return tryDeliver(mail, session); + return tryDeliver(mail); } catch (SendFailedException sfe) { return handleSenderFailedException(mail, sfe); } catch (MessagingException ex) { @@ -210,7 +202,7 @@ public class DeliveryRunnable implements Runnable { } } - private ExecutionResult tryDeliver(Mail mail, Session session) throws MessagingException { + private ExecutionResult tryDeliver(Mail mail) throws MessagingException { if (mail.getRecipients().isEmpty()) { logger.info("No recipients specified... not sure how this could have happened."); return ExecutionResult.permanentFailure(new Exception("No recipients specified for " + mail.getName() + " sent by " + mail.getSender())); @@ -239,15 +231,15 @@ public class DeliveryRunnable implements Runnable { targetServers = getGatewaySMTPHostAddresses(configuration.getGatewayServer()); } - return doDeliver(mail, session, mail.getMessage(), convertToInetAddr(mail.getRecipients()), targetServers); + return doDeliver(mail, mail.getMessage(), convertToInetAddr(mail.getRecipients()), targetServers); } - private ExecutionResult doDeliver(Mail mail, Session session, MimeMessage message, InternetAddress[] addr, Iterator<HostAddress> targetServers) throws MessagingException { + private ExecutionResult doDeliver(Mail mail, MimeMessage message, InternetAddress[] addr, Iterator<HostAddress> targetServers) throws MessagingException { MessagingException lastError = null; while (targetServers.hasNext()) { try { - if (tryDeliveryToHost(mail, session, message, addr, targetServers.next())) { + if (mailDelivrerToHost.tryDeliveryToHost(mail, message, addr, targetServers.next())) { return ExecutionResult.success(); } } catch (SendFailedException sfe) { @@ -273,39 +265,6 @@ public class DeliveryRunnable implements Runnable { return ExecutionResult.temporaryFailure(); } - private boolean tryDeliveryToHost(Mail mail, Session session, MimeMessage message, InternetAddress[] addr, HostAddress outgoingMailServer) throws MessagingException { - 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()) ); - connect(outgoingMailServer, transport); - transport.sendMessage(adaptToTransport(message, transport), addr); - logger.debug("Mail (" + mail.getName() + ") sent successfully to " + outgoingMailServer.getHostName() + - " at " + outgoingMailServer.getHost() + " from " + props.get("mail.smtp.from") + " for " + mail.getRecipients()); - return true; - } finally { - closeTransport(mail, outgoingMailServer, transport); - } - } - 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()); @@ -468,61 +427,6 @@ public class DeliveryRunnable implements Runnable { return addr; } - private MimeMessage adaptToTransport(MimeMessage message, SMTPTransport transport) throws MessagingException { - // if the transport is a SMTPTransport (from sun) some - // performance enhancement can be done. - if (transport.getClass().getName().endsWith(".SMTPTransport")) { - // if the message is alredy 8bit or binary and the server doesn't support the 8bit extension it has - // to be converted to 7bit. Javamail api doesn't perform - // that conversion, but it is required to be a rfc-compliant smtp server. - - // Temporarily disabled. See JAMES-638 - if (!transport.supportsExtension(BIT_MIME_8)) { - try { - converter7Bit.convertTo7Bit(message); - } catch (IOException e) { - // An error has occured during the 7bit conversion. - // The error is logged and the message is sent anyway. - - logger.error("Error during the conversion to 7 bit.", e); - } - } - } else { - // If the transport is not the one developed by Sun we are not sure of how it - // handles the 8 bit mime stuff, so I convert the message to 7bit. - try { - converter7Bit.convertTo7Bit(message); - } catch (IOException e) { - logger.error("Error during the conversion to 7 bit.", e); - } - } - return message; - } - - private void closeTransport(Mail mail, HostAddress outgoingMailServer, SMTPTransport transport) { - if (transport != null) { - try { - // James-899: transport.close() sends QUIT to the server; if that fails - // (e.g. because the server has already closed the connection) the message - // should be considered to be delivered because the error happened outside - // of the mail transaction (MAIL, RCPT, DATA). - transport.close(); - } catch (MessagingException e) { - logger.error("Warning: could not close the SMTP transport after sending mail (" + mail.getName() + ") to " + outgoingMailServer.getHostName() + " at " + outgoingMailServer.getHost() + " for " + mail.getRecipients() + "; probably the server has already closed the " - + "connection. Message is considered to be delivered. Exception: " + e.getMessage()); - } - transport = null; - } - } - - private void connect(HostAddress outgoingMailServer, SMTPTransport transport) throws MessagingException { - if (configuration.getAuthUser() != null) { - transport.connect(outgoingMailServer.getHostName(), configuration.getAuthUser(), configuration.getAuthPass()); - } else { - transport.connect(); - } - } - private ExecutionResult handleTemporaryResolutionException(Mail mail, String host) { ExecutionResult executionResult = ExecutionResult.temporaryFailure(new MessagingException("Temporary problem looking " + "up mail server for host: " + host + ". I cannot determine where to send this message.")); @@ -548,10 +452,6 @@ public class DeliveryRunnable implements Runnable { } } - protected Session obtainSession(Properties props) { - return Session.getInstance(props); - } - private long getNextDelay(int retry_count) { if (retry_count > configuration.getDelayTimes().size()) { return Delay.DEFAULT_DELAY_TIME; http://git-wip-us.apache.org/repos/asf/james-project/blob/f567a5a5/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerToHost.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerToHost.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerToHost.java new file mode 100644 index 0000000..46bd8f9 --- /dev/null +++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/MailDelivrerToHost.java @@ -0,0 +1,142 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you under the Apache License, Version 2.0 (the * + * "License"); you may not use this file except in compliance * + * with the License. You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ****************************************************************/ + +package org.apache.james.transport.mailets.remoteDelivery; + +import java.io.IOException; +import java.util.Properties; + +import javax.mail.MessagingException; +import javax.mail.Session; +import javax.mail.internet.InternetAddress; +import javax.mail.internet.MimeMessage; + +import org.apache.mailet.HostAddress; +import org.apache.mailet.Mail; +import org.apache.mailet.MailetContext; +import org.slf4j.Logger; + +import com.sun.mail.smtp.SMTPTransport; + +@SuppressWarnings("deprecation") +public class MailDelivrerToHost { + public static final String BIT_MIME_8 = "8BITMIME"; + + private final RemoteDeliveryConfiguration configuration; + private final Converter7Bit converter7Bit; + private final Session session; + private final Logger logger; + + public MailDelivrerToHost(RemoteDeliveryConfiguration remoteDeliveryConfiguration, MailetContext mailetContext, Logger logger) { + this.configuration = remoteDeliveryConfiguration; + this.converter7Bit = new Converter7Bit(mailetContext); + this.session = Session.getInstance(configuration.createFinalJavaxProperties()); + this.logger = logger; + } + + public boolean tryDeliveryToHost(Mail mail, MimeMessage message, InternetAddress[] addr, HostAddress outgoingMailServer) throws MessagingException { + 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()) ); + connect(outgoingMailServer, transport); + transport.sendMessage(adaptToTransport(message, transport), addr); + logger.debug("Mail (" + mail.getName() + ") sent successfully to " + outgoingMailServer.getHostName() + + " at " + outgoingMailServer.getHost() + " from " + props.get("mail.smtp.from") + " for " + mail.getRecipients()); + return true; + } finally { + closeTransport(mail, outgoingMailServer, transport); + } + } + + private void connect(HostAddress outgoingMailServer, SMTPTransport transport) throws MessagingException { + if (configuration.getAuthUser() != null) { + transport.connect(outgoingMailServer.getHostName(), configuration.getAuthUser(), configuration.getAuthPass()); + } else { + transport.connect(); + } + } + + private MimeMessage adaptToTransport(MimeMessage message, SMTPTransport transport) throws MessagingException { + // if the transport is a SMTPTransport (from sun) some + // performance enhancement can be done. + if (transport.getClass().getName().endsWith(".SMTPTransport")) { + // if the message is alredy 8bit or binary and the server doesn't support the 8bit extension it has + // to be converted to 7bit. Javamail api doesn't perform + // that conversion, but it is required to be a rfc-compliant smtp server. + + // Temporarily disabled. See JAMES-638 + if (!transport.supportsExtension(BIT_MIME_8)) { + try { + converter7Bit.convertTo7Bit(message); + } catch (IOException e) { + // An error has occured during the 7bit conversion. + // The error is logged and the message is sent anyway. + + logger.error("Error during the conversion to 7 bit.", e); + } + } + } else { + // If the transport is not the one developed by Sun we are not sure of how it + // handles the 8 bit mime stuff, so I convert the message to 7bit. + try { + converter7Bit.convertTo7Bit(message); + } catch (IOException e) { + logger.error("Error during the conversion to 7 bit.", e); + } + } + return message; + } + + private void closeTransport(Mail mail, HostAddress outgoingMailServer, SMTPTransport transport) { + if (transport != null) { + try { + // James-899: transport.close() sends QUIT to the server; if that fails + // (e.g. because the server has already closed the connection) the message + // should be considered to be delivered because the error happened outside + // of the mail transaction (MAIL, RCPT, DATA). + transport.close(); + } catch (MessagingException e) { + logger.error("Warning: could not close the SMTP transport after sending mail (" + mail.getName() + ") to " + outgoingMailServer.getHostName() + " at " + outgoingMailServer.getHost() + " for " + mail.getRecipients() + "; probably the server has already closed the " + + "connection. Message is considered to be delivered. Exception: " + e.getMessage()); + } + transport = null; + } + } + + +} --------------------------------------------------------------------- To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org For additional commands, e-mail: server-dev-h...@james.apache.org