Search code examples
emailgrailsconfigurationgrails-plugin

Grails mail plugin delivery to console / log in development mode


I am using Grails with the mail plugin. In development mode I would like the mails my applications sends to be rendered (to catch bugs in the templates) but printed to the console.

The only option I found was

grails.mail.disabled=true

But, according to the documentation:

this will treat any call to mailService.sendMail() as a no-op

which is not quite what I want, since I want developers to be able to click on our confirmation links (for which I need the mail output).

Is there a nice way to "deliver" the mails to the console? I am aware that I could override the to-field with another address, but I'd rather not involve our mailserver when testing.


Solution

  • You could create your own dummy implementation of mailService as a class in src/groovy and then put some conditional code in grails-app/conf/spring/resources.groovy to define your dummy service only in development mode. The very simplest I can think of would be

    src/groovy/com/example/DummyMailService.groovy

    package com.example
    import org.springframework.mail.MailMessage
    
    class DummyMailService {
      MailMessage sendMail(Closure callable) {
        callable.delegate = new CallPrinter()
        callable.call()
        return null
      }
    }
    
    class CallPrinter {
      def methodMissing(name, args) {
        println "${name}: ${args}"
      }
    }
    

    grails-app/conf/spring/resources.groovy

    import grails.util.Environment
    
    beans = {
      if(Environment.current == Environment.DEVELOPMENT) {
        mailService(com.example.DummyMailService)
      }
    }
    

    Obviously you could be cleverer, e.g. using a logger rather than println, or switching the dummy service based on a config option rather than just the environment (so you can turn on mail in dev mode later on when you specifically want to test it).

    If you want to be able to handle body(view:'...', model:[:]) calls that render templates you could do that using the groovyPageRenderer:

    class DummyMailService {
      def callPrinter
    
      MailMessage sendMail(Closure callable) {
        callable.delegate = callPrinter
        callable.call()
        return null
      }
    }
    
    class CallPrinter {
      def groovyPageRenderer
    
      def methodMissing(name, args) {
        println "${name}: ${args}"
      }
    
      void body(Map params) {
        methodMissing("body", groovyPageRenderer.render(params))
      }
    }
    

    and in resources.groovy

    mailService(com.example.DummyMailService) {
      callPrinter = { com.example.CallPrinter p ->
        groovyPageRenderer = ref('groovyPageRenderer')
      }
    }