Reference

Community

Proposal for Email Integration in Grails

Spring Mail

Default implementation for email integration will use Spring framework's JavaMailSender implementation. However, we should create test or development mail senders for environments that are not set to send email. A test mail sender will dump emails sent ( and headers ) into a text file or database for easy viewing.

Configuration

Configuration should be done similar to data sources, with XxxMailSender.groovy files under the grails-app/conf directory.

// views directory - messageNotification.gsp
Dear ${session.user},
You have a new message to view this message go here.
http://domain.com/send/email/${session.user.id}

The properties to, cc, bcc and from of the message object should be able to take either a Map of email-address:name pairs, a List of email addresses or just a singular email address.

Here we use a convention based approached combined with Spring dependency injection.

First the required mailer is injected into the controller.

Then a message is created using the createMessage method of the mailer that takes the model

We then invoke the send method on the someMailer. The send method uses the latter part of its name, in this case "MessageNotification" to map to delegate to the appropriate view that contains the e-mail message (in this case messageNotification.gsp)

Mailer(s) - The alternative approach.

_The difference is that we don't build an email in the controller or service. We delegate the building of the email to a closure within the Mailer class. This approach keeps your code very clean._

A mailer prepares an email for sending. They set the recipients, attach any files, build or generate the body(s). To create a mailer you simply create a class whose name ends with "Mailer" and place it within the "grails-app/mailers" directory.

Mailers are injectable into other classes such as controllers, services and jobs.

Sending emails

An mailer can have multiple closure properties. Each of these properties maps to a different email you may wish to build:

_It would be nice if default values for headers, from and bounce could be set by the current mailSender but overridden at an email scope._

Email Dynamic Methods

body

Description

A multi-purpose method for rendering the body of emails. This can be called multiple times to add bodies of different content type. LIke the render method on controllers it is best illustrated with a few examples!

Receive Emails

Our xxxMailer can be configured to receive incoming email and interact with the domain model of the application on the basis of the content. We handle these incoming emails by defining a method called receive() that takes and Email object (Yet to define what an email object actualy consists of).

The purpose of the checkMail method is to check your mailbox and call the receive method for each new message downloaded. I envisage that the checkMail method would be called by creating a Quartz job and injecting into it the xxxMailer. A mail checking solution that suites everybody's needs probably isn't going to be possible but we could support the basic IMAP & Pop3 protocols that JavaMail gives us, and leave the suggestion that the developer can override this method to perform anything more elaborate.

class MyJob {

// Injected here by spring
def XxxMailer xxxMailer

def cronExpression = "0 0 6 * * ?"

def execute(){
xxxMailer.checkMail()
}
}

Another variation/hybrid

My feeling is that we must use the MVC model for the messages. This means having controllers populate the model for the mail view, without requiring service injection, which in my view messes things up and requires controllers to know what is handling the mail of a certain type.

The above lets us send multiple mails easily, and lets us determine in an MVC way which mail view to use.

The builder in the last mail() example is used to configure advanced options. This could be removed if we provide GSP tags or other mechanisms (context helper) within the view template to configure the message itself, although arguably these should not be in the view.