
at.molindo.notify.channel.mail.DirectMailClient Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of molindo-notify Show documentation
Show all versions of molindo-notify Show documentation
Extensible notification framework
The newest version!
/**
* Copyright 2010 Molindo GmbH
*
* Licensed 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 at.molindo.notify.channel.mail;
import java.util.Collections;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import javax.mail.Address;
import javax.mail.MessagingException;
import javax.mail.SendFailedException;
import javax.mail.Session;
import javax.naming.NamingException;
import org.springframework.beans.factory.InitializingBean;
import at.molindo.utils.collections.CollectionUtils;
import at.molindo.utils.data.ExceptionUtils;
import at.molindo.utils.net.DnsUtils;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.sun.mail.smtp.SMTPAddressFailedException;
import com.sun.mail.smtp.SMTPSendFailedException;
public class DirectMailClient extends AbstractMailClient implements InitializingBean {
private static final int DEFAULT_CACHE_CONCURRENCY = 4;
private static final long DEFAULT_CACHE_EXPIRATION_MIN = 10;
private static final String CONNECTION_TIMEOUT_MS = "60000";
private static final String READ_TIMEOUT_MS = "60000";
// permanent errors
private static final int MAILBOX_UNAVAILABLE = 550;
private static final int MAILBOX_NOT_LOCAL = 551;
private static final int MAILBOX_NAME_NOT_ALLOWED = 553;
private static final int TRANSACTION_FAILED = 554;
private static final Set PERMANENT_ERROR_CODES = Collections.unmodifiableSet(CollectionUtils.set(
MAILBOX_UNAVAILABLE, MAILBOX_NOT_LOCAL, MAILBOX_NAME_NOT_ALLOWED, TRANSACTION_FAILED));
private LoadingCache _sessionCache;
private int _cacheConcurrency = DEFAULT_CACHE_CONCURRENCY;
private long _cacheExpirationMin = DEFAULT_CACHE_EXPIRATION_MIN;
private String _localAddress;
private String _socksProxyHost;
private String _socksProxyPort;
private Boolean _proxySet;
private String _localHost;
private boolean _startTLSEnabled = false;
@Override
public DirectMailClient init() throws MailException {
super.init();
_sessionCache = CacheBuilder.newBuilder().concurrencyLevel(_cacheConcurrency)
.expireAfterAccess(_cacheExpirationMin, TimeUnit.MINUTES).build(new CacheLoader() {
@Override
public Session load(String domain) throws MailException {
return createSmtpSession(domain);
}
});
return this;
}
@Override
protected Session getSmtpSession(String recipient) throws MailException {
try {
return _sessionCache.get(MailUtils.domainFromAddress(recipient));
} catch (ExecutionException e) {
if (e.getCause() instanceof MailException) {
throw (MailException) e.getCause();
} else {
throw new RuntimeException("unexpected exception while getting SMTP session for " + recipient, e);
}
}
}
protected Session createSmtpSession(String domain) throws MailException {
try {
final Properties props = new Properties();
props.setProperty("mail.smtp.host", DnsUtils.lookupMailHosts(domain)[0]);
props.setProperty("mail.smtp.port", "25");
props.setProperty("mail.smtp.auth", "false");
props.setProperty("mail.smtp.starttls.enable", Boolean.toString(getStartTLSEnabled()));
// set proxy
if (Boolean.TRUE.equals(getProxySet())) {
props.setProperty("proxySet", "true");
props.setProperty("socksProxyHost", getSocksProxyHost());
props.setProperty("socksProxyPort", getSocksProxyPort());
}
if (getLocalHost() != null) {
props.setProperty("mail.smtp.localhost", getLocalHost());
}
if (getLocalAddress() != null) {
props.setProperty("mail.smtp.localaddress", getLocalAddress());
}
props.setProperty("mail.smtp.connectiontimeout", CONNECTION_TIMEOUT_MS);
props.setProperty("mail.smtp.timeout", READ_TIMEOUT_MS);
// props.put("mail.debug", "true");
return Session.getInstance(props);
} catch (NamingException e) {
throw new MailException("can't lookup mail host: " + domain, e, true);
}
}
@Override
protected String toErrorMessage(MessagingException e) {
if (e instanceof SendFailedException) {
if (e.getNextException() instanceof SMTPSendFailedException) {
final SMTPSendFailedException se = (SMTPSendFailedException) e.getNextException();
return se.getCommand() + " failed " + " with " + se.getReturnCode() + " (" + e.getMessage() + ")";
} else if (e.getNextException() instanceof SMTPAddressFailedException) {
// copied from above, as there is no common base class but same
// methods
final SMTPAddressFailedException se = (SMTPAddressFailedException) e.getNextException();
return se.getCommand() + " failed " + " with " + se.getReturnCode() + " (" + e.getMessage() + ")";
} else {
final StringBuilder buf = new StringBuilder();
Address[] addresses = ((SendFailedException) e).getInvalidAddresses();
if (addresses != null) {
for (final Address a : addresses) {
buf.append(a).append(" ");
}
}
return "invalied address(es): " + buf + "(" + ExceptionUtils.getAllMessages(e) + ")";
}
} else {
return super.toErrorMessage(e);
}
}
@Override
protected boolean isTemporary(MessagingException e) {
if (e instanceof SendFailedException) {
if (e.getNextException() instanceof SMTPSendFailedException) {
final SMTPSendFailedException se = (SMTPSendFailedException) e.getNextException();
final int rc = se.getReturnCode();
return !PERMANENT_ERROR_CODES.contains(rc);
} else if (e.getNextException() instanceof SMTPAddressFailedException) {
// copied from above, as there is no common base class but same
// methods
final SMTPAddressFailedException se = (SMTPAddressFailedException) e.getNextException();
final int rc = se.getReturnCode();
return !PERMANENT_ERROR_CODES.contains(rc);
} else {
return true;
}
} else {
return true;
}
}
public int getCacheConcurrency() {
return _cacheConcurrency;
}
public void setCacheConcurrency(int cacheConcurrency) {
_cacheConcurrency = cacheConcurrency;
}
public long getCacheExpirationMin() {
return _cacheExpirationMin;
}
public void setCacheExpirationMin(long cacheExpirationMin) {
_cacheExpirationMin = cacheExpirationMin;
}
public void setLocalAddress(final String localAddress) {
_localAddress = localAddress;
}
public void setLocalHost(final String localHost) {
_localHost = localHost;
}
public String getLocalAddress() {
return _localAddress;
}
public String getLocalHost() {
return _localHost;
}
public void setStartTLSEnabled(boolean startTLSEnabled) {
_startTLSEnabled = startTLSEnabled;
}
public boolean getStartTLSEnabled() {
return _startTLSEnabled;
}
public void setSocksProxyHost(final String socksProxyHost) {
_socksProxyHost = socksProxyHost;
}
public void setSocksProxyPort(final String socksProxyPort) {
_socksProxyPort = socksProxyPort;
}
public void setProxySet(final Boolean proxySet) {
_proxySet = proxySet;
}
private String getSocksProxyHost() {
return _socksProxyHost;
}
private String getSocksProxyPort() {
return _socksProxyPort;
}
private Boolean getProxySet() {
return _proxySet;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy