base.email.Mail Maven / Gradle / Ivy
/**
* Creative commons Attribution-NonCommercial license.
*
* http://creativecommons.org/licenses/by-nc/2.5/au/deed.en_GB
*
* NO WARRANTY IS GIVEN OR IMPLIED, USE AT YOUR OWN RISK.
*/
package base.email;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.InetAddress;
import java.net.SocketAddress;
import java.net.SocketTimeoutException;
import java.util.Date;
import java.util.List;
import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import base.email.encoding.Encoding;
import base.email.encoding.PlainTextEncoding;
import base.email.encoding.QuotedPrintableEncoding;
import base.text.Base64Encode;
import base.text.StringHelper;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
/**
* Deliver an email message via an SMTP server. Note this feature is
* custom written because this facility does not always work out of
* the box on all systems. Based upon but not fully tested against
* RFC 821 and RFC 2822. Example usage:
*
*
* Mail m=new Mail("smtp.example.com");
*
* if(m.testConnection() == 0) {
* System.out.println("Connection to mailserver available");
* } else {
* System.out.println("Problem with specified mailserver: "+m.getError());
* }
*
* m.enableAuthentication("[email protected]","password");
* int result = m.sendMail("[email protected]","[email protected]","My subject","content2");
* if(result>0) {
* System.err.println(m.getError());
* }
*
* result=m.sendMail("[email protected]","[email protected]","Another subject","content2");
* if(result>0) {
* System.err.println(m.getError());
* }
*
* result=m.sendMails("[email protected]","[email protected],[email protected]","test1","content");
* if(result>0) {
* System.err.println(m.getError());
* }
*
*/
public class Mail {
private String host = null;
private int port = 25;
private String error = "";
private static Random generator = new Random();
private int timeout = 10000;
public Mail(String host, int port) {
this.host = host;
this.port = port;
}
public Mail(String host) {
this.host = host;
}
String authUsername = null;
String authPassword = null;
boolean authEnabled = false;
/**
* Attempt to authenticate to the mail server, primarily used to enable
* relaying of email where required.
*
* @param username Provide account username
* @param password Specify account password
*/
public void enableAuthentication(String username, String password) {
authUsername = username;
authPassword = password;
authEnabled = true;
}
/**
* Disable attempting to authenticate with mail server.
*/
public void disableAuthentication() {
authUsername = null;
authPassword = null;
authEnabled = false;
}
/**
* Used to retrive the error message related generated due
* to failure of sendMail() function.
*
* @return Text string containing english description of problem.
*/
public String getError() {
String e2 = error;
error = "";
return e2;
}
/**
* Specify maximum length of time in milliseconds to wait for an SMTP server to respond. Default is ten seconds.
* @param timeout Maximum wait time in milliseconds
*/
public void setTimeout(int timeout) {
this.timeout = timeout;
}
/**
* The maximum length of time to wait for an SMTP server to respond
* @return Maximum wait time in milliseconds
*/
public int getTimeout() {
return timeout;
}
/**
* Send a message in plain text format, no html or mime encoding
*
* @param from Sender email address.
* @param to Destination email address.
* @param subject Subject of email message.
* @param html content of email message to be sent, or null for no html.
* @param text text content of the email
* @param headers Extra header lines to insert, this may be null.
*
* @return 0 if successful, otherwise error number returned.
*/
public int send(String from, String to, String subject, String html, String text, List headers) {
StringBuffer message = new StringBuffer();
Socket socket = null;
String response = null;
String datestamp = "";
Format dformat = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss Z");
datestamp = dformat.format(new Date());
Pattern p = Pattern.compile("[\"']*([^\"'<]*)[\"']* *<([^>]*)>");
String fromEmail = from;
String fromName = "";
if(from.indexOf('<') > 0) {
Matcher m = p.matcher(from);
if(m.matches()) {
fromName = m.group(1);
fromEmail = m.group(2);
}
}
String toEmail = to;
String toName = "";
if(to.indexOf('<') > 0) {
Matcher m = p.matcher(to);
if(m.matches()) {
toName = m.group(1);
toEmail = m.group(2);
}
}
EmailAddressParse etest = new EmailAddressParse();
if(!etest.isValid(fromEmail)) {
error = etest.getError();
return 1;
}
if(!etest.isValid(toEmail)) {
error = etest.getError();
return 1;
}
try {
SocketAddress sockaddr = new InetSocketAddress(host, port);
socket = new Socket();
socket.setSoTimeout(timeout);
socket.connect(sockaddr, timeout);
} catch(SocketTimeoutException e) {
error = "Timeout while connecting to mail server";
if(socket != null) { try { socket.close(); } catch(IOException f) {} }
return 2;
} catch(IOException e) {
error = "Unable to connect to mail server";
if(socket != null) { try { socket.close(); } catch(IOException f) {} }
return 1;
}
try {
InetAddress lina = InetAddress.getLocalHost();
OutputStream ps = socket.getOutputStream();
InputStreamReader dd = new InputStreamReader(socket.getInputStream());
BufferedReader dis = new BufferedReader(dd);
response = dis.readLine();
if(response.indexOf("220 ") != 0) {
error = "Mail did not respond like a mail server";
return 1;
}
message.append("HELO ");
message.append(lina.toString());
message.append("\r\n");
ps.write(message.toString().getBytes());
ps.flush();
response = dis.readLine();
if(response.indexOf("250 ") != 0) {
error = response + " (Sent: " + message.toString() + ")";
return 1;
}
message.setLength(0);
if(port == 587) {
message.append("starttls\r\n");
ps.write(message.toString().getBytes());
ps.flush();
response = dis.readLine();
if(response.indexOf("220 ") != 0) {
error = "STARTTLS failed. " + response;
return 1;
}
SSLSocket sslSocket = (SSLSocket)((SSLSocketFactory)SSLSocketFactory.getDefault()).createSocket(
socket,
socket.getInetAddress().getHostAddress(),
socket.getPort(),
true);
dis = new BufferedReader(new InputStreamReader(sslSocket.getInputStream()));
ps = sslSocket.getOutputStream();
message.setLength(0);
}
if(authEnabled) {
message.append("AUTH LOGIN\r\n");
ps.write(message.toString().getBytes());
ps.flush();
response = dis.readLine();
if(response.indexOf("334 ") != 0) {
error = response;
return 1;
}
message.setLength(0);
message.append(Base64Encode.encode(authUsername));
message.append("\r\n");
ps.write(message.toString().getBytes());
ps.flush();
response=dis.readLine();
if(response.indexOf("334 ") != 0) {
error = response;
return 1;
}
message.setLength(0);
ps.write((Base64Encode.encode(authPassword) + "\r\n").getBytes());
ps.flush();
response = dis.readLine();
if(response.indexOf("235 ") != 0) {
error = response;
return 1;
}
}
ps.write(("MAIL FROM:" + fromEmail + "\r\n").getBytes());
ps.flush();
response = dis.readLine();
if(response.indexOf("250 ") != 0) {
error=response;
return 1;
}
ps.write(("RCPT TO:" + toEmail + "\r\n").getBytes());
ps.flush();
response=dis.readLine();
if(response.indexOf("250 ") != 0) {
error = response;
return 1;
}
message.append("DATA\r\n");
ps.write(message.toString().getBytes());
response = dis.readLine();
if(response.indexOf("354 ") != 0) {
error = response;
return 1;
}
message.setLength(0);
message.append("Date: ");
message.append(datestamp);
message.append("\r\n");
if(fromName.length() > 0) {
message.append("From: \"");
message.append(fromName);
message.append("\" <");
message.append(fromEmail);
message.append(">");
} else {
message.append("From: ");
message.append(fromEmail);
}
message.append("\r\n");
message.append("Subject: " + subject);
message.append("\r\n");
if(toName.length() > 0) {
message.append("To: \"" + toName + "\" <" + toEmail + ">");
message.append("\r\n");
} else {
message.append("To: " + toEmail);
message.append("\r\n");
}
String messageId = null;
if(headers != null) {
for(String header : headers) {
message.append(header);
message.append("\r\n");
if(header.toLowerCase().startsWith("message-id:")) {
messageId = header;
}
}
}
if(messageId == null) {
message.append("Message-ID: <"+(new base.uuid.UUID().toString().toUpperCase())+"@"+lina.toString()+">");
message.append("\r\n");
}
ps.write(message.toString().getBytes());
message.setLength(0);
if(html != null && html.length() > 0) {
Encoding quotedPrintable = new QuotedPrintableEncoding();
html = quotedPrintable.encode(html);
Encoding plainText = new PlainTextEncoding();
text = plainText.encode(text);
String boundary = String.valueOf(Math.abs(generator.nextLong()));
message.append("Content-type: multipart/alternative; charset=UTF-8; boundary=");
message.append(boundary);
message.append("\r\n");
message.append("Mime-Version: 1.0\r\n");
message.append("\r\n");
message.append("--");
message.append(boundary);
message.append("\r\n");
message.append("Content-Type: text/plain; charset=utf-8; format=flowed\r\n");
message.append("Content-Transfer-Encoding: 8bit\r\n");
message.append("Content-Disposition: inline\r\n");
message.append("\r\n");
message.append(text);
message.append("\r\n\r\n");
message.append("--");
message.append(boundary);
message.append("\r\n");
message.append("Content-Type: text/html; charset=utf-8\r\n");
message.append("Content-Transfer-Encoding: quoted-printable\r\n");
message.append("Content-Disposition: inline\r\n");
message.append("\r\n");
message.append(html);
message.append("\r\n\r\n");
message.append("--");
message.append(boundary);
message.append("--\r\n");
} else {
message.append("\r\n");
Encoding plainText = new PlainTextEncoding();
text = plainText.encode(text);
message.append(text);
message.append("\r\n");
}
message.append(".\r\n");
ps.write(message.toString().getBytes());
ps.flush();
response = dis.readLine();
if(response == null) {
error = "Error reading data from server. ";
return 1;
}
if(response.indexOf("250 ") != 0) {
error = response;
return 1;
}
message.setLength(0);
message.append("QUIT\r\n");
ps.write(message.toString().getBytes()); ps.flush();
response = dis.readLine();
if(response == null) {
error = "Error reading data from server. ";
return 1;
}
if(response.indexOf("221 ") != 0) {
error = response;
return 1;
}
message.setLength(0);
} catch(SocketTimeoutException e) {
error = "Timeout while waiting for response from mail server. " + StringHelper.exceptionToString(e, "\n");
if(message.length() > 0) {
error = error + " (Sent: " + StringHelper.maxLength(message.toString(), 100) + ")";
}
return 4;
} catch (Exception ex) {
error = "Problem communicating with mail server. " + StringHelper.exceptionToString(ex, "\n ");
if(message.length() > 0) {
error = error + " (Sent: " + StringHelper.maxLength(message.toString(), 100) + ")";
}
return 2;
} finally {
if(socket != null) {
try { socket.close(); } catch(IOException f) {}
}
}
return 0;
}
/**
* Used to test connection and communication with the specified mail server.
* Will report if a connection can not be established with the mail server
* or if the mailserver does not reply with content a mail server should reply
* with, or finally if there are network difficulties at the time of the test.
*
* @return 0 if successful, >0 if not successful. Use getError() to read the problem.
*/
public int testConnection() {
Socket socket = null;
String response = null;
try {
SocketAddress sockaddr = new InetSocketAddress(host, port);
socket = new Socket();
socket.setSoTimeout(timeout);
socket.connect(sockaddr, timeout);
} catch(SocketTimeoutException e) {
error = "Timeout while connecting to mail server";
if(socket != null) { try { socket.close(); } catch(IOException f) {} }
return 3;
} catch(IOException e) {
error = "Unable to connect to mail server";
if(socket != null) { try { socket.close(); } catch(IOException f) {} }
return 1;
}
try {
PrintStream ps = new PrintStream(socket.getOutputStream());
InputStreamReader dd = new InputStreamReader(socket.getInputStream());
BufferedReader dis = new BufferedReader(dd);
response = dis.readLine();
if(response.indexOf("220 ") != 0) {
error="Mail did not respond like a mail server";
return 1;
}
ps.println("QUIT");
ps.flush();
response = dis.readLine();
if(response.indexOf("221 ") != 0) {
error = response;
return 1;
}
} catch(SocketTimeoutException e) {
error = "Timeout while waiting for response from mail server. " + StringHelper.exceptionToString(e, "\n");
try { socket.close(); } catch(IOException f) {}
return 4;
} catch (Exception e) {
error = "Problem communicating with mail server. " + e.getMessage();
try { socket.close(); } catch(IOException f) {}
return 2;
}
try { socket.close(); } catch(IOException e) {}
return 0;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy