ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Using Groovy to Send Emails
Pages: 1, 2, 3

Towards a DSL: Groovy + Ant

Groovy also provides Ant integration through its AntBuilder class. This class follows a special DSL-style pattern of coding supported by Groovy's built-in builder facilities and bundled builder classes. Builders are most useful for creating any kind of nested data structure, whether this be a straight XML file, a hierarchical object structure, or nested widgets in a GUI. AntBuilder builds Ant projects that contain a nested set of build instructions. It interfaces directly with the Ant API, so the normal Ant XML build file is skipped altogether. The advantage is that AntBuilder code tends to be less verbose than the equivalent XML and can make use of Groovy features such as conditional statements and loops, as during construction of the Ant project.



Ant supports sending emails through its mail task. Here is what our code looks like:

port = 1025
fixture = new EmailFixture(port)

ant = new AntBuilder()
ant.mail(mailhost:'localhost', mailport:"$port",
         subject:'Successful build'){
    from(address:'cruise@mycompany.org')
    cc(address:'partners@mycompany.org')
    to(address:'devteam@mycompany.org')
    message("Successful build for ${new Date()}")
}

fixture.assertEmailArrived(from:'cruise@mycompany.org',
                           subject:'Successful build')

Writing this class was the easiest of all the solutions and has yielded short, easy-to-maintain code. But we could do a lot more if we wanted. Suppose we wanted to send attachments of the build artifacts along with our notification email. Also suppose we wanted the content of the message to be HTML instead of the simple text content used in previous examples. Sound like a lot of work? It really isn't. Here is what the result would look like:

results = [Unit: '898 Tests, 0 Failures, 0 Errors',
           Integration: '45 Tests, 0 Failures, 0 Errors',
           Acceptance: '75 Tests, 0 Failures, 1 Errors']
ant = new AntBuilder()
writer = new StringWriter()
today = new Date()
allOk = results.every{ entry ->
    entry.value.contains(' 0 Errors') &&
    entry.value.contains(' 0 Failures')
}
new groovy.xml.MarkupBuilder(writer).html {
    body {
        h1(allOk ? 'Successful' : 'Failed' + " build for $today")
        table {
            tr {
                th('Test Suite'); th('Result')
            }
            results.each { suite, result ->
                numbers = result.split('').grep(~/\d| /).join()
                passed = numbers.endsWith('0  0 ')
                tr {
                    td(suite)
                    td(bgcolor: passed?'green':'red', result)
                }
            }
        }
    }
}
ant.mail(mailhost:'localhost', messagemimetype:'text/html',
         subject:"Build notification for $today"){
    from(address:'cruise@mycompany.org')
    to(address:'devteam@mycompany.org')
    cc(address:'partners@mycompany.org')
    message(writer)
    attachments(){
        fileset(dir:'dist'){
              include(name:'**/*.zip')
        }
    }
}

Here, build results would typically be extracted from logfiles; for our purposes, we just used a list. We have also ignored the test fixture (but see the next section, where we change the test fixture to use a real email server).

If you point this to a real mail server, you will receive an email similar to the one shown in Figure 1.

Screenshot of received Email
Figure 1. Screenshot of received email

A Testing Epilogue

To wrap up, we are going to look at testing our code against a real email server instead of the Wiser mock server. We'll simply replace the code inside our email fixture with code to access a real email server using the POP3 protocol. We'll use the Canoo WebTest open source testing tool. It is written as an Ant extension, so we can follow the same coding style as shown for sending our email via Ant. Here is what the result would look like:

def ant = new AntBuilder()

def webtest_home = System.properties.'webtest.home'

ant.taskdef(resource:'webtest.taskdef'){
    classpath(){
       pathelement(location:"$webtest_home/lib")
       fileset(dir:"$webtest_home/lib", includes:"**/*.jar")
    }
}

ant.testSpec(name:'Email Test'){
    steps {
        emailSetConfig(server:'localhost', password:'password',
            username:'devteam@mycompany.org', type:'pop3')
        emailStoreMessageId(subject:'/Build notification/',
            property:'msg')
        emailStoreHeader(property:'subject',
            messageId:'#{msg}', headerName:'Subject')
        groovy('''def subject = step.webtestProperties.subject
            assert subject.startsWith('Build notification')''')
        emailMessageContentFilter(messageId:'#{msg}')
        verifyText(text:'Failed build')
    }
}

Some points of interest:

  • The '/' symbols surrounding 'Build notification' indicate to WebTest that we should match as a regular expression (ignoring the changing date part of the subject in our case).
  • WebTest makes heavy use of dynamic properties, e.g., msg is used to store the message id of the message we are interested in. The syntax #{msg} is used to refer to the stored id to distinguish it from Ant properties prefixed with the '$' symbol.
  • The groovy step allows you to run Groovy code from within any Ant script. So here, we are calling Groovy to Ant back to Groovy again. We don't need to here (because we are in Groovy, so we can just write Groovy code), but this illustrates that we can.

That wraps up our quick tour of some of the common ways to send emails. I certainly haven't tried to provide you with an exhaustive list of ways to send emails from Groovy. For instance, you could use platform-specific means just as easily if portability across platforms is not a high priority. As an example, on Windows, you could write some code that uses Groovy's Scriptom module to talk directly to Outlook and ask it to send an email for you.

Conclusion

Groovy allows you to send emails easily. This isn't because the Groovy language designers particularly set out to make this task easy but because they designed into the language a cohesive set of features that can leverage one anther. This design makes the language productive in many scenarios. In our examples, we made use of some of Groovy's features that support Agile development, its unsurpassed Java integration, the neat syntax for doing closures, and the great support for writing your own DSLs, including the builder concept. Groovy is not alone in having many of these features. Other languages have them as well. Groovy does, however, package these features in a very cohesive way, and this puts the fun back into programming. Even mundane tasks like sending emails are a pleasure with Groovy!

Resources

Return to ONJava.com.