Pages

Monday, 16 July 2012

Integrating Campaign Monitor with Grails

This article describes how to create and remove subscribers from your Campaign Monitor list using the Campaign Monitor API from your Grails application.

Campaign Monitor is a mass-email tool for sending email marketing messages and newsletters. It has an API to allow you to maintain your contact list in Campaign Monitor as well as respond to unsubscribe events etc within your application.

This article doesn't cover every api call you can make but it does provide a foundation that can be expanded for any other task you may want to achieve.

Configuration

We will make use of the Groovy HTTP Builder which is a fantastic library for making HTTP POSTs and GETs from a Groovy application. It handles encoding for text, XML, JSON and URL, for both the request and response.

We can add a dependency on this in BuildConfig.groovy


runtime ('org.codehaus.groovy.modules.http-builder:http-builder:0.5.2')
  {
    excludes "xml-apis"
  }

We need to exclude xml-apis as it may conflict with other versions of this jar that have already been downloaded.

The Code

We can create a simple service that has two methods addSubscriber and unsubscribe.

class CampaignMonitorService {

 static transactional = true

 def addSubscriber(SecUser user) {
  try {
   def subscribe = new HTTPBuilder( 'http://api.createsend.com/api/v3/subscribers/bcd59617945a7a50064b1fe881b3a3bd.json' )
   subscribe.auth.basic '7f576635a9a5c97ca3711f28c6ce8010', '' // leave password blank

   def body = """{
   "EmailAddress": "${user.username}",
   "Name": "${user.firstName} ${user.secondName}",
 "CustomFields": [
    {
      "Key": "FirstName1",
      "Value": "${user.firstName}"
    },
    {
      "Key": "LastName1",
      "Value": "${user.secondName}"
    },
    {
      "Key": "Company",
      "Value": "${user.company}"
    },
{
      "Key": "City",
      "Value": "${user.city}"
    },
{
      "Key": "county",
      "Value": "${user.county}"
    }
  ]
  }"""
   subscribe.post(body: body,
     requestContentType: JSON ) { resp ->
      assert resp.statusLine.statusCode == 201
     }
  } catch (Exception e) {println e.printStackTrace()}
 }
}

def unsubscribe(SecUser user) {
  try {
   def subscribe = new HTTPBuilder( 'http://api.createsend.com/api/v3/subscribers/bcd59617945a7a50064b1fe881b3a3bd/unsubscribe.json' )
   subscribe.auth.basic '7f576635a9a5c97ca3711f28c6ce8010', '' // leave password blank

   def body = """{
   "EmailAddress": "${user.username}"}"""
   subscribe.post(body: body,
     requestContentType: JSON ) { resp ->

      println " response status: ${resp}"
      assert resp.statusLine.statusCode == 200
     }
  } catch (Exception e) {println e.printStackTrace()}
 }

Points to Note

  • The .json extension to the api call means that it is expecting a JSON object in the request body. This is easy to provide because HTTP-Builder will convert the Map to a JSON object (it can handle closures, lists and POJOs too).
  • We use basic HTTP authentication, however the Campaign Monitor API only requires a user name (your API key) and no password
  • The response is JSON too so we are provided with it as a GPathResult which means we can parse it using dot notation
  • In this example a simple try/catch is used to catch exceptions however you can equally define a closure for handling errors returned by CM see here

Sunday, 15 July 2012

Generating Zip Files From Multiple Files In Grails

This article describes how to write a controller in Grails that takes a number of files on the server and bundles them in to a zip file. The resulting file is put on to the response so the application user can download it.

There are already a number of articles out there on creating zip files in groovy. This (short!) article pulls them together and includes how to handle multiple, fairly sizeable files and how to set the response headers correctly.

The Code

ByteArrayOutputStream baos = new ByteArrayOutputStream()
ZipOutputStream zipFile = new ZipOutputStream(baos)

  album.tracks.each {track ->
    if (track.mp3DownloadPath != "") {
      File file = new File(grailsApplication.config.tracks.root.directory+track.mp3DownloadPath)
      zipFile.putNextEntry(new ZipEntry(track.title+".mp3"))
      file.withInputStream { i ->
       
        zipFile << i

      }
      zipFile.closeEntry()
     }
    }
    zipFile.finish()
    response.setHeader("Content-disposition", "filename=\"${album.title}.zip\"")
    response.contentType = "application/zip"
    response.outputStream << baos.toByteArray()
    response.outputStream.flush()

Points to Note

  • We use the GDK withInputStream method on File to create a new InputStream. This automatically close the InputStream for us after the closure is exited.
  • The Groovy left-shit operator <<, is a good short-hand for copying an InputStream into an OutputStream. You can use it to copy byte arrays into OutputStreams too.
  • zipFile.finish() is called after all the files have been added to the ZipOutputStream. Not calling this resulted in a corrupted zip file.
  • When setting the response header, it was necessary to wrap the file name in double quotes to prevent Chrome occassionally complaining about a 'Duplicate Headers Received from Server' error.  response.setHeader("Content-disposition", "filename=\"${album.title}.zip\"")