Monday, June 18, 2012

Email with Spring and SendGrid (Part 3)

Review

In the previous section, we have learned how to sign-up with SendGrid's free plan. In this section, we will start writing the Java classes and discuss the project's structure.


Project Structure

Our application is a Maven project which means our project follows the Maven structure.

Here's a preview of our project's structure:





Domain Layer

The domain layer contains a Message class that represents an email message.

package org.krams.domain;
import java.io.Serializable;
public class Message implements Serializable {
private static final long serialVersionUID = -4093981756240899937L;
private String senderName;
private String senderEmail;
private String ccEmail;
private String subject;
private String body;
private String receiverName;
private String receiverEmail;
public Message() {
super();
}
public Message(String senderName, String senderEmail, String ccEmail,
String subject, String body, String receiverName,
String receiverEmail) {
super();
this.senderName = senderName;
this.senderEmail = senderEmail;
this.ccEmail = ccEmail;
this.subject = subject;
this.body = body;
this.receiverName = receiverName;
this.receiverEmail = receiverEmail;
}
...getters/setters
}
view raw Message.java hosted with ❤ by GitHub


Controller Layer

The controller layer contains a simple controller that serves a form for composing and sending emails. It also contains a send method that accepts a Message object. The controller delegates the sending part to an email service.
package org.krams.controller;
import org.krams.domain.Message;
import org.krams.response.StatusResponse;
import org.krams.service.EmailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping("/email")
public class EmailController {
@Autowired
private EmailService emailService;
@RequestMapping
public String form() {
return "form";
}
@RequestMapping(value ="/send", method=RequestMethod.POST)
public @ResponseBody StatusResponse send(@RequestBody Message message) {
return emailService.send(message);
}
}


Service Layer

The service layer contains the email service. We have a simple interface EmailService for sending messages.
package org.krams.service;
import org.krams.domain.Message;
import org.krams.response.StatusResponse;
public interface EmailService {
StatusResponse send(Message message);
}


The actual implementation SendGridEmailService relies on RestTemplate to send the email message via HTTP as a POST method.
package org.krams.service;
import org.apache.log4j.Logger;
import org.krams.domain.Message;
import org.krams.response.StatusResponse;
import org.krams.util.SendGridParameter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
@Service
public class SendGridEmailService implements EmailService {
protected static Logger logger = Logger.getLogger("service");
private RestTemplate restTemplate = new RestTemplate();
@Value("${sendgrid.api.user}")
private String sendgridApiUser;
@Value("${sendgrid.api.key}")
private String sendgridApiKey;
@Override
public StatusResponse send(Message message) {
try {
MultiValueMap<String, Object> vars = new LinkedMultiValueMap<String, Object>();
vars.add(SendGridParameter.API_USER, sendgridApiUser);
vars.add(SendGridParameter.API_KEY, sendgridApiKey);
vars.add(SendGridParameter.SENDER_NAME, message.getSenderName());
vars.add(SendGridParameter.SENDER_EMAIL, message.getSenderEmail());
vars.add(SendGridParameter.BLIND_COPY_EMAIL, message.getCcEmail());
vars.add(SendGridParameter.SUBJECT, message.getSubject());
vars.add(SendGridParameter.TEXT, "");
vars.add(SendGridParameter.HTML, message.getBody());
vars.add(SendGridParameter.RECEIVER_EMAIL, message.getReceiverEmail());
vars.add(SendGridParameter.RECEIVER_NAME, message.getReceiverName());
restTemplate.postForLocation(SendGridParameter.URL, vars);
} catch (Exception ex) {
logger.error(ex);
return new StatusResponse(false, "An error has occurred!");
}
return new StatusResponse(true, "Message sent");
}
}


Utility Layer

This layer contains helper classes and interfaces. Here we've extracted the required SendGrid parameters for sending emails via HTTP. Please refer to Part 2 of this guide if you need to review the SendGrid Web API.
package org.krams.util;
public interface SendGridParameter {
public static final String URL = "http://sendgrid.com/api/mail.send.json";
public static final String API_USER = "api_user";
public static final String API_KEY = "api_key";
public static final String RECEIVER_EMAIL = "to";
public static final String RECEIVER_NAME = "toname";
public static final String SUBJECT = "subject";
public static final String TEXT = "text";
public static final String HTML = "html";
public static final String SENDER_EMAIL = "from";
public static final String SENDER_NAME = "fromname";
public static final String BLIND_COPY_EMAIL = "bcc";
}


View Layer

