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
Cool! Send emails as well? http://code.google.com/p/subethasmtp/wiki/SimpleExample
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
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!