Improved SMTP email robustness and added JUnit test for it

This commit is contained in:
Ziver Koc 2017-01-20 00:38:47 +01:00
parent b109d6ae5c
commit 3d04dba4fd
3 changed files with 239 additions and 66 deletions

View file

@ -1,11 +1,13 @@
package zutil.net.smtp;
import java.io.IOException;
import java.io.PrintStream;
import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.regex.Pattern;
import static zutil.net.smtp.SMTPClient.NEWLINE;
import sun.net.smtp.SmtpClient;
/**
* Simplifies sending of a email
@ -13,16 +15,20 @@ import sun.net.smtp.SmtpClient;
* @author Ziver
*/
public class Email {
public enum ContentType{
public enum ContentType{
PLAIN, HTML
}
private static final SimpleDateFormat dateFormatter =
new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z");
private static final Pattern PATTERN_NEWLINE = Pattern.compile("(\\r\\n|\\n)");
private String from;
private String niceFrom = null;
private String to;
private String replyTo = null;
private String fromAddress;
private String fromName = null;
private String toAddress;
private String toName = null;
private String replyToAddress = null;
private Date date = null;
private ContentType type = ContentType.PLAIN;
private String subject;
private String message;
@ -33,33 +39,66 @@ public class Email {
public void setFrom(String address){
from = address;
this.fromAddress = sanitizeParam(address);
}
public void setFrom(String address, String niceName){
from = address;
niceFrom = niceName;
fromAddress = sanitizeParam(address);
fromName = sanitizeParam(niceName);
}
public String getFromAddress(){
return from;
return fromAddress;
}
public void setReplyTo(String rpt){
replyTo = rpt;
public String getFromName() {
return fromName;
}
public void setReplyTo(String address){
this.replyToAddress = sanitizeParam(address);
}
public void setTo(String t){
to = t;
public String getReplyToAddress() {
return replyToAddress;
}
public void setTo(String address){
this.toAddress = sanitizeParam(address);
}
public String getTo(){
return to;
public void setTo(String address, String niceName){
this.toAddress = sanitizeParam(address);
this.toName = sanitizeParam(niceName);
}
public String getToAddress(){
return toAddress;
}
public String getToName() {
return toName;
}
public void setDate(Date date){
this.date = date;
}
public void setContentType(ContentType t){
type = t;
}
public void setSubject(String s){
subject = s;
public void setSubject(String subject){
this.subject = sanitizeParam(subject);
}
public String getSubject(){
return subject;
}
public void setMessage(String msg){
message = msg;
message = msg.replaceAll("(\\r\\n|\\n)", NEWLINE);
message = message.replaceAll(NEWLINE+"\\.", NEWLINE +"..");
}
public String getMessage(){
return message;
}
private String sanitizeParam(String param){
return PATTERN_NEWLINE.matcher(param).replaceAll("");
}
/**
@ -67,33 +106,48 @@ public class Email {
*
* @throws IllegalArgumentException if from address and to address has not been set
*/
public void write(PrintStream out) throws IOException{
if(from == null)
public void write(Writer out) throws IOException{
if(fromAddress == null)
throw new IllegalArgumentException("From value cannot be null!");
if(to == null)
if(toAddress == null)
throw new IllegalArgumentException("To value cannot be null!");
//************ Headers
if (niceFrom!=null)
out.println("From: \""+niceFrom+"\" <"+from+">");
// From
if (fromName !=null)
out.write("From: "+ fromName +" <"+ fromAddress +">"+ NEWLINE);
else
out.println("From: <"+from+">");
if ( replyTo != null )
out.println("Reply-To: <"+replyTo+">");
out.println("To: " + to);
out.println("Subject: "+subject);
out.write("From: "+ fromAddress + NEWLINE);
// Reply-To
if ( replyToAddress != null )
out.write("Reply-To: <"+ replyToAddress +">"+ NEWLINE);
// To
if (toName !=null)
out.write("To: "+ toName +" <"+ toAddress +">"+ NEWLINE);
else
out.write("To: "+ toAddress + NEWLINE);
// Date
out.println("Date: "+dateFormatter.format(new Date(System.currentTimeMillis())));
if (date != null)
out.write("Date: "+dateFormatter.format(date) + NEWLINE);
else
out.write("Date: "+dateFormatter.format(new Date(System.currentTimeMillis())) + NEWLINE);
// Content type
switch( type ){
case HTML:
out.println("Content-Type: text/html;"); break;
out.write("Content-Type: text/html;"+ NEWLINE); break;
default:
out.println("Content-Type: text/plain;"); break;
out.write("Content-Type: text/plain;"+ NEWLINE); break;
}
out.println();
// Subject
out.write("Subject: "+(subject!=null ? subject : "") + NEWLINE);
out.write(NEWLINE);
//*********** Mesasge
out.println( message );
out.write( message );
}
}

View file

@ -26,10 +26,7 @@ package zutil.net.smtp;
import zutil.log.LogUtil;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.util.logging.Level;
@ -46,7 +43,7 @@ import java.util.logging.Logger;
public class SMTPClient {
private static final Logger logger = LogUtil.getLogger();
private static final String NEWLINE = "\r\n";
protected static final String NEWLINE = "\r\n";
private static final String CMD_HELO = "HELO";
private static final String CMD_FROM = "MAIL FROM";
private static final String CMD_TO = "RCPT TO";
@ -59,7 +56,7 @@ public class SMTPClient {
private Socket socket;
private BufferedReader in;
private PrintStream out;
private Writer out;
/**
@ -77,7 +74,7 @@ public class SMTPClient {
public SMTPClient(String host, int port) throws IOException {
socket = new Socket(host, port);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintStream(socket.getOutputStream());
out = new OutputStreamWriter(socket.getOutputStream());
readCommand();
sendCommand(CMD_HELO + " " + InetAddress.getLocalHost().getHostName());
@ -92,26 +89,12 @@ public class SMTPClient {
* @param msg the email body message
*/
public synchronized void send(String from, String to, String subj, String msg) throws IOException{
if(from == null)
throw new IllegalArgumentException("From value cannot be null!");
if(to == null)
throw new IllegalArgumentException("To value cannot be null!");
try{
// Pre metadata
sendCommand(CMD_FROM + ":" + from);
sendCommand(CMD_TO + ":" + to);
sendCommand(CMD_DATA);
// Message headers and body
out.println("From: "+from);
out.println("To: "+to);
out.println("Subject: "+subj);
out.println("");
out.println(msg);
sendCommand(CMD_DATA_END);
reset();
}catch(IOException e){
logger.log(Level.SEVERE, null, e);
}
Email email = new Email();
email.setFrom(from);
email.setTo(to);
email.setSubject(subj);
email.setMessage(msg);
send(email);
}
/**
@ -122,15 +105,16 @@ public class SMTPClient {
public synchronized void send(Email email) throws IOException{
if(email.getFromAddress() == null)
throw new IllegalArgumentException("From value cannot be null!");
if(email.getTo() == null)
if(email.getToAddress() == null)
throw new IllegalArgumentException("To value cannot be null!");
try{
// Pre metadata
sendCommand(CMD_FROM + ":" + email.getFromAddress());
sendCommand(CMD_TO + ":" + email.getTo());
sendCommand(CMD_TO + ":" + email.getToAddress());
sendCommand(CMD_DATA);
// Message headers and body
email.write(out);
out.write(NEWLINE);
sendCommand(CMD_DATA_END);
reset();
}catch(IOException e){
@ -148,7 +132,7 @@ public class SMTPClient {
*/
public synchronized int sendCommand(String cmd) throws IOException{
logger.finest(">> "+cmd);
out.print(cmd + NEWLINE);
out.write(cmd + NEWLINE);
String reply = readCommand();
return parseReturnCode(reply);
}