Dark theme | Light theme

April 17, 2009

Send mail with Apache Camel from Grails

We have seen how to use a Grails service in a Camel route, but the Apache Camel plugin also allows us to send messages to a Camel route. We can use the sendMessage method in our controllers and services. We define the starting point of the route and a message object and we can send it.

For our example we are going to send an e-mail message from a controller. We are using a fire-and-forget method, so we can immediatelly return to the web page and we don't have to wait until the mail communication is finished. Let's start with a Grails application:

$ grails create-app sendmail
$ cd sendmail
$ grails install-plugin camel

Next we create a controller which will create and send a message to a Camel route:

$ grails create-controller mail

We open the MailController in an editor and add a mail closure. Here we get the values from the request parameters name and email (the web page with a form and two input fields name and email is created next). We invoke the sendMessage method to send a map message to the route starting point seda:mailQueue. The SEDA component from Apache Camel allows asynchronuous communication, so we immediatelly return to our controller after the message is sent. To get more robust asynchronuous communication we could use for example ActiveMQ. Finally we return to the web page with a flash message we can display.

class MailController {
    def mail = {
        if ( != null && != null) {
            sendMessage "seda:mailQueue", [name:, email:]
            flash.message = "Check your e-mail for new messages."

The controller will look for a file grails-app/views/mail/mail.gsp to display a web page. So let's create it. The page only needs a form with input fields for name and e-mail:

<%@ page contentType="text/html;charset=UTF-8" %>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Mail with Apache Camel and Grails</title>
    <h1>Mail with Apache Camel</h1>
    <g:if test="${flash.message}">
      <div class="message">${flash.message}</div>
    <g:form method="POST">
      Name: <g:textField name="name"/><br />
      E-mail: <g:textField name="email"/><br />
      <g:submitButton name="submit" value="Send mail"/>

Okay we have created the controller and web page. Next we create the Camel route:

$ grails create-route mail

The route will listen with the SEDA component for incoming messages. The message contains a map with the name and e-mail values. We use these values to create the content of an e-mail message. The content is HTML so we can show off Groovy's builder support. We also define the subject, to and from headers of the e-mail message. Then we use Camel's mail component to send the e-mail via SMTP.

import org.codehaus.groovy.grails.commons.*

class MailRoute {
    def configure = {
        def config = ConfigurationHolder.config

        .process {
            def name =
            def to =
            def html = new groovy.xml.StreamingMarkupBuilder().bind {
                html {
                    body {
                        p "${name},"
                        p {
                            mkp.yield "Thank you for your interest in "
                            a href:'', "Apache Camel"
                            mkp.yield "."
                        p {
                            i "P.S. Grails rocks"
            it.out.setBody html.toString()
            it.out.setHeader "to", to
            it.out.setHeader "from", ""
            it.out.setHeader "subject", "Mail sent from Apache Camel"

The Camel mail component has a dependeny on the JavaMail API libraries. We must download the libraries and add them to our lib directory. Or we can install the Grails mail plugin, which contains the JavaMail API libraries already. This way the libraries are automatically added to our application. (grails install-plugin mail)

And we are done. We can run our application and start sending e-mails:

$ grails run-app

Notice how the web page returns immediatelly after we submit the form, because of the asynchronuous SEDA component.