You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by ro...@apache.org on 2018/01/10 10:14:37 UTC
[37/53] [abbrv] james-project git commit: JAMES-2277 respect naming
conventions
http://git-wip-us.apache.org/repos/asf/james-project/blob/52c18ef6/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/DnsHelper.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/DnsHelper.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/DnsHelper.java
new file mode 100644
index 0000000..92cb4e6
--- /dev/null
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/DnsHelper.java
@@ -0,0 +1,49 @@
+/****************************************************************
+ * 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.remote.delivery;
+
+import java.util.Iterator;
+
+import org.apache.james.dnsservice.api.DNSService;
+import org.apache.james.dnsservice.api.TemporaryResolutionException;
+import org.apache.james.dnsservice.library.MXHostAddressIterator;
+import org.apache.mailet.HostAddress;
+
+@SuppressWarnings("deprecation")
+public class DnsHelper {
+
+ public static final boolean USE_SEVERAL_IP = false;
+ private final DNSService dnsServer;
+ private final RemoteDeliveryConfiguration configuration;
+
+ public DnsHelper(DNSService dnsServer, RemoteDeliveryConfiguration configuration) {
+ this.dnsServer = dnsServer;
+ this.configuration = configuration;
+ }
+
+ public Iterator<HostAddress> retrieveHostAddressIterator(String host) throws TemporaryResolutionException {
+ if (configuration.getGatewayServer().isEmpty()) {
+ return new MXHostAddressIterator(dnsServer.findMXRecords(host).iterator(), dnsServer, USE_SEVERAL_IP);
+ } else {
+ return new MXHostAddressIterator(configuration.getGatewayServer().iterator(), dnsServer, USE_SEVERAL_IP);
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/52c18ef6/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/EnhancedMessagingException.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/EnhancedMessagingException.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/EnhancedMessagingException.java
new file mode 100644
index 0000000..06f8a61
--- /dev/null
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/EnhancedMessagingException.java
@@ -0,0 +1,167 @@
+/****************************************************************
+ * 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.remote.delivery;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Optional;
+import java.util.function.Function;
+import javax.mail.MessagingException;
+import javax.mail.internet.InternetAddress;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+import com.sun.mail.smtp.SMTPAddressFailedException;
+import com.sun.mail.smtp.SMTPSendFailedException;
+import com.sun.mail.smtp.SMTPSenderFailedException;
+
+public class EnhancedMessagingException {
+
+ private static final Logger logger = LoggerFactory.getLogger(EnhancedMessagingException.class);
+
+ private final MessagingException messagingException;
+ private final Optional<Integer> returnCode;
+ private final Optional<Integer> nestedReturnCode;
+
+ public EnhancedMessagingException(MessagingException messagingException) {
+ this.messagingException = messagingException;
+ this.returnCode = computeReturnCode();
+ this.nestedReturnCode = computeNestedReturnCode();
+ }
+
+ public boolean hasReturnCode() {
+ return returnCode.isPresent();
+ }
+
+ public boolean hasNestedReturnCode() {
+ return nestedReturnCode.isPresent();
+ }
+
+ public boolean isServerError() {
+ return isServerError(returnCode) || isServerError(nestedReturnCode);
+ }
+
+ private boolean isServerError(Optional<Integer> returnCode) {
+ return (returnCode.isPresent()
+ && returnCode.get() >= 500
+ && returnCode.get() <= 599)
+ || messageIndicatesServerException();
+ }
+
+ private boolean messageIndicatesServerException() {
+ return Optional.ofNullable(messagingException.getMessage())
+ .map(startWith5())
+ .orElse(false);
+ }
+
+ private Function<String, Boolean> startWith5() {
+ return message -> message.startsWith("5");
+ }
+
+ private Optional<Integer> computeReturnCode() {
+ if (messagingException instanceof SMTPAddressFailedException) {
+ SMTPAddressFailedException addressFailedException = (SMTPAddressFailedException) this.messagingException;
+ return Optional.of(addressFailedException.getReturnCode());
+ }
+ if (messagingException instanceof SMTPSendFailedException) {
+ SMTPSendFailedException sendFailedException = (SMTPSendFailedException) this.messagingException;
+ return Optional.of(sendFailedException.getReturnCode());
+ }
+ if (messagingException instanceof SMTPSenderFailedException) {
+ SMTPSenderFailedException senderFailedException = (SMTPSenderFailedException) this.messagingException;
+ return Optional.of(senderFailedException.getReturnCode());
+ }
+ if (messagingException.getClass().getName().endsWith(".SMTPSendFailedException")
+ || messagingException.getClass().getName().endsWith(".SMTPAddressSucceededException")) {
+ try {
+ return Optional.of((Integer)invokeGetter(messagingException, "getReturnCode"));
+ } catch (ClassCastException | IllegalArgumentException | IllegalStateException e) {
+ logger.error("unexpected exception", e);
+ }
+ }
+ return Optional.empty();
+ }
+
+ public Optional<String> computeCommand() {
+ if (hasReturnCode()) {
+ try {
+ return Optional.of((String) invokeGetter(messagingException, "getCommand"));
+ } catch (ClassCastException | IllegalArgumentException | IllegalStateException e) {
+ logger.error("unexpected exception", e);
+ }
+ }
+ return Optional.empty();
+ }
+
+ public Optional<InternetAddress> computeAddress() {
+ if (hasReturnCode()) {
+ try {
+ return Optional.of((InternetAddress) invokeGetter(messagingException, "getAddress"));
+ } catch (ClassCastException | IllegalArgumentException | IllegalStateException e) {
+ logger.error("unexpected exception", e);
+ }
+ }
+ return Optional.empty();
+ }
+
+ public String computeAction() {
+ return messagingException.getClass().getName().endsWith(".SMTPAddressFailedException") ? "FAILED" : "SUCCEEDED";
+ }
+
+ public Optional<Integer> getReturnCode() {
+ return returnCode;
+ }
+
+ private Optional<Integer> computeNestedReturnCode() {
+ EnhancedMessagingException currentMessagingException = this;
+ while (true) {
+ Optional<Integer> returnCode = currentMessagingException.computeReturnCode();
+ if (returnCode.isPresent()) {
+ return returnCode;
+ }
+ if (currentMessagingException.hasNestedMessagingException()) {
+ currentMessagingException = currentMessagingException.getNestedMessagingException();
+ } else {
+ return Optional.empty();
+ }
+ }
+ }
+
+ private boolean hasNestedMessagingException() {
+ return messagingException.getNextException() != null
+ && messagingException.getNextException() instanceof MessagingException;
+ }
+
+ private EnhancedMessagingException getNestedMessagingException() {
+ Preconditions.checkState(hasNestedMessagingException());
+ return new EnhancedMessagingException((MessagingException) messagingException.getNextException());
+ }
+
+ private Object invokeGetter(Object target, String getter) {
+ try {
+ Method getAddress = target.getClass().getMethod(getter);
+ return getAddress.invoke(target);
+ } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+ return new IllegalStateException("Exception invoking " + getter + " on a " + target.getClass() + " object");
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/52c18ef6/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/ExecutionResult.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/ExecutionResult.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/ExecutionResult.java
new file mode 100644
index 0000000..3dae211
--- /dev/null
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/ExecutionResult.java
@@ -0,0 +1,93 @@
+/****************************************************************
+ * 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.remote.delivery;
+
+import java.util.Optional;
+
+import com.google.common.base.Objects;
+
+public class ExecutionResult {
+
+ public enum ExecutionState {
+ SUCCESS,
+ PERMANENT_FAILURE,
+ TEMPORARY_FAILURE
+ }
+
+ public static ExecutionResult success() {
+ return new ExecutionResult(ExecutionState.SUCCESS, Optional.empty());
+ }
+
+ public static ExecutionResult temporaryFailure(Exception e) {
+ return new ExecutionResult(ExecutionState.TEMPORARY_FAILURE, Optional.of(e));
+ }
+
+ public static ExecutionResult permanentFailure(Exception e) {
+ return new ExecutionResult(ExecutionState.PERMANENT_FAILURE, Optional.of(e));
+ }
+
+ public static ExecutionResult temporaryFailure() {
+ return new ExecutionResult(ExecutionState.TEMPORARY_FAILURE, Optional.empty());
+ }
+
+ public static ExecutionResult onFailure(boolean permanent, Exception exeption) {
+ if (permanent) {
+ return permanentFailure(exeption);
+ } else {
+ return temporaryFailure(exeption);
+ }
+ }
+
+ private final ExecutionState executionState;
+ private final Optional<Exception> exception;
+
+ public ExecutionResult(ExecutionState executionState, Optional<Exception> exception) {
+ this.executionState = executionState;
+ this.exception = exception;
+ }
+
+ public ExecutionState getExecutionState() {
+ return executionState;
+ }
+
+ public Optional<Exception> getException() {
+ return exception;
+ }
+
+ public boolean isPermanent() {
+ return executionState == ExecutionState.PERMANENT_FAILURE;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof ExecutionResult) {
+ ExecutionResult that = (ExecutionResult) o;
+ return Objects.equal(this.executionState, that.executionState)
+ && Objects.equal(this.exception, that.exception);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(executionState, exception);
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/james-project/blob/52c18ef6/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/HeloNameProvider.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/HeloNameProvider.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/HeloNameProvider.java
new file mode 100644
index 0000000..9042fbb
--- /dev/null
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/HeloNameProvider.java
@@ -0,0 +1,53 @@
+/****************************************************************
+ * 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.remote.delivery;
+
+import org.apache.james.domainlist.api.DomainList;
+import org.apache.james.domainlist.api.DomainListException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class HeloNameProvider {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(HeloNameProvider.class);
+ public static final String LOCALHOST = "localhost";
+
+ private final String heloName;
+ private final DomainList domainList;
+
+ public HeloNameProvider(String heloName, DomainList domainList) {
+ this.heloName = heloName;
+ this.domainList = domainList;
+ }
+
+ public String getHeloName() {
+ if (heloName == null) {
+ // TODO: Maybe we should better just lookup the hostname via dns
+ try {
+ return domainList.getDefaultDomain();
+ } catch (DomainListException e) {
+ LOGGER.warn("Unable to access DomainList", e);
+ return LOCALHOST;
+ }
+ } else {
+ return heloName;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/52c18ef6/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/InternetAddressConverter.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/InternetAddressConverter.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/InternetAddressConverter.java
new file mode 100644
index 0000000..c68b9ec
--- /dev/null
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/InternetAddressConverter.java
@@ -0,0 +1,39 @@
+/****************************************************************
+ * 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.remote.delivery;
+
+import java.util.Collection;
+import javax.mail.internet.InternetAddress;
+
+import org.apache.james.core.MailAddress;
+
+import com.google.common.base.Preconditions;
+
+
+public class InternetAddressConverter {
+
+ public static InternetAddress[] convert(Collection<MailAddress> recipients) {
+ Preconditions.checkNotNull(recipients);
+ return recipients.stream()
+ .map(MailAddress::toInternetAddress)
+ .toArray(InternetAddress[]::new);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/52c18ef6/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/MailDelivrer.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/MailDelivrer.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/MailDelivrer.java
new file mode 100644
index 0000000..9fbb4ba
--- /dev/null
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/MailDelivrer.java
@@ -0,0 +1,273 @@
+/****************************************************************
+ * 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.remote.delivery;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.mail.Address;
+import javax.mail.MessagingException;
+import javax.mail.SendFailedException;
+import javax.mail.internet.InternetAddress;
+
+import org.apache.james.core.MailAddress;
+import org.apache.james.dnsservice.api.DNSService;
+import org.apache.james.dnsservice.api.TemporaryResolutionException;
+import org.apache.mailet.HostAddress;
+import org.apache.mailet.Mail;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Iterables;
+
+@SuppressWarnings("deprecation")
+public class MailDelivrer {
+ private static final Logger LOGGER = LoggerFactory.getLogger(MailDelivrer.class);
+
+ private final RemoteDeliveryConfiguration configuration;
+ private final MailDelivrerToHost mailDelivrerToHost;
+ private final DnsHelper dnsHelper;
+ private final MessageComposer messageComposer;
+ private final Bouncer bouncer;
+
+ public MailDelivrer(RemoteDeliveryConfiguration configuration, MailDelivrerToHost mailDelivrerToHost, DNSService dnsServer, Bouncer bouncer) {
+ this(configuration, mailDelivrerToHost, new DnsHelper(dnsServer, configuration), bouncer);
+ }
+
+ @VisibleForTesting
+ MailDelivrer(RemoteDeliveryConfiguration configuration, MailDelivrerToHost mailDelivrerToHost, DnsHelper dnsHelper, Bouncer bouncer) {
+ this.configuration = configuration;
+ this.mailDelivrerToHost = mailDelivrerToHost;
+ this.dnsHelper = dnsHelper;
+ this.messageComposer = new MessageComposer(configuration);
+ this.bouncer = bouncer;
+ }
+
+ /**
+ * We can assume that the recipients of this message are all going to the same mail server. We will now rely on the
+ * DNS server to do DNS MX record lookup and try to deliver to the multiple mail servers. If it fails, it should
+ * throw an exception.
+ *
+ * @param mail org.apache.james.core.MailImpl
+ * @return boolean Whether the delivery was successful and the message can be deleted
+ */
+ public ExecutionResult deliver(Mail mail) {
+ try {
+ return tryDeliver(mail);
+ } catch (SendFailedException sfe) {
+ return handleSenderFailedException(mail, sfe);
+ } catch (MessagingException ex) {
+ // We check whether this is a 5xx error message, which indicates a permanent failure (like account doesn't exist
+ // or mailbox is full or domain is setup wrong). We fail permanently if this was a 5xx error
+ boolean isPermanent = new EnhancedMessagingException(ex).isServerError();
+ return logAndReturn(mail, ExecutionResult.onFailure(isPermanent, ex));
+ } catch (Exception ex) {
+ LOGGER.error("Generic exception = permanent failure: {}", ex.getMessage(), ex);
+ return logAndReturn(mail, ExecutionResult.permanentFailure(ex));
+ }
+ }
+
+ 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()));
+ }
+ if (configuration.isDebug()) {
+ LOGGER.debug("Attempting to deliver {}", mail.getName());
+ }
+
+ String host = retrieveTargetHostname(mail);
+ try {
+ // Figure out which servers to try to send to. This collection
+ // will hold all the possible target servers
+ Iterator<HostAddress> targetServers = dnsHelper.retrieveHostAddressIterator(host);
+ if (!targetServers.hasNext()) {
+ return handleNoTargetServer(mail, host);
+ }
+ return doDeliver(mail, InternetAddressConverter.convert(mail.getRecipients()), targetServers);
+ } catch (TemporaryResolutionException e) {
+ return logAndReturn(mail, ExecutionResult.temporaryFailure(new MessagingException("Temporary problem looking " +
+ "up mail server for host: " + host + ". I cannot determine where to send this message.")));
+ }
+ }
+
+ private String retrieveTargetHostname(Mail mail) {
+ Preconditions.checkArgument(!mail.getRecipients().isEmpty(), "Mail should have recipients to attempt delivery");
+ MailAddress rcpt = Iterables.getFirst(mail.getRecipients(), null);
+ return rcpt.getDomain();
+ }
+
+ private ExecutionResult doDeliver(Mail mail, InternetAddress[] addr, Iterator<HostAddress> targetServers) throws MessagingException {
+ MessagingException lastError = null;
+
+ while (targetServers.hasNext()) {
+ try {
+ return mailDelivrerToHost.tryDeliveryToHost(mail, addr, targetServers.next());
+ } catch (SendFailedException sfe) {
+ lastError = handleSendFailExceptionOnMxIteration(mail, sfe);
+ } catch (MessagingException me) {
+ lastError = handleMessagingException(mail, me);
+ if (configuration.isDebug()) {
+ LOGGER.debug(me.getMessage(), me.getCause());
+ } else {
+ LOGGER.info(me.getMessage());
+ }
+ }
+ }
+ // 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 ExecutionResult.temporaryFailure();
+ }
+
+ private MessagingException handleMessagingException(Mail mail, MessagingException me) throws MessagingException {
+ LOGGER.debug("Exception delivering message ({}) - {}", mail.getName(), me.getMessage());
+ if ((me.getNextException() != null) && (me.getNextException() instanceof IOException)) {
+ // If it's an IO exception with no nested exception, it's probably
+ // some socket or weird I/O related problem.
+ return 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;
+ }
+ }
+
+ @VisibleForTesting
+ ExecutionResult handleSenderFailedException(Mail mail, SendFailedException sfe) {
+ logSendFailedException(sfe);
+ EnhancedMessagingException enhancedMessagingException = new EnhancedMessagingException(sfe);
+ List<MailAddress> invalidAddresses = AddressesArrayToMailAddressListConverter.getAddressesAsMailAddress(sfe.getInvalidAddresses());
+ List<MailAddress> validUnsentAddresses = AddressesArrayToMailAddressListConverter.getAddressesAsMailAddress(sfe.getValidUnsentAddresses());
+ if (configuration.isDebug()) {
+ LOGGER.debug("Mail {} has initially recipients: {}", mail.getName(), mail.getRecipients());
+ if (!invalidAddresses.isEmpty()) {
+ LOGGER.debug("Invalid recipients: {}", invalidAddresses);
+ }
+ if (!validUnsentAddresses.isEmpty()) {
+ LOGGER.debug("Unsent recipients: {}", validUnsentAddresses);
+ }
+ }
+ if (!validUnsentAddresses.isEmpty()) {
+ if (!invalidAddresses.isEmpty()) {
+ mail.setRecipients(invalidAddresses);
+ bouncer.bounce(mail, sfe);
+ }
+ mail.setRecipients(validUnsentAddresses);
+ if (enhancedMessagingException.hasReturnCode()) {
+ boolean isPermanent = enhancedMessagingException.isServerError();
+ return logAndReturn(mail, ExecutionResult.onFailure(isPermanent, sfe));
+ } else {
+ return logAndReturn(mail, ExecutionResult.temporaryFailure(sfe));
+ }
+ }
+ if (!invalidAddresses.isEmpty()) {
+ mail.setRecipients(invalidAddresses);
+ return logAndReturn(mail, ExecutionResult.permanentFailure(sfe));
+ }
+
+ if (enhancedMessagingException.hasReturnCode() || enhancedMessagingException.hasNestedReturnCode()) {
+ if (enhancedMessagingException.isServerError()) {
+ return ExecutionResult.permanentFailure(sfe);
+ }
+ }
+ return ExecutionResult.temporaryFailure(sfe);
+ }
+
+ private ExecutionResult logAndReturn(Mail mail, ExecutionResult executionResult) {
+ LOGGER.debug(messageComposer.composeFailLogMessage(mail, executionResult));
+ return executionResult;
+ }
+
+ private MessagingException handleSendFailExceptionOnMxIteration(Mail mail, SendFailedException sfe) throws SendFailedException {
+ logSendFailedException(sfe);
+
+ if (sfe.getValidSentAddresses() != null) {
+ Address[] validSent = sfe.getValidSentAddresses();
+ if (validSent.length > 0) {
+ LOGGER.debug("Mail ({}) sent successfully for {}", mail.getName(), validSent);
+ }
+ }
+
+ EnhancedMessagingException enhancedMessagingException = new EnhancedMessagingException(sfe);
+ if (enhancedMessagingException.isServerError()) {
+ throw sfe;
+ }
+
+ final Address[] validUnsentAddresses = sfe.getValidUnsentAddresses();
+ if (validUnsentAddresses != null && validUnsentAddresses.length > 0) {
+ if (configuration.isDebug()) {
+ LOGGER.debug("Send failed, {} valid addresses remain, continuing with any other servers", (Object) validUnsentAddresses);
+ }
+ return sfe;
+ } else {
+ // There are no valid addresses left to send, so rethrow
+ throw sfe;
+ }
+ }
+
+ private ExecutionResult handleNoTargetServer(Mail mail, String host) {
+ LOGGER.info("No mail server found for: {}", host);
+ MessagingException messagingException = new MessagingException("There are no DNS entries for the hostname " + host + ". I cannot determine where to send this message.");
+ int retry = DeliveryRetriesHelper.retrieveRetries(mail);
+ if (retry >= configuration.getDnsProblemRetry()) {
+ return logAndReturn(mail, ExecutionResult.permanentFailure(messagingException));
+ } else {
+ return logAndReturn(mail, ExecutionResult.temporaryFailure(messagingException));
+ }
+ }
+
+ private void logSendFailedException(SendFailedException sfe) {
+ if (configuration.isDebug()) {
+ EnhancedMessagingException enhancedMessagingException = new EnhancedMessagingException(sfe);
+ if (enhancedMessagingException.hasReturnCode()) {
+ LOGGER.info("SMTP SEND FAILED: Command [{}] RetCode: [{}] Response[{}]", enhancedMessagingException.computeCommand(),
+ enhancedMessagingException.getReturnCode(), sfe.getMessage());
+ } else {
+ LOGGER.info("Send failed", sfe);
+ }
+ logLevels(sfe);
+ }
+ }
+
+ private void logLevels(MessagingException me) {
+ Exception ne;
+ while ((ne = me.getNextException()) != null && ne instanceof MessagingException) {
+ me = (MessagingException) ne;
+ EnhancedMessagingException enhancedMessagingException = new EnhancedMessagingException(me);
+ if (me.getClass().getName().endsWith(".SMTPAddressFailedException") || me.getClass().getName().endsWith(".SMTPAddressSucceededException")) {
+ LOGGER.debug("ADDRESS :[{}] Address:[{}] Command : [{}] RetCode[{}] Response [{}]",
+ enhancedMessagingException.computeAction(), me, enhancedMessagingException.computeAddress(),
+ enhancedMessagingException.computeCommand(), enhancedMessagingException.getReturnCode());
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/52c18ef6/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/MailDelivrerToHost.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/MailDelivrerToHost.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/MailDelivrerToHost.java
new file mode 100644
index 0000000..5be0f62
--- /dev/null
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/MailDelivrerToHost.java
@@ -0,0 +1,136 @@
+/****************************************************************
+ * 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.remote.delivery;
+
+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 org.slf4j.LoggerFactory;
+
+import com.sun.mail.smtp.SMTPTransport;
+
+@SuppressWarnings("deprecation")
+public class MailDelivrerToHost {
+ private static final Logger LOGGER = LoggerFactory.getLogger(MailDelivrerToHost.class);
+ public static final String BIT_MIME_8 = "8BITMIME";
+
+ private final RemoteDeliveryConfiguration configuration;
+ private final Converter7Bit converter7Bit;
+ private final Session session;
+
+ public MailDelivrerToHost(RemoteDeliveryConfiguration remoteDeliveryConfiguration, MailetContext mailetContext) {
+ this.configuration = remoteDeliveryConfiguration;
+ this.converter7Bit = new Converter7Bit(mailetContext);
+ this.session = Session.getInstance(configuration.createFinalJavaxProperties());
+ }
+
+ public ExecutionResult tryDeliveryToHost(Mail mail, InternetAddress[] addr, HostAddress outgoingMailServer) throws MessagingException {
+ Properties props = getPropertiesForMail(mail);
+ LOGGER.debug("Attempting delivery of {} to host {} at {} from {}",
+ mail.getName(), outgoingMailServer.getHostName(), outgoingMailServer.getHost(), 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(mail.getMessage(), transport), addr);
+ LOGGER.debug("Mail ({}) sent successfully to {} at {} from {} for {}", mail.getName(), outgoingMailServer.getHostName(),
+ outgoingMailServer.getHost(), props.get("mail.smtp.from"), mail.getRecipients());
+ } finally {
+ closeTransport(mail, outgoingMailServer, transport);
+ }
+ return ExecutionResult.success();
+ }
+
+ private Properties getPropertiesForMail(Mail mail) {
+ 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);
+ }
+ return props;
+ }
+
+ 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 (shouldAdapt(transport)) {
+ try {
+ converter7Bit.convertTo7Bit(message);
+ } catch (IOException e) {
+ LOGGER.error("Error during the conversion to 7 bit.", e);
+ }
+ }
+ return message;
+ }
+
+ private boolean shouldAdapt(SMTPTransport transport) {
+ // If the transport is a SMTPTransport (from sun) some performance enhancement can be done.
+ // 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.
+ return !transport.getClass().getName().endsWith(".SMTPTransport")
+ || !transport.supportsExtension(BIT_MIME_8);
+ // if the message is already 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.
+ }
+
+ 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 ({}) to {} at {} for {}; " +
+ "probably the server has already closed the connection. Message is considered to be delivered. Exception: {}",
+ mail.getName(), outgoingMailServer.getHostName(), outgoingMailServer.getHost(), mail.getRecipients(), e.getMessage());
+ }
+ transport = null;
+ }
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/52c18ef6/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/MessageComposer.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/MessageComposer.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/MessageComposer.java
new file mode 100644
index 0000000..2dfa0a9
--- /dev/null
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/MessageComposer.java
@@ -0,0 +1,141 @@
+/****************************************************************
+ * 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.remote.delivery;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import javax.mail.MessagingException;
+import javax.mail.SendFailedException;
+import javax.mail.internet.InternetAddress;
+
+import org.apache.mailet.Mail;
+
+public class MessageComposer {
+
+ private final RemoteDeliveryConfiguration configuration;
+
+ public MessageComposer(RemoteDeliveryConfiguration configuration) {
+ this.configuration = configuration;
+ }
+
+ /**
+ * Try to return a usefull logString created of the Exception which was
+ * given. Return null if nothing usefull could be done
+ *
+ * @param e The MessagingException to use
+ * @return logString
+ */
+ public String fromException(Exception e) {
+ if (e.getClass().getName().endsWith(".SMTPSendFailedException")) {
+ return "RemoteHost said: " + e.getMessage();
+ } else if (e instanceof SendFailedException) {
+ SendFailedException exception = (SendFailedException) e;
+
+ // No error
+ if (exception.getInvalidAddresses().length == 0 && exception.getValidUnsentAddresses().length == 0) {
+ return null;
+ }
+
+ Exception ex;
+ StringBuilder sb = new StringBuilder();
+ boolean smtpExFound = false;
+ sb.append("RemoteHost said:");
+
+ if (e instanceof MessagingException) {
+ while ((ex = ((MessagingException) e).getNextException()) != null && ex instanceof MessagingException) {
+ e = ex;
+ if (ex.getClass().getName().endsWith(".SMTPAddressFailedException")) {
+ try {
+ InternetAddress ia = (InternetAddress) invokeGetter(ex, "getAddress");
+ sb.append(" ( ").append(ia).append(" - [").append(ex.getMessage().replaceAll("\\n", "")).append("] )");
+ smtpExFound = true;
+ } catch (IllegalStateException ise) {
+ // Error invoking the getAddress method
+ } catch (ClassCastException cce) {
+ // The getAddress method returned something
+ // different than InternetAddress
+ }
+ }
+ }
+ }
+ if (!smtpExFound) {
+ boolean invalidAddr = false;
+ sb.append(" ( ");
+
+ if (exception.getInvalidAddresses().length > 0) {
+ sb.append(Arrays.toString(exception.getInvalidAddresses()));
+ invalidAddr = true;
+ }
+ if (exception.getValidUnsentAddresses().length > 0) {
+ if (invalidAddr) {
+ sb.append(" ");
+ }
+ sb.append(Arrays.toString(exception.getValidUnsentAddresses()));
+ }
+ sb.append(" - [");
+ sb.append(exception.getMessage().replaceAll("\\n", ""));
+ sb.append("] )");
+ }
+ return sb.toString();
+ }
+ return null;
+ }
+
+ public String composeFailLogMessage(Mail mail, ExecutionResult executionResult) {
+ StringWriter sout = new StringWriter();
+ PrintWriter out = new PrintWriter(sout, true);
+ out.print(permanentAsString(executionResult.isPermanent()) + " exception delivering mail (" + mail.getName()
+ + ")" + retrieveExceptionLog(executionResult.getException().orElse(null)) + ": ");
+ if (configuration.isDebug()) {
+ if (executionResult.getException().isPresent()) {
+ executionResult.getException().get().printStackTrace(out);
+ }
+ }
+ return sout.toString();
+ }
+
+ private String permanentAsString(boolean permanent) {
+ if (permanent) {
+ return "Permanent";
+ }
+ return "Temporary";
+ }
+
+ private String retrieveExceptionLog(Exception ex) {
+ String exceptionLog = fromException(ex);
+ if (exceptionLog != null) {
+ return ". " + exceptionLog;
+ }
+ return "";
+ }
+
+ private Object invokeGetter(Object target, String getter) {
+ try {
+ Method getAddress = target.getClass().getMethod(getter);
+ return getAddress.invoke(target);
+ } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+ return new IllegalStateException("Exception invoking " + getter + " on a " + target.getClass() + " object");
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/52c18ef6/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/RemoteDeliveryConfiguration.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/RemoteDeliveryConfiguration.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/RemoteDeliveryConfiguration.java
new file mode 100644
index 0000000..63f5451
--- /dev/null
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/RemoteDeliveryConfiguration.java
@@ -0,0 +1,320 @@
+/****************************************************************
+ * 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.remote.delivery;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+import java.util.Properties;
+
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.james.domainlist.api.DomainList;
+import org.apache.mailet.MailetConfig;
+import org.apache.mailet.base.MailetUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.github.steveash.guavate.Guavate;
+import com.google.common.base.Splitter;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+
+public class RemoteDeliveryConfiguration {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(RemoteDeliveryConfiguration.class);
+
+ public static final String DELIVERY_THREADS = "deliveryThreads";
+ public static final String USE_PRIORITY = "usePriority";
+ public static final String MAX_DNS_PROBLEM_RETRIES = "maxDnsProblemRetries";
+ public static final String HELO_NAME = "heloName";
+ public static final String JAVAX_PREFIX = "mail.";
+ public static final String BIND = "bind";
+ public static final String GATEWAY_PASSWORD = "gatewayPassword";
+ public static final String GATEWAY_USERNAME_COMPATIBILITY = "gatewayusername";
+ public static final String GATEWAY_USERNAME = "gatewayUsername";
+ public static final String GATEWAY_PORT = "gatewayPort";
+ public static final String GATEWAY = "gateway";
+ public static final String SSL_ENABLE = "sslEnable";
+ public static final String START_TLS = "startTLS";
+ public static final String BOUNCE_PROCESSOR = "bounceProcessor";
+ public static final String SENDPARTIAL = "sendpartial";
+ public static final String TIMEOUT = "timeout";
+ public static final String CONNECTIONTIMEOUT = "connectiontimeout";
+ public static final String OUTGOING = "outgoing";
+ public static final String MAX_RETRIES = "maxRetries";
+ public static final String DELAY_TIME = "delayTime";
+ public static final String DEBUG = "debug";
+ public static final int DEFAULT_SMTP_TIMEOUT = 180000;
+ public static final String DEFAULT_OUTGOING_QUEUE_NAME = "outgoing";
+ public static final int DEFAULT_CONNECTION_TIMEOUT = 60000;
+ public static final int DEFAULT_DNS_RETRY_PROBLEM = 0;
+ public static final int DEFAULT_MAX_RETRY = 5;
+ public static final String ADDRESS_PORT_SEPARATOR = ":";
+
+ private final boolean isDebug;
+ private final boolean usePriority;
+ private final boolean startTLS;
+ private final boolean isSSLEnable;
+ private final boolean isBindUsed;
+ private final boolean sendPartial;
+ private final int maxRetries;
+ private final long smtpTimeout;
+ private final int dnsProblemRetry;
+ private final int connectionTimeout;
+ private final int workersThreadCount;
+ private final List<Long> delayTimes;
+ private final HeloNameProvider heloNameProvider;
+ private final String outGoingQueueName;
+ private final String bindAddress;
+ private final String bounceProcessor;
+ private final Collection<String> gatewayServer;
+ private final String authUser;
+ private final String authPass;
+ private final Properties javaxAdditionalProperties;
+
+ public RemoteDeliveryConfiguration(MailetConfig mailetConfig, DomainList domainList) {
+ isDebug = MailetUtil.getInitParameter(mailetConfig, DEBUG).orElse(false);
+ startTLS = MailetUtil.getInitParameter(mailetConfig, START_TLS).orElse(false);
+ isSSLEnable = MailetUtil.getInitParameter(mailetConfig, SSL_ENABLE).orElse(false);
+ usePriority = MailetUtil.getInitParameter(mailetConfig, USE_PRIORITY).orElse(false);
+ sendPartial = MailetUtil.getInitParameter(mailetConfig, SENDPARTIAL).orElse(false);
+ outGoingQueueName = Optional.ofNullable(mailetConfig.getInitParameter(OUTGOING)).orElse(DEFAULT_OUTGOING_QUEUE_NAME);
+ bounceProcessor = mailetConfig.getInitParameter(BOUNCE_PROCESSOR);
+ bindAddress = mailetConfig.getInitParameter(BIND);
+
+ DelaysAndMaxRetry delaysAndMaxRetry = computeDelaysAndMaxRetry(mailetConfig);
+ maxRetries = delaysAndMaxRetry.getMaxRetries();
+ delayTimes = delaysAndMaxRetry.getExpandedDelays();
+ smtpTimeout = computeSmtpTimeout(mailetConfig);
+ connectionTimeout = computeConnectionTimeout(mailetConfig);
+ dnsProblemRetry = computeDnsProblemRetry(mailetConfig);
+ heloNameProvider = new HeloNameProvider(mailetConfig.getInitParameter(HELO_NAME), domainList);
+ workersThreadCount = Integer.valueOf(mailetConfig.getInitParameter(DELIVERY_THREADS));
+
+ String gatewayPort = mailetConfig.getInitParameter(GATEWAY_PORT);
+ String gateway = mailetConfig.getInitParameter(GATEWAY);
+ gatewayServer = computeGatewayServers(gatewayPort, gateway);
+ if (gateway != null) {
+ authUser = computeGatewayUser(mailetConfig);
+ authPass = mailetConfig.getInitParameter(GATEWAY_PASSWORD);
+ } else {
+ authUser = null;
+ authPass = null;
+ }
+ isBindUsed = bindAddress != null;
+ javaxAdditionalProperties = computeJavaxProperties(mailetConfig);
+ }
+
+ private Properties computeJavaxProperties(MailetConfig mailetConfig) {
+ Properties result = new Properties();
+ // deal with <mail.*> attributes, passing them to javamail
+ result.putAll(
+ ImmutableList.copyOf(mailetConfig.getInitParameterNames())
+ .stream()
+ .filter(propertyName -> propertyName.startsWith(JAVAX_PREFIX))
+ .map(propertyName -> Pair.of(propertyName, mailetConfig.getInitParameter(propertyName)))
+ .collect(Guavate.toImmutableMap(Pair::getKey, Pair::getValue)));
+ return result;
+ }
+
+ private int computeDnsProblemRetry(MailetConfig mailetConfig) {
+ String dnsRetry = mailetConfig.getInitParameter(MAX_DNS_PROBLEM_RETRIES);
+ if (!Strings.isNullOrEmpty(dnsRetry)) {
+ return Integer.valueOf(dnsRetry);
+ } else {
+ return DEFAULT_DNS_RETRY_PROBLEM;
+ }
+ }
+
+ private int computeConnectionTimeout(MailetConfig mailetConfig) {
+ try {
+ return Integer.valueOf(
+ Optional.ofNullable(mailetConfig.getInitParameter(CONNECTIONTIMEOUT))
+ .orElse(String.valueOf(DEFAULT_CONNECTION_TIMEOUT)));
+ } catch (Exception e) {
+ LOGGER.warn("Invalid timeout setting: {}", mailetConfig.getInitParameter(TIMEOUT));
+ return DEFAULT_CONNECTION_TIMEOUT;
+ }
+ }
+
+ private long computeSmtpTimeout(MailetConfig mailetConfig) {
+ try {
+ if (mailetConfig.getInitParameter(TIMEOUT) != null) {
+ return Integer.valueOf(mailetConfig.getInitParameter(TIMEOUT));
+ } else {
+ return DEFAULT_SMTP_TIMEOUT;
+ }
+ } catch (Exception e) {
+ LOGGER.warn("Invalid timeout setting: {}", mailetConfig.getInitParameter(TIMEOUT));
+ return DEFAULT_SMTP_TIMEOUT;
+ }
+ }
+
+ private DelaysAndMaxRetry computeDelaysAndMaxRetry(MailetConfig mailetConfig) {
+ try {
+ int intendedMaxRetries = Integer.valueOf(
+ Optional.ofNullable(mailetConfig.getInitParameter(MAX_RETRIES))
+ .orElse(String.valueOf(DEFAULT_MAX_RETRY)));
+ return DelaysAndMaxRetry.from(intendedMaxRetries, mailetConfig.getInitParameter(DELAY_TIME));
+ } catch (Exception e) {
+ LOGGER.warn("Invalid maxRetries setting: {}", mailetConfig.getInitParameter(MAX_RETRIES));
+ return DelaysAndMaxRetry.defaults();
+ }
+ }
+
+ private String computeGatewayUser(MailetConfig mailetConfig) {
+ // backward compatibility with 2.3.x
+ String user = mailetConfig.getInitParameter(GATEWAY_USERNAME);
+ if (user == null) {
+ return mailetConfig.getInitParameter(GATEWAY_USERNAME_COMPATIBILITY);
+ }
+ return user;
+ }
+
+ private List<String> computeGatewayServers(String gatewayPort, String gateway) {
+ if (gateway != null) {
+ ImmutableList.Builder<String> builder = ImmutableList.builder();
+ Iterable<String> gatewayParts = Splitter.on(',').split(gateway);
+ for (String gatewayPart : gatewayParts) {
+ builder.add(parsePart(gatewayPort, gatewayPart));
+ }
+ return builder.build();
+ } else {
+ return ImmutableList.of();
+ }
+ }
+
+ private String parsePart(String gatewayPort, String gatewayPart) {
+ String address = gatewayPart.trim();
+ if (!address.contains(ADDRESS_PORT_SEPARATOR) && gatewayPort != null) {
+ return address + ADDRESS_PORT_SEPARATOR + gatewayPort;
+ }
+ return address;
+ }
+
+ public Properties createFinalJavaxProperties() {
+ Properties props = new Properties();
+ props.put("mail.debug", "false");
+ // Reactivated: javamail 1.3.2 should no more have problems with "250 OK" messages
+ // (WAS "false": Prevents problems encountered with 250 OK Messages)
+ props.put("mail.smtp.ehlo", "true");
+ // By setting this property to true the transport is allowed to send 8 bit data to the server (if it supports
+ // the 8bitmime extension).
+ props.setProperty("mail.smtp.allow8bitmime", "true");
+ props.put("mail.smtp.timeout", String.valueOf(smtpTimeout));
+ props.put("mail.smtp.connectiontimeout", String.valueOf(connectionTimeout));
+ props.put("mail.smtp.sendpartial", String.valueOf(sendPartial));
+ props.put("mail.smtp.localhost", heloNameProvider.getHeloName());
+ props.put("mail.smtp.starttls.enable", String.valueOf(startTLS));
+ props.put("mail.smtp.ssl.enable", String.valueOf(isSSLEnable));
+ if (isBindUsed()) {
+ // undocumented JavaMail 1.2 feature, smtp transport will use
+ // our socket factory, which will also set the local address
+ props.put("mail.smtp.socketFactory.class", RemoteDeliverySocketFactory.class.getClass());
+ // Don't fallback to the standard socket factory on error, do throw an exception
+ props.put("mail.smtp.socketFactory.fallback", "false");
+ }
+ if (authUser != null) {
+ props.put("mail.smtp.auth", "true");
+ }
+ props.putAll(javaxAdditionalProperties);
+ return props;
+ }
+
+ public boolean isDebug() {
+ return isDebug;
+ }
+
+ public List<Long> getDelayTimes() {
+ return delayTimes;
+ }
+
+ public int getMaxRetries() {
+ return maxRetries;
+ }
+
+ public long getSmtpTimeout() {
+ return smtpTimeout;
+ }
+
+ public boolean isSendPartial() {
+ return sendPartial;
+ }
+
+ public int getConnectionTimeout() {
+ return connectionTimeout;
+ }
+
+ public int getWorkersThreadCount() {
+ return workersThreadCount;
+ }
+
+ public Collection<String> getGatewayServer() {
+ return gatewayServer;
+ }
+
+ public String getAuthUser() {
+ return authUser;
+ }
+
+ public String getAuthPass() {
+ return authPass;
+ }
+
+ public boolean isBindUsed() {
+ return isBindUsed;
+ }
+
+ public String getBounceProcessor() {
+ return bounceProcessor;
+ }
+
+ public boolean isUsePriority() {
+ return usePriority;
+ }
+
+ public boolean isStartTLS() {
+ return startTLS;
+ }
+
+ public boolean isSSLEnable() {
+ return isSSLEnable;
+ }
+
+ public HeloNameProvider getHeloNameProvider() {
+ return heloNameProvider;
+ }
+
+ public String getOutGoingQueueName() {
+ return outGoingQueueName;
+ }
+
+ public Properties getJavaxAdditionalProperties() {
+ return javaxAdditionalProperties;
+ }
+
+ public int getDnsProblemRetry() {
+ return dnsProblemRetry;
+ }
+
+ public String getBindAddress() {
+ return bindAddress;
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/52c18ef6/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/RemoteDeliverySocketFactory.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/RemoteDeliverySocketFactory.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/RemoteDeliverySocketFactory.java
new file mode 100644
index 0000000..60722a2
--- /dev/null
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/RemoteDeliverySocketFactory.java
@@ -0,0 +1,138 @@
+/****************************************************************
+ * 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.remote.delivery;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+
+import javax.net.SocketFactory;
+
+/**
+ * <p>
+ * It is used by RemoteDelivery in order to make possible to bind the client
+ * socket to a specific ip address.
+ * </p>
+ * <p>
+ * This is not a nice solution because the ip address must be shared by all
+ * RemoteDelivery instances. It would be better to modify JavaMail (current
+ * version 1.3) to support a corresonding property, e.g. mail.smtp.bindAdress.
+ * </p>
+ * <p>
+ * This used to not extend javax.net.SocketFactory descendant, because
+ * <ol>
+ * <li>
+ * it was not necessary because JavaMail 1.2 uses reflection when accessing this
+ * class;</li>
+ * <li>
+ * it was not desirable because it would require java 1.4.</li>
+ * </ol>
+ * </p>
+ * <p>
+ * But since James 2.3.0a1:
+ * <ol>
+ * <li>we require Java 1.4 so the dependency on SocketFactory is not really an
+ * issue;</li>
+ * <li>Javamail 1.4 cast the object returned by getDefault to SocketFactory and
+ * fails to create the socket if we don't extend SocketFactory.</li>
+ * </ol>
+ * </p>
+ * <p>
+ * <strong>Note</strong>: Javamail 1.4 should correctly support
+ * mail.smtp.localaddr so we could probably get rid of this class and simply add
+ * that property to the Session.
+ * </p>
+ */
+public class RemoteDeliverySocketFactory extends SocketFactory {
+
+ /**
+ * @param addr
+ * the ip address or host name the delivery socket will bind to
+ */
+ public static void setBindAdress(String addr) throws UnknownHostException {
+ if (addr == null) {
+ bindAddress = null;
+ } else {
+ bindAddress = InetAddress.getByName(addr);
+ }
+ }
+
+ /**
+ * the same as the similarly named javax.net.SocketFactory operation.
+ */
+ public static SocketFactory getDefault() {
+ return new RemoteDeliverySocketFactory();
+ }
+
+ /**
+ * the same as the similarly named javax.net.SocketFactory operation. Just
+ * to be safe, it is not used by JavaMail 1.3. This is the only method used
+ * by JavaMail 1.4.
+ */
+ public Socket createSocket() throws IOException {
+ Socket s = new Socket();
+ s.bind(new InetSocketAddress(bindAddress, 0));
+ return s;
+ }
+
+ /**
+ * the same as the similarly named javax.net.SocketFactory operation. This
+ * is the one which is used by JavaMail 1.3. This is not used by JavaMail
+ * 1.4.
+ */
+ public Socket createSocket(String host, int port) throws IOException {
+ return new Socket(host, port, bindAddress, 0);
+ }
+
+ /**
+ * the same as the similarly named javax.net.SocketFactory operation. Just
+ * to be safe, it is not used by JavaMail 1.3. This is not used by JavaMail
+ * 1.4.
+ */
+ public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort) throws IOException {
+ return new Socket(host, port, clientHost == null ? bindAddress : clientHost, clientPort);
+ }
+
+ /**
+ * the same as the similarly named javax.net.SocketFactory operation. Just
+ * to be safe, it is not used by JavaMail 1.3. This is not used by JavaMail
+ * 1.4.
+ */
+ public Socket createSocket(InetAddress host, int port) throws IOException {
+ return new Socket(host, port, bindAddress, 0);
+ }
+
+ /**
+ * the same as the similarly named javax.net.SocketFactory operation. Just
+ * to be safe, it is not used by JavaMail 1.3. This is not used by JavaMail
+ * 1.4.
+ */
+ public Socket createSocket(InetAddress address, int port, InetAddress clientAddress, int clientPort) throws IOException {
+ return new Socket(address, port, clientAddress == null ? bindAddress : clientAddress, clientPort);
+ }
+
+ /**
+ * it should be set by setBindAdress(). Null means the socket is bind to the
+ * default address.
+ */
+ private static InetAddress bindAddress;
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/52c18ef6/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/Repeat.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/Repeat.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/Repeat.java
new file mode 100644
index 0000000..6926c2d
--- /dev/null
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remote/delivery/Repeat.java
@@ -0,0 +1,38 @@
+/****************************************************************
+ * 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.remote.delivery;
+
+import java.util.List;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+
+public class Repeat {
+
+ @SuppressWarnings("unchecked")
+ public static <T> List<T> repeat(T element, int times) {
+ Preconditions.checkArgument(times >= 0, "Times argument should be strictly positive");
+ return ImmutableList.copyOf(
+ Iterables.limit(
+ Iterables.cycle(element), times));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/52c18ef6/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/AddressesArrayToMailAddressListConverter.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/AddressesArrayToMailAddressListConverter.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/AddressesArrayToMailAddressListConverter.java
deleted file mode 100644
index 9fbf7c8..0000000
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/AddressesArrayToMailAddressListConverter.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/****************************************************************
- * 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.util.Arrays;
-import java.util.List;
-import java.util.Optional;
-
-import javax.mail.Address;
-import javax.mail.internet.AddressException;
-
-import org.apache.james.core.MailAddress;
-import org.apache.james.util.OptionalUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.github.steveash.guavate.Guavate;
-import com.google.common.collect.ImmutableList;
-
-public class AddressesArrayToMailAddressListConverter {
- private static final Logger LOGGER = LoggerFactory.getLogger(AddressesArrayToMailAddressListConverter.class);
-
- public static List<MailAddress> getAddressesAsMailAddress(Address[] addresses) {
- if (addresses == null) {
- return ImmutableList.of();
- }
- return Arrays.asList(addresses)
- .stream()
- .map(address -> toMailAddress(address))
- .flatMap(OptionalUtils::toStream)
- .collect(Guavate.toImmutableList());
- }
-
- private static Optional<MailAddress> toMailAddress(Address address) {
- try {
- return Optional.of(new MailAddress(address.toString()));
- } catch (AddressException e) {
- LOGGER.debug("Can't parse unsent address {}", address, e);
- return Optional.empty();
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/james-project/blob/52c18ef6/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Bouncer.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Bouncer.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Bouncer.java
deleted file mode 100644
index 5b40cc1..0000000
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Bouncer.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/****************************************************************
- * 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.PrintWriter;
-import java.io.StringWriter;
-import java.net.ConnectException;
-import java.net.SocketException;
-import java.net.UnknownHostException;
-
-import javax.mail.MessagingException;
-import javax.mail.SendFailedException;
-
-import org.apache.james.core.MailAddress;
-import org.apache.mailet.Mail;
-import org.apache.mailet.MailetContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class Bouncer {
- private static final Logger LOGGER = LoggerFactory.getLogger(Bouncer.class);
-
- public static final String DELIVERY_ERROR = "delivery-error";
- private final RemoteDeliveryConfiguration configuration;
- private final MailetContext mailetContext;
-
- public Bouncer(RemoteDeliveryConfiguration configuration, MailetContext mailetContext) {
- this.configuration = configuration;
- this.mailetContext = mailetContext;
- }
-
- public void bounce(Mail mail, Exception ex) {
- if (mail.getSender() == null) {
- LOGGER.debug("Null Sender: no bounce will be generated for {}", mail.getName());
- } else {
- if (configuration.getBounceProcessor() != null) {
- mail.setAttribute(DELIVERY_ERROR, getErrorMsg(ex));
- try {
- mailetContext.sendMail(mail, configuration.getBounceProcessor());
- } catch (MessagingException e) {
- LOGGER.warn("Exception re-inserting failed mail: ", e);
- }
- } else {
- bounceWithMailetContext(mail, ex);
- }
- }
- }
-
-
- private void bounceWithMailetContext(Mail mail, Exception ex) {
- LOGGER.debug("Sending failure message {}", mail.getName());
- try {
- mailetContext.bounce(mail, explanationText(mail, ex));
- } catch (MessagingException me) {
- LOGGER.warn("Encountered unexpected messaging exception while bouncing message", me);
- } catch (Exception e) {
- LOGGER.warn("Encountered unexpected exception while bouncing message", e);
- }
- }
-
- public String explanationText(Mail mail, Exception ex) {
- StringWriter sout = new StringWriter();
- PrintWriter out = new PrintWriter(sout, true);
- out.println("Hi. This is the James mail server at " + resolveMachineName() + ".");
- out.println("I'm afraid I wasn't able to deliver your message to the following addresses.");
- out.println("This is a permanent error; I've given up. Sorry it didn't work out. Below");
- out.println("I include the list of recipients and the reason why I was unable to deliver");
- out.println("your message.");
- out.println();
- for (MailAddress mailAddress : mail.getRecipients()) {
- out.println(mailAddress);
- }
- if (ex instanceof MessagingException) {
- if (((MessagingException) ex).getNextException() == null) {
- out.println(sanitizeExceptionMessage(ex));
- } else {
- Exception ex1 = ((MessagingException) ex).getNextException();
- if (ex1 instanceof SendFailedException) {
- out.println("Remote mail server told me: " + sanitizeExceptionMessage(ex1));
- } else if (ex1 instanceof UnknownHostException) {
- out.println("Unknown host: " + sanitizeExceptionMessage(ex1));
- out.println("This could be a DNS server error, a typo, or a problem with the recipient's mail server.");
- } else if (ex1 instanceof ConnectException) {
- // Already formatted as "Connection timed out: connect"
- out.println(sanitizeExceptionMessage(ex1));
- } else if (ex1 instanceof SocketException) {
- out.println("Socket exception: " + sanitizeExceptionMessage(ex1));
- } else {
- out.println(sanitizeExceptionMessage(ex1));
- }
- }
- }
- out.println();
- return sout.toString();
- }
-
- private String sanitizeExceptionMessage(Exception e) {
- if (e.getMessage() == null) {
- return "null";
- } else {
- return e.getMessage().trim();
- }
- }
-
- private String resolveMachineName() {
- try {
- return configuration.getHeloNameProvider().getHeloName();
- } catch (Exception e) {
- return "[address unknown]";
- }
- }
-
- public String getErrorMsg(Exception ex) {
- if (ex instanceof MessagingException) {
- return getNestedExceptionMessage((MessagingException) ex);
- } else {
- return sanitizeExceptionMessage(ex);
- }
- }
-
- public String getNestedExceptionMessage(MessagingException me) {
- if (me.getNextException() == null) {
- return sanitizeExceptionMessage(me);
- } else {
- Exception ex1 = me.getNextException();
- return sanitizeExceptionMessage(ex1);
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/james-project/blob/52c18ef6/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Converter7Bit.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Converter7Bit.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Converter7Bit.java
deleted file mode 100644
index ab798e6..0000000
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/Converter7Bit.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/****************************************************************
- * 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 javax.mail.MessagingException;
-import javax.mail.internet.MimeMultipart;
-import javax.mail.internet.MimePart;
-
-import org.apache.mailet.MailetContext;
-
-public class Converter7Bit {
-
- private final MailetContext mailetContext;
-
- public Converter7Bit(MailetContext mailetContext) {
- this.mailetContext = mailetContext;
- }
-
- public MimePart convertTo7Bit(MimePart part) throws MessagingException, IOException {
- if (part.isMimeType("multipart/*")) {
- MimeMultipart parts = (MimeMultipart) part.getContent();
- int count = parts.getCount();
- for (int i = 0; i < count; i++) {
- convertTo7Bit((MimePart) parts.getBodyPart(i));
- }
- } else if ("8bit".equals(part.getEncoding())) {
- // The content may already be in encoded the form (likely with mail
- // created from a
- // stream). In that case, just changing the encoding to
- // quoted-printable will mangle
- // the result when this is transmitted. We must first convert the
- // content into its
- // native format, set it back, and only THEN set the transfer
- // encoding to force the
- // content to be encoded appropriately.
-
- // if the part doesn't contain text it will be base64 encoded.
- String contentTransferEncoding = part.isMimeType("text/*") ? "quoted-printable" : "base64";
- part.setContent(part.getContent(), part.getContentType());
- part.setHeader("Content-Transfer-Encoding", contentTransferEncoding);
- part.addHeader("X-MIME-Autoconverted", "from 8bit to " + contentTransferEncoding + " by " + mailetContext.getServerInfo());
- }
- return part;
- }
-
-}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org