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

Envelope senders for Grails mail plugin (Spring Java Mail)

I would have expected the desire to set a specific envelope sender address for mails from a web-app to be fairly common. However finding information on how to do it with the Grails mail plugin (ie Spring mail (wrappers for JavaMail)) proved much harder than I expected.

In fact, I ended up reading the source code!

It turns out that setting a single, application wide envelope sender is pretty easy (and is actually documented in various places). Simply set a value in Config.groovy such as:

grails.mail.smtp.from = "envelope@domain.com"

In my case though, I was looking to implement VERP for a mailing list, so that wasn't suitable.

From reading the source I discovered that the JavaMail SMTPTransport would actually check if the message it was given was an SMTPMessage and would respect the envelopeFrom property if it was.

To take advantage of this but still make use of the message builder from the mail plugin, I wrote a small service that wraps around the normal mailService:

import com.sun.mail.smtp.SMTPMessage
import javax.mail.internet.MimeMessage
import org.springframework.mail.MailMessage
import org.springframework.mail.javamail.MimeMailMessage
import org.grails.mail.MailMessageBuilder

class AdvancedMailService {
    static transactional = false

    def mailService
    def mailSender

    MailMessage sendMail(String envelopeFrom, Closure callable) {
        def messageBuilder = new MailMessageBuilder(mailService, mailSender)
        callable.delegate = messageBuilder
        callable.resolveStrategy = Closure.DELEGATE_FIRST
        callable.call()

        def message = messageBuilder.createMessage()
        mailService.initMessage(message)
        MimeMessage mimeMsg
        if(message instanceof MimeMailMessage)
            mimeMsg = message.getMimeMessage()
        else
            mimeMsg = message

        SMTPMessage smtpMsg = new SMTPMessage(mimeMsg)
        smtpMsg.envelopeFrom = envelopeFrom

        mailService.sendMail(smtpMsg)
        return message
    }
}

You have to call it as a specific service, but otherwise it's much the same as the normal mail service, eg:

advancedMailService.sendMail("list-recipient=theirdomain.com@domain.com") {
    from 'Mailing List <list@domain.com>'
    to "recipient@theirdomain.com"
    subject "Test mail"
    body(view: "/mails/test1", model: model)
    headers([
        'Precedence': 'bulk',
    ])
}

Now I just need to set something up to process the bounces. I wonder how easy it would be to embed James!?

Update: revised approach, complete with patch sent to grails-mail plugin.

Update: I didn't use James, but I did finally accept SMTP mail in Grails.

Comments

On Sept. 2, 2010, 8:46 p.m. Helga said...

I'm about to implement VERP style bounce handling as well and found your post really useful. I'd go even further and let the service construct the envelop from the addressses. Did you think about contributing to the mail plugin? I think setting the envelop address is general functionality worth having there. It's easy to contribute as the grails-mail plugins sources have moved to github recently: http://github.com/gpc/grails-mail Just fork, tweak and issue a pull request.

On Sept. 22, 2010, 9:42 a.m. Simon said...

Yep, in the age of git, I really should do that. I've sorted an account at github and forked the mail plugin. I need to adjust my code and do some testing, then I'll see what happens to a pull request.

Add a comment