Introduction
The GreenMail plugin runs a mock GreenMail SMTP server inside a Grails application, so mail the application sends during development and test is captured instead of delivered.
Captured messages can be asserted on from integration tests, or browsed in a running application
through the view the plugin ships at /greenmail.
License
This plugin is released under the Apache License, Version 2.0
Acknowledgments
Following are the plugin contributors:
Source code
The full source code for this plugin can be found on GitHub.
For issues, improvements or new features go to the plugin’s GitHub issues.
Usage
Installation
Add the plugin to the dependencies block of your build.gradle. GreenMail is a development and
test tool, so testImplementation is normally the right configuration:
dependencies {
testImplementation 'io.github.gpc:greenmail:7.0.2'
}
If you also want to browse captured messages while running the application with bootRun, use
developmentOnly in addition to testImplementation.
The plugin exposes com.icegreen:greenmail as an api dependency, so GreenMail and the
GreenMailUtil helpers are available to your tests without declaring them yourself. If you want to
declare types on your MimeMessage variables, add the mail API too:
dependencies {
testImplementation 'jakarta.mail:jakarta.mail-api:2.1.3'
}
Requirements:
-
Grails 7.0.0 or higher
-
Java 17 or higher
Previous versions
For Grails 5 use version 5.0.0 of this plugin. For Grails 3 use version 2.0.0.
Configuration
The plugin assumes a Java mail provider is installed — for instance the Grails Mail plugin — and that the provider is pointed at the port the mock GreenMail SMTP server listens on.
Options
| Property | Default | Description |
|---|---|---|
|
|
Set to |
|
|
The port the mock SMTP server listens on. The default comes from GreenMail’s own
|
Example configuration
Using the Grails Mail plugin, wiring the provider to GreenMail is a matter of setting
grails.mail.port:
--- # Mail and GreenMail configuration
environments:
development:
grails:
mail:
port: 3025 # Use the default GreenMail port
test:
grails:
plugin:
greenmail:
ports:
smtp: 2525 # Use a custom GreenMail port
mail:
port: "${grails.plugin.greenmail.ports.smtp}"
production:
grails:
plugin:
greenmail:
disabled: true # Never run GreenMail in production
mail: # Your real SMTP server; see the mail plugin for options
server: smtp.example.com
port: 25
| Always disable the plugin in production. It starts a real SMTP listener and retains every message it receives in memory. |
Usage in integration tests
Inject the greenMail bean into an @Integration specification and assert on the messages the
application sent. Clearing the mailbox between features keeps specifications independent:
import com.icegreen.greenmail.util.GreenMailUtil
import grails.plugin.greenmail.GreenMail
import grails.plugins.mail.MailService
import grails.testing.mixin.integration.Integration
import jakarta.mail.internet.MimeMessage
import spock.lang.Specification
@Integration
class GreenmailExampleSpec extends Specification {
MailService mailService
GreenMail greenMail
void cleanup() {
greenMail.deleteAllMessages()
}
void 'sent mail is captured by GreenMail'() {
when:
mailService.sendMail {
to 'to@example.com'
from 'from@example.com'
subject 'subject'
body 'hello world'
}
then:
greenMail.messagesCount == 1
and:
MimeMessage message = greenMail.latestMessage
message.subject == 'subject'
message.to == 'to@example.com'
GreenMailUtil.getBody(message) == 'hello world'
}
}
Put each assertion on its own line in a then: or and: block. Assertions written inside a
with closure or a helper closure are not evaluated as Spock conditions and will silently pass.
|
waitForIncomingEmail is useful when mail is sent asynchronously:
assert greenMail.waitForIncomingEmail(5000, 1)
Usage in a running application
The plugin ships a controller and view that list the messages the application has "sent". With the application running, browse to:
http://localhost:8080/greenmail
The list shows the sent date, subject and recipients of each captured message. Follow the Show link on a row to view the raw message, including headers.
The following URLs are mapped:
| URL | Description |
|---|---|
|
Lists all captured messages. |
|
Shows the raw content of a single message by its index in the list. |
|
Deletes all captured messages. |
JSON output
Append a .json extension to list or show to get the captured messages as JSON, which is handy
for scripted checks:
http://localhost:8080/greenmail/list.json http://localhost:8080/greenmail/show/0.json
Both respond with application/json. list.json returns a list of objects carrying id, sent,
subject, to and body; show/$id.json returns a single such object.
The .js extension returns the same JSON and is retained for backwards compatibility.
|
When grails.plugin.greenmail.disabled is true these URL mappings are not installed.
Additional methods and extensions
The greenMail bean
grails.plugin.greenmail.GreenMail extends com.icegreen.greenmail.util.GreenMail and adds a few
Groovy-friendly members on top of the inherited API:
| Member | Description |
|---|---|
|
The received messages as a |
|
The number of received messages. |
|
The message at the given index. |
|
The most recently received message, or |
|
Clears the mailbox. Call this from |
MimeMessage extension properties
The plugin registers a Groovy extension module that adds recipient properties to
jakarta.mail.internet.MimeMessage, so recipients can be read without going through
getRecipients(RecipientType):
| Property | Description |
|---|---|
|
The first |
|
All |
MimeMessage.getRecipients(RecipientType) returns null when the message has no recipient of that
type. The plural properties normalise that to an empty list, so reading a recipient type the message
does not carry needs no guard:
MimeMessage message = greenMail.latestMessage
message.to // 'first@example.com'
message.tos // ['first@example.com', 'second@example.com']
message.ccs // ['copied@example.com']
message.bcc // null, when the message has no BCC recipients
message.bccs // []
Release Notes
-
7.0.2
-
Migrated to the
grails-plugin-templatebuild structure -
Guard against starting the GreenMail server twice when the application context is refreshed
-
The
.jsonextension on/greenmail/listand/greenmail/show/$idnow returns JSON instead of falling back to the HTML view -
/greenmail/show/$idno longer prefixes the message headers withnull, and theidfield of/greenmail/show/$id.jsonis now a number, matching/greenmail/list.json -
The
MimeMessagetos/ccs/bccsproperties now return an empty list instead ofnullwhen the message has no recipient of that type, andto/cc/bccreturnnullinstead of throwing aNullPointerException
-
-
7.0.1 - Package the precompiled GSP view so the
/greenmaillist renders in consuming applications -
7.0.0 - Support for Grails 7, Jakarta Mail and GreenMail 2.x
-
5.0.0 - Support for Grails 5
-
2.0.0 - Support for Grails 3
-
1.3.0 - Support for Grails 2