The view layer contains a simple html form for composing and sending email messages. One important section here that needs to be discussed is the usage of the postJSON plugin.
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<c:url value="/email/send" var="sendUrl"/>
<html>
<head>
<link rel="stylesheet" type="text/css" media="screen" href='<c:url value="/resources/css/jquery-ui/pepper-grinder/jquery-ui-1.8.16.custom.css"/>'/>
<link rel="stylesheet" type="text/css" media="screen" href='<c:url value="/resources/css/style.css"/>'/>
<script type='text/javascript' src='<c:url value="/resources/js/jquery-1.6.4.min.js"/>'></script>
<script type='text/javascript' src='<c:url value="/resources/js/jquery-ui-1.8.16.custom.min.js"/>'></script>
<script type='text/javascript' src='<c:url value="/resources/js/util.js"/>'></script>
<title>Email</title>
<script type='text/javascript'>
$(function() {
init();
});
function init() {
$('input:button').button();
$('#submit').button();
$('#emailForm').submit(function() {
event.preventDefault();
$.postJSON('${sendUrl}', {
senderName: $('#senderName').val(),
senderEmail: $('#senderEmail').val(),
ccEmail: $('#ccEmail').val(),
subject: $('#subject').val(),
body: $('#textBody').val(),
receiverName: $('#receiverName').val(),
receiverEmail: $('#receiverEmail').val()
},
function(result) {
if (result.success == true) {
dialog('Success', 'Email has been sent!');
} else {
dialog('Failure', 'Email has not been sent!');
}
});
});
$('#reset').click(function() {
clearForm();
dialog('Success', 'Fields have been cleared!');
});
}
function dialog(title, text) {
$('#msgbox').text(text);
$('#msgbox').dialog(
{ title: title,
modal: true,
buttons: {"Ok": function() {
$(this).dialog("close");}
}
});
}
function clearForm() {
$('#receiverName').val('');
$('#receiverEmail').val('');
$('#ccEmail').val('');
$('#senderName').val('');
$('#senderEmail').val('');
$('#subject').val('');
$('#textBody').val('');
}
</script>
</head>
<body>
<h1 id='banner'>Compose Email</h1>
<div>
<form id='emailForm'>
<fieldset>
<legend>New Email</legend>
<label for='receiverName'>To (name):</label><input type='text' id='receiverName'/><br/>
<label for='receiverEmail'>To (email)</label><input type='text' id='receiverEmail'/><br/>
<label for='ccEmail'>Cc (email):</label><input type='text' id='ccEmail'/><br/>
<label for='senderName'>From (name):</label><input type='text' id='senderName'/><br/>
<label for='senderEmail'>From (email):</label><input type='text' id='senderEmail'/><br/>
<label for='subject'>Subject:</label><input type='text' id='subject'/><br/>
<label for='textBody' style="display:break">Message</label>
<textarea name="textBody" id="textBody">Email message here</textarea><br/>
<input type='button' value='Reset' id='reset' />
<input type='submit' value='Send' id='submit'/>
</fieldset>
</form>
</div>
<div id='msgbox' title='' style='display:none'></div>
</body>
</html>
view raw form.jsp hosted with ❤ by GitHub

jQuery plugin

postJSON is a jQuery plugin that allows sending of JSON objects via POST. This plugin is based a plugin I found at the jQuery plugin repository. Unfortunately, the location doesn't seem to exist anymore. Also, I've made some modifications with the plugin (see the comments).
/*************************************************
* Source: http://plugins.jquery.com/project/postJSON
* Modifications:
* a. Replace json to jsonData
* b. Replace success to callbackSuccess
*
* Function: $.postJSON ( url, jsonObject, success, options )
* url: The url to post the json object to
* jsonObject: The JSON object to post
* success: The success handler to invoke on successful submission
* options: Additional options to provide to the AJAX call. This is the exact same object you would use when calling $.ajax directly.
*
* Description:
* $.postJSON simplifies posting JSON objects to any url by invoking $.ajax with the required options. The specified JSON object will be stringified and posted to the url.
* It's up to the server to deserialize the stringified JSON object. ASP.NET MVC 3 will do this automatically
*
* Sample usage:
* var onSuccess = function() { ... };
* var onError = function() { ... };
* $.postJSON ( '/account/login', { username: 'jack', password: 'secretPass' }, onSuccess, { error: onError } );
**************************************************/
(function ($) {
$.extend({
postJSON: function (url, jsonData, callbackSuccess, options) {
var config = {
url: url,
type: "POST",
data: jsonData ? JSON.stringify(jsonData) : null,
dataType: "json",
contentType: "application/json; charset=utf-8",
success: callbackSuccess
};
// $.ajax($.extend(options, config)); // only works for jQuery 1.4+
$.ajaxSetup(config); // only works for jQuery 1.5+
$.ajax();
// reset back so that future users aren't affected
config = {
url: null,
type: "GET",
data: null,
dataType: null,
contentType: "application/x-www-form-urlencoded",
success: null
};
$.ajaxSetup(config);
}
});
})(jQuery);
view raw util.js hosted with ❤ by GitHub


Next

We've completed writing our Java classes. In the next section, we will start writing the configuration files. Click here to proceed.

StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: Email with Spring and SendGrid (Part 3) ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

4 comments:

  1. Where can I found the StatusResponse .java?

    ReplyDelete