package org.openslx.bwlp.sat.mail;
import java.io.IOException;
import java.io.Writer;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import javax.security.auth.login.LoginException;
import org.apache.commons.net.PrintCommandListener;
import org.apache.commons.net.smtp.AuthenticatingSMTPClient;
import org.apache.commons.net.smtp.AuthenticatingSMTPClient.AUTH_METHOD;
import org.apache.commons.net.smtp.SMTPReply;
import org.apache.commons.net.smtp.SimpleSMTPHeader;
import org.apache.log4j.Logger;
import org.openslx.bwlp.sat.util.Util;
public class SmtpMailer {
// TODO Logging
private static final Logger LOGGER = Logger.getLogger(SmtpMailer.class);
public enum EncryptionMode {
NONE,
IMPLICIT,
EXPLICIT
}
private final String fromAddress;
private final String fromName;
private final String replyTo;
private final AuthenticatingSMTPClient client;
public SmtpMailer(String host, int port, EncryptionMode ssl, String fromAddress, String fromName,
String replyTo, String username, String password) throws UnknownHostException, SocketException,
IOException, LoginException, InvalidKeyException, NoSuchAlgorithmException,
InvalidKeySpecException {
InetAddress[] ips = InetAddress.getAllByName(host);
if (ips == null || ips.length == 0)
throw new UnknownHostException(host);
LOGGER.debug("Mailing via " + host + ", " + ssl);
if (ssl == EncryptionMode.EXPLICIT || ssl == EncryptionMode.NONE) {
client = new AuthenticatingSMTPClient("TLSv1.2", false, "UTF-8");
} else {
client = new AuthenticatingSMTPClient("TLSv1.2", true, "UTF-8");
}
boolean cleanup = true;
try {
client.addProtocolCommandListener(new PrintCommandListener(System.out));
client.setConnectTimeout(5000);
IOException conEx = null;
for (InetAddress ip : ips) {
try {
client.connect(ip, port);
if (!SMTPReply.isPositiveCompletion(client.getReplyCode())) {
client.disconnect();
continue;
}
conEx = null;
break;
} catch (IOException e) {
conEx = e;
}
}
if (conEx != null)
throw conEx;
if (!client.elogin("bwlehrpool.sat")) {
throw new LoginException("SMTP server rejected EHLO");
}
if (ssl == EncryptionMode.EXPLICIT && !client.execTLS()) {
throw new LoginException("STARTTLS (explicit TLS) failed");
}
if (!Util.isEmptyString(username)) {
boolean authed = false;
try {
authed = client.auth(AUTH_METHOD.CRAM_MD5, username, password);
} catch (InvalidKeyException | NoSuchAlgorithmException | InvalidKeySpecException e) {
e.printStackTrace();
}
if (!authed && !client.auth(AUTH_METHOD.PLAIN, username, password)) {
throw new LoginException("Server rejected AUTH command. Invalid username or password?");
}
}
cleanup = false;
this.fromAddress = fromAddress;
this.fromName = fromName;
this.replyTo = replyTo;
} finally {
if (cleanup)
cleanup();
}
}
private void cleanup() {
try {
client.logout();
} catch (Exception e) {
}
try {
client.disconnect();
} catch (Exception e) {
}
}
private void abort() throws IOException {
if (!client.reset())
throw new IOException("Cannot abort current mail transaction");
}
public boolean send(String recipient, String subject, String message) {
Writer writer;
SimpleSMTPHeader header;
try {
header = new QuotingSmtpHeader(fromAddress, fromName, recipient, subject);
if (!Util.isEmptyString(replyTo)) {
header.addHeaderField("Reply-To", replyTo);
}
header.addHeaderField("Content-Type", "text/plain; charset=utf-8");
header.addHeaderField("Content-Transfer-Encoding", "8bit");
if (!client.setSender(fromAddress)) {
abort();
return false;
}
if (!client.addRecipient(recipient)) {
abort();
return false;
}
writer = client.sendMessageData();
if (writer == null) {
abort();
return false;
}
writer.write(header.toString());
writer.write(message);
writer.close();
client.completePendingCommand();
return true;
} catch (IOException e) {
cleanup();
return false;
}
}
public boolean isConnected() {
if (!client.isConnected())
return false;
try {
client.sendNoOp();
return true;
} catch (IOException e) {
return false;
}
}
public void close() {
if (client.isConnected()) {
try {
client.logout();
} catch (Exception e) { // Don't care
}
try {
client.disconnect();
} catch (Exception e) { // Don't care
}
}
}
}