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

advertisement

AddThis Social Bookmark Button

Using Groovy to Send Emails

by Paul King
03/23/2007

New programming languages have recently become an increasingly important discussion point. Emerging dynamic and scripting languages are being used in both client and server frameworks to achieve greater flexibility, agility, and productivity. At the same time, Domain Specific Languages (DSLs) are being used to provide greater expressivity with reduced scaffolding code and language syntax noise.

In the midst of these evolving trends sit several relatively recent dynamic languages, including Groovy. Groovy is one of the more popular dynamic languages designed to run on the JVM. It has a syntax that is very familiar to Java programmers, supports all the latest features and paradigms present in the dynamic language world, reduces large amounts of scaffolding code, and integrates seamlessly with Java. In essence, it allows you to gain from the emerging trends in language evolution while still leveraging the skills, infrastructure, and libraries you already have from the Java world.

As tempting as it might be to just rave about Groovy's great design or do a feature-by-feature comparison with other languages, in this tutorial, I try to dispense with hype (the last paragraph is more than enough!). I instead take a well-known topic (sending email) and show several ways you can do it with Groovy. Along the way we'll be looking at some of Groovy's features, and gain some appreciation of how dynamic languages can make otherwise mundane programming tasks both more productive and more fun.

A Testing Prologue

Test-driven development advocates writing a failing test before writing the production code in order to make the test pass. Let's give that a try for our email example. First, we'll write a little helper class to assist with our testing.

import org.subethamail.wiser.Wiser

class EmailFixture {
    private wiser = new Wiser()
    EmailFixture(int port) {
        wiser.port = port
        wiser.start()
    }

    def assertEmailArrived(args) {
        wiser.stop()
        assert wiser.messages.size() != 0, 'No messages arrived!'
        def message = wiser.messages[0].mimeMessage
        assert message?.subject == args['subject']
        assert message?.from[0].toString() == args['from']
    }
}

We have wrapped the Wiser email testing library inside a fixture class. Wiser acts as an SMTP server on your system and makes the messages it receives directly available to your Groovy (or Java) program. This saves you from having to use a real messaging service, keeping our test insulated from unreliable and slow external systems. Wiser's details are all hidden away inside our fixture, so you could easily swap it for an alternative like Dumbster or some other library with similar functionality.

Some points of interest:

  • You should note that the syntax is very similar to Java. Perhaps the first obvious difference is that semicolons are missing. They are optional unless you have multiple statements on one line.
  • We also don't need to statically type variables and methods. Variables wiser and message, method assertEmailArrived, and the method argument args don't specify a type. We can use a static type if we want, as shown with the constructor argument port.
  • The assert statement is turned on by default in Groovy, whereas it is off by default in Java.
  • Groovy has some neat shorthands, too. The expression message?.subject is equivalent to the Java expression message.getSubject() but also guards against null pointer exceptions. The expression args['subject'] is equivalent to args.get('subject'). Minor improvements here but they all add up.

We are now in a position to write our failing test:

fixture = new EmailFixture(port)
// ... code to send email goes here ...
fixture.assertEmailArrived(from:'cruise@myhost.org',
                           subject:'Test build')

Our test is making sure that the email arrives with the correct from address and subject, but we could extend this to other parts of the email content if we wished. Note that we are using named parameters with the assertEmailArrived method. This allows us to reorder our parameters or add new parameters without breaking existing code. Under the covers, a java.util.Map is being passed into our fixture from our calling code, but that is transparent to the Groovy developer.

I should point out that the details being sent in our email examples aren't important. We are mimicking the kind of functionality that is already built into many build systems to notify interested parties of successful (and potentially failing) builds. The same kind of functionality is needed in many ecommerce scenarios.

Streamlining Apache Commons Net

Apache Jakarta Commons Net implements the client side of over a dozen basic Internet protocols including the email protocols SMTP and POP3. The library concentrates on providing a uniform way of interacting with a wide range of protocols at a fairly low level rather than on implementing powerful higher-level abstractions. We will just be using its SMTP facilities here. It would be a good choice if you only have simple needs or if you need to interact with some of the other protocols it supports.

import org.apache.commons.net.smtp.*

port = 1025
org = 'mycompany.org'
fixture = new EmailFixture(port)

client = new SMTPClient()
client.connect('localhost', port)
client.login()

// set sender and recipient
client.sender = "cruise@$org"
client.addRecipient("devteam@$org")

// create and send header information
header = new SimpleSMTPHeader("cruise@$org",
        "devteam@$org", 'Successful build')
header.addCC("partners@$org")
header.addHeaderField('Organization', org)
writer = new PrintWriter(client.sendMessageData())
writer << header

// send body of message
writer << 'Successful build for ' + new Date()
writer.close()

client.logout()
client.disconnect()

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

Groovy helped a little here, but the code is still a bit tedious. The Commons Net SMTP API does provide some more-powerful abstractions, which would have reduced the amount of code we needed to write, but none of these exactly matched our requirements. We had to operate at the API's lowest level.

Some points of interest:

  • We can use the << operator when working with streams or readers.
  • Double-quoted strings in Groovy are known as GStrings. Variable expansion (in our code, the org variable) automatically occurs within GStrings.
  • We are using a Java library here, but because Groovy has the same object model as Java, we don't need to worry about any API mismatch as we would with some other popular scripting/dynamic languages that integrate with Java.

Pages: 1, 2, 3

Next Pagearrow