Using GMail with a Log4j SMTP Appender in Grails

I saw a plaintive wail on Twitter about using GMail as the smtp server to send error emails using a Log4j SMTPAppender in Grails. It turned out to be a little tricky (and a bigger solution than 140 characters would allow) so I thought I’d describe the process here.

Most of the properties are configurable as appender attributes (e.g. server name, auth username, etc.) but two important ones aren’t. SMTPAppender creates a Properties instance with System.getProperties() as the default values and adds smtp properties to that. But you need to specify the smtp port (it will default to 25 otherwise) and you need to tell it to send a STARTTLS command. Both are configurable via system properties:

System.setProperty 'mail.smtp.port', '587'
System.setProperty 'mail.smtp.starttls.enable', 'true'

and if you add those calls to Config.groovy before the appender is instantiated then it will have the values available when it configures its JavaMail Session:

import org.apache.log4j.Level
import org.apache.log4j.net.SMTPAppender

...

mail.error.server = 'smtp.gmail.com'
mail.error.port = 587
mail.error.username = 'your.email@gmail.com'
mail.error.password = 'yourpassword'
mail.error.to = 'to@yourapp.com'
mail.error.from = 'from@yourapp.com'
mail.error.subject = '[Application Error]'
mail.error.starttls = true
mail.error.debug = false

environments {
   production {
      grails.serverURL = "http://www.changeme.com"
   }
   development {
      grails.serverURL = "http://localhost:8080/${appName}"
   }
   test {
      grails.serverURL = "http://localhost:8080/${appName}"
   }
}

log4j = {

   System.setProperty 'mail.smtp.port', mail.error.port.toString()
   System.setProperty 'mail.smtp.starttls.enable', mail.error.starttls.toString()

   appenders {

      appender new SMTPAppender(name: 'smtp', to: mail.error.to, from: mail.error.from,
         subject: mail.error.subject, threshold: Level.ERROR,
         SMTPHost: mail.error.server, SMTPUsername: mail.error.username,
         SMTPDebug: mail.error.debug.toString(), SMTPPassword: mail.error.password,
         layout: pattern(conversionPattern:
            '%d{[ dd.MM.yyyy HH:mm:ss.SSS]} [%t] %n%-5p %n%c %n%C %n %x %n %m%n'))
   }

   error  'org.codehaus.groovy.grails.web.servlet',  //  controllers
          'org.codehaus.groovy.grails.web.pages', //  GSP
          'org.codehaus.groovy.grails.web.sitemesh', //  layouts
          'org.codehaus.groovy.grails.web.mapping.filter', // URL mapping
          'org.codehaus.groovy.grails.web.mapping', // URL mapping
          'org.codehaus.groovy.grails.commons', // core / classloading
          'org.codehaus.groovy.grails.plugins', // plugins
          'org.codehaus.groovy.grails.orm.hibernate', // hibernate integration
          'org.springframework',
          'org.hibernate',
          'net.sf.ehcache.hibernate'
   warn   'org.mortbay.log'

   root {
      error 'stdout', 'smtp'
      additivity = true
   }
}

I’ve parameterized the properties to make them configurable for each environment or using an external configuration file.

Note that GMail has a limit of 500 emails per day, so if you generate a lot of errors in your app you could hit that limit.

9 Responses to “Using GMail with a Log4j SMTP Appender in Grails”

  1. Great Burt!

    This would give a nice, tiny, and useful plugin 🙂

    :]

  2. Wolfgang says:

    Hi Burt,

    nice trick!

    FYI: some parts of your code example (e.g. ‘appender new SMTPAppender’) are not visible in my browser (Safari 4 on OSX Snow Leopard), Firefox shows them without problem. Maybe a rendering problem or text and bgcolor are too similar to white…

  3. Tom says:

    Careful. If your SMTP server goes down, you may run into a thread deadlock scenario. This happened to me last year. My SMTP server went down and all threads that used log4j locked up because the one thread that tried to send an email was blocking them.

  4. Burt says:

    @Tom I agree, there are lots of things that can go wrong. A few months ago we were running a batch process that got stuck and I ended up with over 2000 emails in my inbox before we killed the process. A custom appender that queues and sends asynchronously and potentially batches messaages would have helped a lot there and could address server availability issues too.

  5. Scott Davis says:

    Burt – strong work! This works exactly as advertised. Thx. (BTW, my new nickname is now ‘plaintive wail’… grin)

  6. […] GMail with a Log4j SMTP Appender in Grails Very useful blog entry about Using GMail with a Log4j SMTP Appender in Grails containing log4j SMTP Appender […]

  7. Chris Fraser says:

    FYI, when upgrading to Grails 2, in order to get at the config params within the log4j block, you have to append “config.” to the param name. So in Burt’s example above, “mail.error.to” becomes “config.mail.error.to”, “mail.error.from” becomes “config.mail.error.from”, etc.

  8. eeezyy says:

    @Chris, thanks for your comment, it helped me avoid a lot of stress. But my current Grails version is 1.3.7 and it just worked with the config-“prefix”

  9. Roshini says:

    Hi

    Need to ask if it works for all unhandled exceptions or only those which are marked by log.error ?

Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 License.