5

I'm trying to use Greenmail to unit test email functions on my localhost. The problem is that I don't have a SMTP server installed already, and feels it over-killing to install one. My expectation is that there should be a free library that allow me keep my sending mail code the same, but instead of truly sending email to a SMTP server, send it to my local machine so that I can retrieve them (for the sake of unit testing).

I once used Greenmail when developing with Grails,and the experience is great. But I can't find something similar for Spring Framework. In Greenmail page, it says that there's a mocking SMTP server bundled with JBoss. But I don't want to run JBoss, since currently my web application is running on Tomcat.

Is there any similar service for Tomcat already? Or are there any better way to send test email to localhost, where I can retrieve the emails sent?

UPDATE:

I tried using Ralph's method, but it still yield the same exception:

[SimpleAsyncTaskExecutor-1] 2012-03-13 10:19:39,475 - ERROR: com.test.my.service.emailing.impl.EmailServiceImpl - Mail server connection failed; nested exception is javax.mail.MessagingException: Could not connect to SMTP host: localhost, port: 3025;
  nested exception is:
    java.net.ConnectException: Connection refused: connect. Failed messages: javax.mail.MessagingException: Could not connect to SMTP host: localhost, port: 3025;
  nested exception is:
    java.net.ConnectException: Connection refused: connect
org.springframework.mail.MailSendException: Mail server connection failed; nested exception is javax.mail.MessagingException: Could not connect to SMTP host: localhost, port: 3025;
  nested exception is:
    java.net.ConnectException: Connection refused: connect. Failed messages: javax.mail.MessagingException: Could not connect to SMTP host: localhost, port: 3025;
  nested exception is:
    java.net.ConnectException: Connection refused: connect; message exception details (1) are:
Failed message 1:
javax.mail.MessagingException: Could not connect to SMTP host: localhost, port: 3025;
  nested exception is:
    java.net.ConnectException: Connection refused: connect
    at com.sun.mail.smtp.SMTPTransport.openServer(SMTPTransport.java:1391)
    at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:412)
    at javax.mail.Service.connect(Service.java:288)
    at org.springframework.mail.javamail.JavaMailSenderImpl.doSend(JavaMailSenderImpl.java:389)
    at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:340)
    at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:336)
    at com.test.my.service.emailing.impl.EmailServiceImpl.test(EmailServiceImpl.java:388)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:309)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.interceptor.AsyncExecutionInterceptor$1.call(AsyncExecutionInterceptor.java:80)
    at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
    at java.util.concurrent.FutureTask.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
Caused by: java.net.ConnectException: Connection refused: connect
    at java.net.PlainSocketImpl.socketConnect(Native Method)
    at java.net.PlainSocketImpl.doConnect(Unknown Source)
    at java.net.PlainSocketImpl.connectToAddress(Unknown Source)
    at java.net.PlainSocketImpl.connect(Unknown Source)
    at java.net.SocksSocketImpl.connect(Unknown Source)
    at java.net.Socket.connect(Unknown Source)
    at java.net.Socket.connect(Unknown Source)
    at com.sun.mail.util.SocketFetcher.createSocket(SocketFetcher.java:233)
    at com.sun.mail.util.SocketFetcher.getSocket(SocketFetcher.java:189)
    at com.sun.mail.smtp.SMTPTransport.openServer(SMTPTransport.java:1359)
    ... 19 more
Hoàng Long
  • 10,746
  • 20
  • 75
  • 124

5 Answers5

16

You can use Greenmail with any Java Program, no matter if it is using Spring or not. You do not need any Spring specific stuff for it.

It run some kind of in process mail server.

import com.icegreen.greenmail.util.GreenMail;
import com.icegreen.greenmail.util.GreenMailUtil;
import com.icegreen.greenmail.util.ServerSetupTest; ...

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("ApplicationContext-Greenmail.xml")
public class EmailServiceIntegrationTest {

    /** Class under test */
    @Resource
    private EmailService emailService;

    private GreenMail greenMail;

    @Before
    public void startMailServer() {
        greenMail = new GreenMail(ServerSetupTest.SMTP);
        greenMail.start();
    }

