Mock Javamail primer

Small primer for mock javamail, a pretty useful project that will be handy whenever you need to test code that uses POP3/IMAP/SMTP and you wouldn't like to build wrappers for anything you need to test - javamail does not really offer interfaces that can be implemented by mock objects, but different implementations can be used at runtime depending on which jars are on the classpath.

Take a look at the project homepage:

http://java.net/projects/mock-javamail

Be sure you've enabled java.net Maven repo, and add this dependency to your pom.xml:

1         <dependency>

2 <groupId>org.jvnet.mock-javamail</groupId>

3 <artifactId>mock-javamail</artifactId>

4 <version>1.9</version>

5 <scope>test</scope>

6 </dependency>

You're almost ready; now setup your test code this way:

 1 public class IMAPMailRepositoryTest {

2 @Before

3 public void setUp() throws Exception {

4 final Session session = Session.getInstance(

5 System.getProperties());

6

7
MimeMessage msg = new MimeMessage(

8 session);

9 msg.setRecipients(Message.RecipientType.TO,

10 "testuser@mockserver.com");

11 msg.setSubject("Some Subject");

12 msg.setText("sometext");

13 Transport.send(msg);

14 }

15

16
@After

17 public void tearDown() throws Exception {

18 Mailbox.clearAll();

19 }



Now you're ready to use your mock javamail:

 1 public class SomeImapClient {

2

3
private static Logger log = Logger.getLogger(SomeImapClient.class);

4

5
public void processMail() {

6 try {

7 Session session = getMailSession();

8 Store store = connect(session);

9 Folder folder = openMailFolder(store);

10 findContent(folder);

11 } catch (MessagingException e) {

12 throw new RuntimeException(e);

13 } catch (IOException e) {

14 throw new RuntimeException(e);

15 }

16

17
}

18

19
public Session getMailSession() {

20 Properties props = System.getProperties();

21 props.setProperty("mail.store.protocol", "imaps");

22 props.setProperty("mail.imap.partialfetch", "0");

23

24
log.debug("Getting session");

25 return Session.getDefaultInstance(props, null);

26

27
}

28

29
public Store connect(Session session) throws MessagingException {

30 log.debug("getting the session for accessing email.");

31 Store store = session.getStore("imap");

32

33
store.connect("mockserver.com", "testuser", "somepassword");

34 log.debug("Connection established with IMAP server.");

35 return store;

36 }

37

38
public Folder openMailFolder(Store store) throws MessagingException {

39 Folder folder = store.getDefaultFolder();

40 folder = folder.getFolder("inbox");

41 folder.open(Folder.READ_ONLY);

42 return folder;

43 }

44

45
public void findContent(Folder folder) throws MessagingException, IOException {

46 for (Message m : folder.getMessages()) {

47 log.debug(m.getSubject());

48

49
}

50

51

52
}

53

54

55
}


Output is:

DEBUG 30 Aug 2011 19:25:25 SomeImapClient:32 - Getting session
DEBUG 30 Aug 2011 19:25:25 SomeImapClient:38 - getting the session for accessing email.
DEBUG 30 Aug 2011 19:25:25 SomeImapClient:42 - Connection established with IMAP server.
DEBUG 30 Aug 2011 19:25:25 SomeImapClient:55 - Some Subject


Some small gotchas:

  • your store.connect("example.com", "username", "anything") must match your "username@example.com" addressee in msg.setRecipients; different addressees will yield multiple mailboxes.
  • Only works for plain imap & pop3 mailboxes. Even though it doesn't make a lot of sense to use SSL on a mock mailbox, if you try getting the "imaps" store you'll get an error as a real implementation of javamail will be employed.
  • I'd always advise to use such tearDown() when doing unit tests, since the Session seems global and different tests could interfere with different contents - unless you use a different fake user/test server url in each of your tests.