Testing JavaMail applications is more difficult than necessary, because it involves a lot of setup outside the test program. Doing this correctly in a portable way so that anyone in your team can run the test is almost impossible.
Mock JavaMail comes to the rescue. This project takes advantage of pluggability in JavaMail, so that you can send/receive e-mails against a temporary in-memory "mailbox". For example, when this JAR is in your classpath, the following code that normally sends e-mail to me actually just sends the e-mail to an in-memory mailbox:
MimeMessage msg = new MimeMessage();
...
msg.setRecipients(TO,"first.last@example.com");
Transport.send(msg);
You can access this e-mail programatically like this:
List<Message> inbox = Mailbox.get("first.last@example.com");
assertEquals(inbox.size(),1); // was the e-mail really sent?
You can also directly add messages to this list to emulate e-mails in the inbox, instead of using the JavaMail API. Staging e-mails like this is useful for testing the server.
Similarly you can access these e-mails programatically by using JavaMail, just like you normally do:
Session session = ...;
Store store = session.getStore("pop3"); // imap would do, too
// connect to first.last@example.com mailbox
store.connect("example.com","first.last","anything");
Folder folder = store.getFolder("INBOX");
folder.open(Folder.READ_WRITE);
Message[] msgs = folder.getMessages();
This allows you to test both the sending side and receiving side. All you need to do is to drop the JAR in the classpath during the test.
This library works thanks to the JavaMail API which allows to use different providers implementation to handle actual email sending.
To ensure it’s used in your tests, you need to define the following Java system properties:
mail.smtp.class
-
set to
org.jvnet.mock_javamail.MockTransport
mail.pop3.class
-
set to
org.jvnet.mock_javamail.MockStore
mail.imap.class
-
set to
org.jvnet.mock_javamail.MockStore
This can be done either manually or via a configuration in your test runner.
For example, with Maven this can be done with the following configuration:
<project>
[…]
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<mail.smtp.class>org.jvnet.mock_javamail.MockTransport</mail.smtp.class>
<mail.pop3.class>org.jvnet.mock_javamail.MockStore</mail.pop3.class>
<mail.imap.class>org.jvnet.mock_javamail.MockStore</mail.imap.class>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
</project>
Mailbox
can be marked as 'error' programatically, which causes all sending/receiving operations to fail.
This can be used to test the error handling behavior of the application.
Mailbox inbox = Mailbox.get("first.last@example.com");
inbox.setError(true);