Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 0 additions & 43 deletions .github/workflows/gradle.yml

This file was deleted.

50 changes: 50 additions & 0 deletions .github/workflows/grails8.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: Grails 8 CI

on:
push:
branches: [ grails8 ]
pull_request:
branches: [ grails8 ]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
app: [ initial, complete ]
name: ${{ matrix.app }}
steps:
- uses: actions/checkout@v4

- name: Set up JDK 21
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '21'

- name: Set up Gradle
uses: gradle/actions/setup-gradle@v4

- name: Unit tests
working-directory: ${{ matrix.app }}
run: |
chmod +x gradlew
./gradlew test --console=plain --stacktrace

- name: Integration tests (complete only)
if: matrix.app == 'complete'
working-directory: complete
run: ./gradlew integrationTest --console=plain --stacktrace

- name: Upload test reports
if: always()
uses: actions/upload-artifact@v4
with:
name: test-reports-${{ matrix.app }}
path: ${{ matrix.app }}/build/reports/tests/
if-no-files-found: ignore
104 changes: 98 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,103 @@
# Send Email and Spock Spring
# grails-email

This repository contains the worked sample app for the [Send Email and Spock Spring](https://grails.apache.org/guides/grails-email/4/guide/index.html) guide on the Apache Grails site.
Sample app for **Sending Email from a Grails 8 Application (and Testing It)** (Apache Grails `8.0.0-SNAPSHOT`, JDK 21).

## Run the example
The guide shows how to send mail from a Grails 8 service over SMTP (Grails Mail plugin) and through a provider (SendGrid / AWS SES), how to inject and externalize mail configuration, and how to verify the send interaction using Spock Spring integration tests — without dispatching real email.

`./gradlew bootRun`
## Layout

## Maintained at apache/grails-static-website
| Directory | What it is |
|-----------|------------|
| `initial/` | Grails 8 REST API starter from [start.grails.org](https://start.grails.org) (`views-json`, `spock`). Work through the guide starting here. |
| `complete/` | Finished sample — `EmailService` boundary, SMTP / SendGrid / SES implementations, `POST /mail/send`, and a Spock Spring integration spec that mocks the sender. |

The guide narrative is maintained at https://github.com/apache/grails-static-website. Changes to the guide content go there; this repo holds the worked sample app only.
## Running

```bash
git clone -b grails8 https://github.com/grails-guides/grails-email.git
cd grails-email/complete
./gradlew test integrationTest
```

To follow the guide step by step, start from `initial/`:

```bash
cd grails-email/initial
./gradlew test
```

Run the finished app locally (SMTP defaults to `localhost:1025` — use [MailHog](https://github.com/mailhog/MailHog) or similar for manual verification):

```bash
cd grails-email/complete
./gradlew bootRun
```

Example endpoint:

```bash
curl -X POST http://localhost:8080/mail/send \
-H 'Content-Type: application/json' \
-d '{"recipient":"user@example.com","subject":"Hello","textBody":"Hi there"}'
```

Switch providers via `application.yml` or environment variables:

| Provider | Set |
|----------|-----|
| SMTP (default) | `EMAIL_PROVIDER=smtp` plus `SMTP_HOST`, `SMTP_PORT`, etc. |
| SendGrid | `EMAIL_PROVIDER=sendgrid`, `SENDGRID_APIKEY`, `SENDGRID_FROM_EMAIL` |
| AWS SES | `EMAIL_PROVIDER=ses`, `AWS_REGION`, `AWS_SOURCE` (+ standard AWS credentials) |

The integration spec (`MailControllerSpec`) uses a Spock mock for `EmailService` and asserts the message is built and the sender is invoked — no live email is sent in CI.

## Requirements

- **JDK 21** (Temurin recommended; the Gradle build enforces Java 21+)
- Optional: local SMTP catcher on port **1025** for manual `bootRun` verification

If Gradle reports *"Run this build using a Java 21 or newer JVM"*, switch your shell to JDK 21:

```bash
sdk install java 21.0.6-tem
sdk default java 21.0.6-tem
java -version # should show 21.x
```

## The pattern, in one place

```yaml
# application.yml — pick a provider and externalize secrets
email:
provider: ${EMAIL_PROVIDER:smtp}

grails:
mail:
host: ${SMTP_HOST:localhost}
port: ${SMTP_PORT:1025}
default:
from: ${SMTP_FROM:no-reply@example.com}
```

```groovy
// grails-app/conf/spring/resources.groovy — inject the right implementation
beans = {
def provider = application.config.getProperty('email.provider', String, 'smtp')
switch (provider) {
case 'sendgrid': emailService(SendGridEmailService); break
case 'ses': emailService(AwsSesEmailService); break
case 'smtp': emailService(SmtpEmailService); break
default: throw new IllegalArgumentException("Unsupported email.provider: ${provider}")
}
}
```

Grails 8 uses `org.grails.plugins:grails-mail` 5.x from the Grails plugin repository — compatible with Apache Grails 8.

## Guide prose

Published narrative lives on [grails.apache.org/guides](https://grails.apache.org/guides/) in [apache/grails-static-website](https://github.com/apache/grails-static-website) under `guides/grails-email/v8/`.

## CI

GitHub Actions (`.github/workflows/grails8.yml`) runs `./gradlew test` for `initial` and `complete`, and `./gradlew integrationTest` for `complete`, on pushes and PRs to the `grails8` branch.
10 changes: 0 additions & 10 deletions build.gradle

This file was deleted.

1 change: 1 addition & 0 deletions complete/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ out/
.project
.settings
.classpath
*.log
Loading