    @After
    public void stopMailServer() {
        greenMail.stop();
    }

    @Test
    public void testPledgeReminder()
                throws InterruptedException, MessagingException {

        String mailText = "Hallo World";
        String mailSubject = "Hallo";
        String mailTo = "test@excaple.com";

        /** when: sending a mail */
        emailService.send(mailSubject, mailTo, mailText);

        assertTrue(greenMail.waitForIncomingEmail(5000, 1));
        Message[] messages = greenMail.getReceivedMessages();
        assertEquals(1, messages.length);
        assertEquals(mailText, messages[0].getSubject());       
        String body = GreenMailUtil.getBody(messages[0]).replaceAll("=\r?\n", "");
        assertEquals(mailText, body);       
    }

}

important: use port 3025

<bean id="javaMailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
    <property name="javaMailProperties">
        <util:properties>
            <prop key="mail.debug">false</prop>
            <prop key="mail.transport.protocol">smtp</prop>
            <prop key="mail.smtp.port">3025</prop>
            <prop key="mail.smtp.auth">true</prop>
            <prop key="mail.smtp.user">test@mail.extern</prop>
            <prop key="mail.smtp.host">localhost</prop>
            <prop key="mail.smtp.from">test@mail.extern</prop>
        </util:properties>
    </property>
    <property name="username" value="test"/>
    <property name="password" value="xxx"/>
    <property name="defaultEncoding" value="utf8" />
</bean>

Then this configuration will configure a Spring JavaMailSender to send its mails to the GreenMail-Server started and finished by the test code.

Ralph
  • 118,862
  • 56
  • 287
  • 383
2

Edit (2017 Nov):

Dumbster link is dead, there is a fork of it on github https://github.com/kirviq/dumbster

---- Original message ----

Have a look at Dumbster - I use it for all my unit testing, as it allows me to assert against the actual emails sent out.

http://quintanasoft.com/dumbster/

Ivar
  • 4,350
  • 2
  • 27
  • 29
TrueDub
  • 5,000
  • 1
  • 27
  • 33
  • 1
    I would prefer greenmail since I had good experience with it on Grails. But if things won't work I'll give Dumbster a try. Thanks! – Hoàng Long Mar 13 '12 at 03:33
1

Try to set GreenMail server's port manually like this:

 @Before
public void startMailServer()
    throws Exception
{
    ServerSetup setup = new ServerSetup(3025,"localhost","smtp");
    greenMail = new GreenMail(setup);
    greenMail.start();
}

and then set your email sender's port the same as above, pay attention to protocol/host/port:

email.protocol=smtp
email.host=localhost
email.port=3025
email.username=to@localhost.com
email.password=to@localhost.com
email.auth=true
email.systemEmail=from@localhost.com

with bean configuration:

<bean id="javaMailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
    <property name="protocol" value="${email.protocol}" />
    <property name="host" value="${email.host}" />
    <property name="port" value="${email.port}" />
    <property name="username" value="${email.username}" />
    <property name="password" value="${email.password}" />
    <property name="javaMailProperties">
        <props>
            <prop key="mail.${email.protocol}.auth">${email.auth}</prop>
        </props>
    </property>
</bean>
0

Doing something like this in a spring test works fine for me:

ServerSetupTest.setPortOffset(<SOME_CUSTOM_PORT>);
testEmailServer = new GreenMail();
testEmailServer.start();

The main idea behind the ServerSetupTest class is to create a ServerSetup with a user-defined port offset for testing. See the docs for more details.

leeor
  • 17,041
  • 6
  • 34
  • 60
0

It seems that someone once proposed such integration : http://sourceforge.net/mailarchive/forum.php?thread_name=45DEB9E3.6090608%40consol.de&forum_name=greenmail-developers

Don't know if it's still working...

ndeverge
  • 21,378
  • 4
  • 56
  • 85
  • Thanks, but you seems misunderstand what I need. I want to use JavaMail, but somehow configure greenmail to receive the emails. By that way I don't need to change the code back and forth (switching for Greenmail class when testing, and switch back to JavaMail to send real emails in production) – Hoàng Long Mar 13 '12 at 03:32