mailService.sendMail {
to 'fred@gmail.com', 'ginger@gmail.com'
from 'john@gmail.com'
cc 'marge@gmail.com', 'ed@gmail.com'
bcc 'joe@gmail.com'
subject 'Hello John'
text 'Here is some text'
}
19 Mail
Version: 8.0.0-SNAPSHOT
Table of Contents
19 Mail
The Grails Mail plugin provides a convenient DSL for sending email. It supports plain-text, HTML, attachments, inline resources and i18n among other features.
Email can be sent using the mailService via the sendMail method. Here is an example:
Here we are sending a plain-text email with no attachments to the given addresses. The sendMail method is injected into all Controllers and Services to simplify access:
sendMail {
to 'fred@example.com'
subject 'Hello Fred'
text 'How are you?'
}
Installation
Add the plugin to the dependencies block of your build.gradle. The version is managed by the Grails BOM, so it does not need to be specified:
dependencies {
implementation 'org.apache.grails:grails-mail'
}
19.1 Configuration
SMTP Server Configuration
By default, the plugin assumes an unsecured mail server configured on port 25, getting the SMTP host name from the environment variable SMTP_HOST. However, you can change this via the grails-app/conf/application.groovy file.
Here is an example of how you would configure the default sender to send with a Gmail account:
grails {
mail {
host = 'smtp.gmail.com'
port = 465
username = 'youraccount@gmail.com'
password = 'yourpassword'
props = [
'mail.smtp.auth' : 'true',
'mail.smtp.socketFactory.port' : '465',
'mail.smtp.socketFactory.class' : 'javax.net.ssl.SSLSocketFactory',
'mail.smtp.socketFactory.fallback': 'false'
]
}
}
And the configuration for sending via a Hotmail/Live account:
grails {
mail {
host = 'smtp.live.com'
port = 587
username = 'youraccount@live.com'
password = 'yourpassword'
props = [
'mail.smtp.starttls.enable': 'true',
'mail.smtp.port' : '587'
]
}
}
If your mail session is provided via JNDI, you can use the jndiName setting:
grails.mail.jndiName = 'myMailSession'
Configuration Defaults
You can set various default settings via the application configuration that will be used in the absence of explicit values when sending email.
You can set the default "from" address to use for messages in application.groovy using:
grails.mail.default.from = 'server@yourhost.com'
You can also set the default "to" address to use for messages in application.groovy using:
grails.mail.default.to = 'user@yourhost.com'
Disabling Email Sending
You can completely disable the sending of email by setting:
grails.mail.disabled = true
You may want to set this value for the development and/or test environments. However, this will treat any call to mailService.sendMail() as a no-op, which means that the mail plugin will not attempt to render the email message or assemble any attachments. This can hide issues such as incorrect view names, or invalid or non-existent configuration, during development.
Overriding Addresses
An alternative to disabling email is to use the overrideAddress config setting for your development and/or test environment to force all email to be delivered to a specific address, regardless of what the addresses were at send time:
grails.mail.overrideAddress = 'test@address.com'
19.2 Sending Emails
Email is sent using the sendMail() method of the mailService. This plugin also adds a shortcut sendMail() method to all Controllers and Services in your application that simply delegates to the mailService. There is no difference between the two methods, so the choice is stylistic.
class PersonController {
def create() {
// create user
sendMail {
from 'admin@mysystem.com'
subject 'New user'
text 'A new user has been created'
}
}
}
class PersonController {
def mailService
def create() {
// create user
mailService.sendMail {
from 'admin@mysystem.com'
subject 'New user'
text 'A new user has been created'
}
}
}
The sendMail() method takes a single Closure argument that uses a DSL (Domain Specific Language) to configure the message to be sent. The following sections describe the aspects of the DSL.
19.3 Message Content
Message content is specified by either the text and/or html methods that specify the plain-text or HTML content respectively.
HTML Email
To send HTML email you can use the html method. This will set the content type of the message to text/html.
You can either supply a string value:
sendMail {
to 'user@somewhere.org'
subject 'Hello John'
html '<b>Hello</b> World'
}
Or a view to render to form the content:
sendMail {
to 'user@somewhere.org'
subject 'Hello John'
html view: '/emails/hello', model: [param1: 'value1', param2: 'value2']
}
See the section on using views for more details of the parameters to this version of html.
Text Email (plain-text)
To send plain-text email you can use the text method. This will set the content type of the message to text/plain.
You can either supply a String value:
sendMail {
to 'user@somewhere.org'
subject 'Hello John'
text 'Hello World'
}
Or a view to render to form the content:
sendMail {
to 'user@somewhere.org'
subject 'Hello John'
text view: '/emails/hello', model: [param1: 'value1', param2: 'value2']
}
See the section on using views for more details of the parameters to this version of text.
Text and HTML
It is possible to send a multipart message that contains both plain-text and HTML versions of the message. In this situation, the email-reading client is responsible for selecting the variant to display to the user.
To do this, simply use both the html and text methods:
sendMail {
to 'user@somewhere.org'
subject 'Hello John'
text view: '/emails/text-hello', model: [param1: 'value1', param2: 'value2']
html view: '/emails/html-hello', model: [param1: 'value1', param2: 'value2']
}
Using Views
Both the text and html methods support specifying a view to render to form the content. These are the accepted parameters:
-
The view is the absolute path (or relative to the current controller if during a request) to the GSP, just like the existing Grails
rendermethod. -
The plugin parameter is only necessary if the view you wish to render comes from a plugin, just like the existing Grails
rendermethod. -
The model parameter is a map representing the model the GSP will see for rendering data, just like the existing Grails
rendermethod.
19.4 Attachments
The Mail plugin is capable of adding attachments to messages as independent files and inline resources. To enable attachment support, you MUST indicate that the message is to be multipart as the first thing you do in the mail DSL.
sendMail {
multipart true
}
File Attachments
The term "file attachments" here refers to the attachment being received as a file, not necessarily using a file in your application to form the attachment.
The following methods are available in the mail DSL to attach files:
// Bytes
attach(String fileName, String contentType, byte[] bytes)
// Files
attach(File file)
attach(String fileName, File file)
attach(String fileName, String contentType, File file)
// InputStream
attach(String fileName, String contentType, InputStreamSource source)
There are 3 things that need to be provided when creating a file attachment:
-
file name - what the email client will call the file
-
content type - what mime type the email client will treat the file as
-
content source - the actual attachment
The Mail plugin supports using either a byte[], File, or InputStreamSource as the content source.
In the case of the variants that take a File that do not specify a file name, the name of the file will be used. In the case of the variants that take a File that do not specify a content type, the content type will be guessed based on the file extension.
sendMail {
multipart true
to 'someone@org.com'
attach 'yourfile.txt', 'text/plain', 'Hello!' as byte[]
}
Inline Attachments
It is also possible to attach content as inline resources. This is particularly useful in the case of HTML email where you wish to embed images in the message. In this case you specify a content id instead of a file name for the attachment, and then reference this content id in your mail message.
To attach an image as an inline resource you could do:
sendMail {
multipart true
to 'someone@org.com'
inline 'logo', 'image/jpeg', new File('logo.jpg')
html view: '/email/welcome'
}
Then in your view you reference the inline attachment using the cid: (content id) namespace:
<html>
<body>
<img src="cid:logo" />
<p>Welcome Aboard!</p>
</body>
</html>
The following methods are available in the mail DSL to inline-attach files:
// Bytes
inline(String fileName, String contentType, byte[] bytes)
// Files
inline(File file)
inline(String fileName, File file)
inline(String fileName, String contentType, File file)
// InputStream
inline(String fileName, String contentType, InputStreamSource source)
There are 3 things that need to be provided when creating an inline attachment:
-
content id - the identifier of the resource
-
content type - what mime type the email client will treat the content as
-
content source - the actual content
The Mail plugin supports using either a byte[], File, or InputStreamSource as the content source.
In the case of the variants that take a File that do not specify a content id, the name of the file will be used. In the case of the variants that take a File that do not specify a content type, the content type will be guessed based on the file extension.
19.5 Testing
Typically, you don’t want to actually send email as part of your automated tests. Besides wrapping all calls to sendMail in an environment-sensitive guard (which is a very bad idea), you can use one of the following techniques to deal with this.
Disabling Email Sending
You can effectively disable email sending globally in your test by setting the following value in your application for the test environment:
grails.mail.disabled = true
This will effectively cause all calls to sendMail() to be a non-operation, with a warning being logged that mail is disabled. The advantage of this technique is that it is cheap. The disadvantage is that it makes it impossible to test that email would be sent and to inspect any aspects of the sent mail.
Using an Override Address
You can override any and all recipient email addresses in sendMail() calls to force messages to be delivered to a certain mailbox:
grails.mail.overrideAddress = 'test@myorg.com'
All to, cc and bcc addresses will be replaced by this value if set. The advantage of this mechanism is that it allows you to test using a real SMTP server. The disadvantage is that it requires a real SMTP server and makes it difficult to test address determination logic.
Using an in-memory SMTP server
The preferred approach is to run an in-memory SMTP server (such as GreenMail) inside your application. This allows you to fully exercise your email-sending code and to inspect sent email to assert correct values for recipient addresses and so on.
The advantage of this approach is that it is as close as possible to the real world and gives you access to the sent email in your tests. The disadvantage is that it is another dependency.