Pither.com / Simon
Development, systems administration, parenting and business

Add an SMTP server to a Grails application

Quite a long time ago I talked about setting envelope sender addresses so that I could send mailshots and get back any bounces in a useful way. The missing component to it was to process those bounces within my application. Here, finally, is my write up of how I did this.

After much searching I eventually found the excellent SubEtha SMTP project which made including an SMTP server within my Grails application incredibly easy. Just four simple steps are required...

Include the library (grails-app/conf/BuildConfig.groovy):

dependencies {
    compile('org.subethamail:subethasmtp:3.1.4') {
        excludes 'mail'
    }
}

Write a SubEtha message listener (for me: src/groovy/com/supajam/smtp/MessageListener.groovy):

package com.supajam.smtp;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.subethamail.smtp.TooMuchDataException;
import org.subethamail.smtp.helper.SimpleMessageListener
import com.supajam.BounceRecord

public class MessageListener implements SimpleMessageListener {
    private final static Logger log = LoggerFactory.getLogger(MessageListener.class);

    public boolean accept(String from, String recipient) {
        return true;
    }

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

        // I use this to process bounce messages, but it's just an
        // email message that could be processed however you like

        BounceRecord.withTransaction {
            if (log.isDebugEnabled())
                log.debug("Processing mail from " + from + " to " + recipient);

            // The regex on the next line is specific to my VERP scheme
            def origAddr = recipient =~ /-(.+=.+)@/

            if(origAddr && origAddr[0].size() > 1) {
                // here I extract the source address, ensure it's
                // valid, record the bounce and remove the address
                // from the mailing list.
            }
        }
    }
}

I've included an outline of the code that I actually use to process incoming email - all of which I know will be bounce messages. There's nothing to force this use though, it's just a generic way to receive emails into an application.

Wire it together with Spring (grails-app/conf/spring/resources.groovy):

beans = {
    // Create an in-process SMTP server for processing bounces
    smtpMessageListener(com.supajam.smtp.MessageListener)

    smtpMessageListenerAdapter(org.subethamail.smtp.helper.SimpleMessageListenerAdapter, ref('smtpMessageListener'))

    smtpServer(org.subethamail.smtp.server.SMTPServer, ref('smtpMessageListenerAdapter')) {
        port = 2500
        hostName = "my.server.name"
        disableTLS = true
        maxConnections = 10
    }
}

To avoid running my grails application as root, I set the SMTP port to a high number (2500 in this example). Getting emails delivered to such a port is beyond this post (but personally I use iptables redirects).

Finally, make it run at application start (grails-app/conf/BootStrap.groovy):

class BootStrap {
    def smtpServer

    def init = { servletContext ->

        log.debug("Starting SMTP server")
        try {
            smtpServer.start()
        }
        catch(Exception e) {
            // Starting the web application is more important
            // than SMTP, so just log the failure and carry on
            log.error("SMTP server could not be started")
        }
    }

    def destroy = {
        log.debug("Stopping SMTP server")
        smtpServer.stop()
    }
}

I guard the SMTP server start just in case there's a problem. No SMTP server is a nuisance but no web application is very bad. Just for cleanliness I also attempt to stop it in the destroy method.

That's it! It really is that simple to have a full SMTP server running within grails and ready to accept and process incoming email.

Comments

On Sept. 28, 2011, 8 p.m. crazy4groovy said...

Cool! Send emails as well? http://code.google.com/p/subethasmtp/wiki/SimpleExample

On Sept. 29, 2011, 6:19 p.m. Simon said...

Sending email from Grails is easiest (and very flexible) with the mail plugin: http://grails.org/plugin/mail

Or if you want the ability to control the envelope address to catch bounces, then see my post: http://www.pither.com/articles/2011/03/13/grails-mail-patch-for-envelopefrom-verp

On Aug. 30, 2012, 7:26 a.m. Sanjay Mysoremutt said...

This sounds great! I came here looking for a simple way to test sending of emails, and I found Dumbster good enough as well for that purpose, but was inspired by this post - thanks!

Add a comment