Search code examples
javaspringemailgreenmail

Testing Greenmail without installing a SMTP server


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

Solution

  • 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 = "[email protected]";
    
            /** 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">[email protected]</prop>
                <prop key="mail.smtp.host">localhost</prop>
                <prop key="mail.smtp.from">[email protected]</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.