de.uniks.networkparser.ext.email.SMTPSession Maven / Gradle / Ivy
package de.uniks.networkparser.ext.email;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import de.uniks.networkparser.buffer.Buffer;
import de.uniks.networkparser.buffer.CharacterBuffer;
import de.uniks.networkparser.converter.ByteConverter64;
import de.uniks.networkparser.interfaces.BaseItem;
import de.uniks.networkparser.list.SimpleKeyValueList;
import de.uniks.networkparser.list.SimpleList;
public class SMTPSession {
public final String RESPONSE_SERVERREADY = "220";
public final String RESPONSE_MAILACTIONOKEY="250";
public final String RESPONSE_STARTMAILINPUT="354";
public final String RESPONSE_SMTP_AUTH_NTLM_BLOB_Response="334";
public final String RESPONSE_LOGIN_SUCCESS="235";
public final String RESPONSE_SERVICE_CLOSING_TRANSMISSION="221";
public static final int SSLPORT=587;
/** 15 sec. socket read timeout */
public static final int SOCKET_READ_TIMEOUT = 15 * 1000;
private static final byte[] CRLF = { (byte)'\r', (byte)'\n' };
private String host;
private int port;
private String sender;
protected Socket serverSocket;
protected BufferedReader in;
protected OutputStream out;
protected SimpleList supportedFeature = new SimpleList();
private boolean allowutf8;
private CharacterBuffer lastAnswer;
private String lastSended;
/**
* Creates new SMTP session by given SMTP host and port, sender email address
* @param host SMTP host
* @param port SMTP port
* @param sender email address of sender
*/
public SMTPSession(String host, int port, String sender) {
this.host = host;
this.port = port;
this.sender = sender;
}
/**
* Creates new SMTP session by given SMTP host, sender email address,
* Assumes SMTP port is 25 (default for SMTP service).
* @param host SMTP host
* @param sender email address of sender
*/
public SMTPSession(String host, String sender) {
this(host, 25, sender);
}
/**
* Creates new SMTP session
*/
public SMTPSession() {
}
public SMTPSession connectSSL(String host, String sender, String password) {
this.host = host;
this.port = SSLPORT;
this.sender = sender;
this.connect(sender, password);
return this;
}
/**
* Closes down the connection to SMTP server (if open). Should be called if
* an exception is raised during the SMTP session.
* @return success
*/
public boolean close() {
try {
in.close();
out.close();
serverSocket.close();
} catch (Exception ex) {
// Ignore the exception. Probably the socket is not open.
return false;
}
return true;
}
/**
* Connects to the SMTP server and gets input and output streams (in, out).
* @param userName the Username
* @param password the password
* @return success
*/
public boolean connect(String userName, String password) {
if(serverSocket == null) {
try {
serverSocket = new Socket(host, port);
serverSocket.setSoTimeout(SOCKET_READ_TIMEOUT);
in = new BufferedReader(new InputStreamReader(serverSocket.getInputStream()));
out = serverSocket.getOutputStream();
checkServerResponse(getResponse(), RESPONSE_SERVERREADY);
sendHelo();
CharacterBuffer answer;
answer = sendCommand("STARTTLS");
startTLS();
sendHelo();
answer = sendCommand("AUTH LOGIN");
if(checkServerResponse(answer, RESPONSE_SMTP_AUTH_NTLM_BLOB_Response) == false) {
close();
return false;
}
ByteConverter64 converter = new ByteConverter64();
answer= sendCommand(converter.toStaticString(userName).toString());
if(checkServerResponse(answer, RESPONSE_SMTP_AUTH_NTLM_BLOB_Response) == false) {
close();
return false;
}
// send passwd
answer = sendCommand(converter.toStaticString(password).toString());
if(checkServerResponse(answer, RESPONSE_LOGIN_SUCCESS) == false) {
close();
return false;
}
}catch (Exception e) {
return false;
}
}
return true;
}
private boolean sendHelo() {
String response = sendCommand("EHLO " + getLocalHost()).toString();
supportedFeature.clear();
String[] lines = response.split("\n");
// Skip first line
for(int i=1;i eprots = new SimpleList();
for (int i = 0; i < prots.length; i++) {
if (prots[i] != null && !prots[i].startsWith("SSL"))
eprots.add(prots[i]);
}
socket.setEnabledProtocols(eprots.toArray(new String[eprots.size()]));
socket.startHandshake();
}
} catch (IOException e) {
}
}
/**
* Connects to the SMTP server and gets input and output streams (in, out).
* @return success
*/
protected boolean connect() {
return this.connect(null, null);
}
/**
* Sends given command and waits for a response from server.
* @param commandString String for sending
* @return response received from the server.
*/
protected CharacterBuffer sendCommand(String commandString) {
this.lastSended = commandString;
byte[] cmd = toBytes(commandString);
sendValues(cmd);
CharacterBuffer response = getResponse();
return response;
}
protected void sendValues(String commandString) {
this.lastSended = commandString;
byte[] cmd = toBytes(commandString);
sendValues(cmd);
}
/**
* Sends given command and waits for a response from server.
*
* @param cmd bytes for sending
*/
protected void sendValues(byte... cmd) {
try {
out.write(cmd);
out.write(CRLF);
out.flush();
} catch (IOException e) {
}
}
/**
* Convert the String to either ASCII or UTF-8 bytes
* depending on allowutf8.
* @param s string to convert
* @return convert String to Byte
*/
private byte[] toBytes(String s) {
if (allowutf8)
return s.getBytes(StandardCharsets.UTF_8);
else
// don't use StandardCharsets.US_ASCII because it rejects non-ASCII
return s.getBytes();
// return ASCIIUtility.getBytes(s);
}
/**
* Sends given commandString to the server, gets its reply and checks if it
* starts with expectedResponseStart. If not, throws IOException with
* server's reply (which is unexpected).
* @param commandString the Command to send
* @param responseCode expected value of Response
* @return success
*/
protected boolean doCommand(String commandString, String responseCode) {
CharacterBuffer response = sendCommand(commandString);
return checkServerResponse(response, responseCode);
}
/**
* Checks if given server reply starts with expectedResponseStart. If not,
* @param response Response as String
* @param code check the response for response code
* @return success
*/
protected boolean checkServerResponse(CharSequence response, String code) {
if(response == null || code == null) {
return false;
}
if(response.length() 3) && (line.charAt(3) == '-'));
this.lastAnswer = response;
return response;
}
/**
* Get the name of the local host, for use in the EHLO and HELO commands.
* The property InetAddress would tell us.
*
* @return the local host name
*/
public String getLocalHost() {
InetAddress localHost;
String localHostName = null;
// get our hostname and cache it for future use
try {
localHost = InetAddress.getLocalHost();
localHostName = localHost.getCanonicalHostName();
// if we can't get our name, use local address literal
if (localHostName == null) {
// XXX - not correct for IPv6
localHostName = "[" + localHost.getHostAddress() + "]";
}
} catch (UnknownHostException e) {
e.printStackTrace();
}
// last chance, try to get our address from our socket
if (localHostName == null || localHostName.length() <= 0) {
if (serverSocket != null && serverSocket.isBound()) {
localHost = serverSocket.getLocalAddress();
localHostName = localHost.getCanonicalHostName();
// if we can't get our name, use local address literal
if (localHostName == null)
// XXX - not correct for IPv6
localHostName = "[" + localHost.getHostAddress() + "]";
}
}
return localHostName;
}
public String getLocalAdress() {
try {
InetAddress localHost = InetAddress.getLocalHost();
return "@"+localHost.getHostName();
}catch (Exception e) {
}
return "mailer@localhost"; // worst-case default
}
/**
* Sends a message using the SMTP protocol.
* @param message to send
* @return success
*/
public boolean sendMessage(EMailMessage message) {
if(connect() == false) {
return false;
}
// Tell the server who this message is from
if(doCommand(message.getHeaderFrom(this.sender), RESPONSE_MAILACTIONOKEY) == false) {
return false;
}
// Now tell the server who we want to send a message to
SimpleList headerTo = message.getHeaderTo();
int pos=0;
for(int i=0;i messages = message.getMessages();
boolean multiPart = message.isMultiPart();
String splitter="--";
if(multiPart) {
sendValues(message.getHeader(EMailMessage.PROPERTY_CONTENTTYPE)+message.getHeader(EMailMessage.PROPERTY_BOUNDARY));
} else {
sendValues(message.getHeader(EMailMessage.PROPERTY_CONTENTTYPE));
sendValues(EMailMessage.CONTENT_ENCODING);
}
// The CRLF separator between header and content
sendValues(CRLF);
for(BaseItem msg : messages) {
CharacterBuffer buffer=new CharacterBuffer();
if(msg != null) {
buffer.with(msg.toString());
}
if(multiPart) {
sendValues(splitter+message.generateBoundaryValue());
sendValues(EMailMessage.PROPERTY_CONTENTTYPE+message.getContentType(msg));
sendValues(EMailMessage.CONTENT_ENCODING);
}
// The CRLF separator between header and content
sendValues(CRLF);
while(buffer.isEnd() == false) {
CharacterBuffer line=buffer.readLine();
// If the line begins with a ".", put an extra "." in front of it.
if (line.startsWith(".")) {
sendValues((byte)'.');
}
sendValues(line.toByteArray());
}
}
SimpleKeyValueList attachments = message.getAttachments();
for(int i=0;i
© 2015 - 2025 Weber Informatics LLC | Privacy Policy