Recent Posts
Archives

PostHeaderIcon Fake SMTP server in Java

Abstract

You need a fake SMTP server, for any reason: either your application does not deploy without an SMTP, or you need see what mails are sent and their attached files, etc.

You will need the code below (one Java class, possibly one propery file and Log4J config file) and following jars: subethasmtp.jar, available on GoogleCode, and Apache Commons Lang commons-lang.jar.

Main class: FakeSMTP

[java]
package jonathan.the.cowboy;

import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.log4j.Logger;
import org.subethamail.wiser.Wiser;

import javax.mail.MessagingException;
import javax.mail.Part;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.Properties;

/**
* This class emulates an SMTP server. It is useful to check a mail is sent, mail traffic is logged.
* <br/>
* To use it in tests, simply complete properties file, then launch the main.
* In WebLogic console, take care to point to the host and ports written in properties files, for instance:
* <pre>
* body=no body,mail.smtp.port=25,mail.transport.protocol=smtp,
* subject=no subject,mail.smtp.host=localhost,mail.host=localhost,from=Jonathan.Lalou@myDomainMail.com
* </pre>
* @author Jonathan Lalou http://jonathan.lalou.free.fr
*/
public class FakeSMTP {
private static final Logger LOGGER = Logger.getLogger(FakeSMTP.class);
private static final String SVN_ID = "$Id$";

private static final String CONFIG_FILE = "jonathan/the/cowboy/fakeSmtp.properties";
private static final String HOST_PROPERTY = "fakeSmtp.host";
private static final String PORT_PROPERTY = "fakeSmtp.port";

private static final String LIFESPAN_PROPERTY = "fakeSmtp.lifeSpan";
private static final int nDEFAULT_PORT = 25;
private static final String szDEFAULT_HOST = "localhost";
private static final boolean PRINT_MESSAGES_ON_OUTPUT = true;

/**
* Life span in seconds
*/
private static final Integer nDEFAULT_LIFE_SPAN = 300;

private Integer lifeSpan;

private Wiser wiser;

private FakeSMTP() {
final Properties properties;
final Integer theoricalLifeSpan;

properties = loadProperties();
wiser = new MyWiser();

wiser.setHostname(null == properties.getProperty(HOST_PROPERTY)
? szDEFAULT_HOST :
properties.getProperty(HOST_PROPERTY));
wiser.setPort(null == properties.getProperty(PORT_PROPERTY)
? nDEFAULT_PORT
: Integer.parseInt(properties.getProperty(PORT_PROPERTY)));
theoricalLifeSpan = null == properties.getProperty(LIFESPAN_PROPERTY)
? nDEFAULT_LIFE_SPAN
: Integer.parseInt(properties.getProperty(LIFESPAN_PROPERTY));
this.setLifeSpan(Math.min(3600, theoricalLifeSpan)); // we take at most 6h

LOGGER.info("Host: " + wiser.getServer().getHostName());
LOGGER.info("Port: " + wiser.getServer().getPort());
LOGGER.info("LifeSpan: " + this.getLifeSpan() + " seconds");
if (LOGGER.isDebugEnabled()){
LOGGER.debug(SVN_ID);
}
}

public void run() {
final Long t0;

t0 = System.currentTimeMillis();
LOGGER.info("FakeSMTP started at: " + new Date(t0).toString());
try {
LOGGER.info("Starting FakeSMTP");
wiser.start();
while ((System.currentTimeMillis() – t0) < (getLifeSpan() * 1000)) ;
} catch (Exception e) {
if (null != wiser)
wiser.stop();
LOGGER.info("Stopped FakeSMTP");
}
LOGGER.info("FakeSMTP ended at: " + new Date(System.currentTimeMillis()).toString());
wiser = null;
System.exit(0);
}

private Properties loadProperties() {
final ClassLoader classLoader = FakeSMTP.class.getClassLoader();
final InputStream inputStream;
final Properties properties;
inputStream = classLoader.getResourceAsStream(CONFIG_FILE);
properties = new Properties();
if (null == inputStream)
LOGGER.info("Could not find ‘" + CONFIG_FILE + "’ in classpath.");
else
try {
properties.load(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
return properties;
}

public static void main(String[] args) {
new FakeSMTP().run();
}

public Integer getLifeSpan() {
return lifeSpan;
}

public void setLifeSpan(Integer lifeSpan) {
this.lifeSpan = lifeSpan;
}

String convertContentMimeMessage(MimeMessage mimeMessage) throws MessagingException, IOException {

Object content = mimeMessage.getContent();
MimeMultipart contentMP = (MimeMultipart) content;
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < contentMP.getCount(); i++) {
Part part = contentMP.getBodyPart(i);
buffer.append(new Date().toString()).
append("[start part ").
append(i).append("]").
append(part.getContent()).
append("[end part ").
append(i).append("]");
}
return buffer.toString();
}

class MyWiser extends Wiser {

public void deliver(String from, String recipient, InputStream data) throws IOException {

if (!PRINT_MESSAGES_ON_OUTPUT) {
super.deliver(from, recipient, data);
return;
}

try {
MimeMessage message = new MimeMessage(getSession(), data);
System.out.println("Subject: " + message.getSubject());
System.out.println("[Start recipients]: " + ToStringBuilder.reflectionToString(message.getAllRecipients()) + "[End recipients]");
System.out.println("[Start body]" + convertContentMimeMessage(message) + "[End body]");
} catch (MessagingException e) {
throw new RuntimeException(e);
}
}
}
}
[/java]

Property file:

# Default values:
fakeSmtp.host=localhost
fakeSmtp.port=25
fakeSmtp.lifeSpan=300

Run

You have only to run the main() method.

Comments are closed.