This is an automated email from the ASF dual-hosted git repository.
cziegeler pushed a commit to branch master
in repository
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-commons-messaging-mail.git
The following commit(s) were added to refs/heads/master by this push:
new 7f3103d docs: add AGENTS.md and improve README build instructions (#3)
7f3103d is described below
commit 7f3103d0c79bcead1a7962afe4fc0e7835921a7f
Author: Carsten Ziegeler <[email protected]>
AuthorDate: Tue Jun 2 10:06:40 2026 +0200
docs: add AGENTS.md and improve README build instructions (#3)
Co-authored-by: Maia <maia@noreply>
---
AGENTS.md | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
CLAUDE.md | 1 +
README.md | 112 +++++++++++++++++++++++++++++++++++-------------------------
3 files changed, 182 insertions(+), 45 deletions(-)
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 0000000..7753421
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,114 @@
+# Project overview
+
+Apache Sling Commons Messaging Mail is an OSGi bundle that provides a
`MailService` API for sending MIME messages over SMTPS. It exposes three public
service interfaces (`MailService`, `MessageBuilder`, `MessageIdProvider`) and
ships concrete implementations (`SimpleMailService`, `SimpleMessageBuilder`,
`SimpleMessageIdProvider`) as OSGi Declarative Services components. The bundle
depends on `sling.commons.messaging`, `sling.commons.crypto` (for password
decryption), and `sling.commons.t [...]
+
+# Core commands
+
+```bash
+# Build and run all checks (Checkstyle, PMD, SpotBugs) + unit tests
+mvn clean verify
+
+# Skip integration tests (faster local iteration)
+mvn clean verify -DskipITs
+
+# Run only unit tests
+mvn test
+
+# Run a single unit test class
+mvn test -Dtest=SimpleMailServiceTest
+
+# Run integration tests only
+mvn failsafe:integration-test failsafe:verify
+
+# Run a single integration test class
+mvn failsafe:integration-test -Dit.test=SimpleMailServiceIT
+
+# Run Checkstyle only
+mvn checkstyle:check
+
+# Run PMD only
+mvn pmd:check
+
+# Run SpotBugs only
+mvn spotbugs:check
+```
+
+No dev server — this is a library bundle, not a standalone application.
+
+# Project layout
+
+```
+pom.xml Maven build descriptor
+bnd.bnd OSGi bundle manifest extras
+checkstyle-suppressions.xml Checkstyle suppression rules
+pmd-exclude.properties PMD false-positive exclusions
+spotbugs-exclude.xml SpotBugs exclusion filters
+
+src/
+ main/java/org/apache/sling/commons/messaging/mail/
+ MailService.java Public API: send MimeMessage async
+ MessageBuilder.java Public API: build MimeMessage
+ MessageIdProvider.java Public API: custom Message-ID generation
+ package-info.java
+ internal/
+ SimpleMailService.java Factory OSGi component (SMTPS sender)
+ SimpleMailServiceConfiguration.java @ObjectClassDefinition metatype
+ SimpleMessageBuilder.java Default message builder
+ SimpleMessageIdProvider.java Default message-ID provider
+ SimpleMessageIdProviderConfiguration.java
+ package-info.java
+
+ test/java/
+ org/apache/commons/mail/util/
+ MimeMessageParser.java Test utility (vendored)
+ org/apache/sling/commons/messaging/mail/internal/
+ SimpleMailServiceTest.java Unit tests (Mockito)
+ SimpleMessageBuilderTest.java
+ SimpleMessageIdProviderTest.java
+ org/apache/sling/commons/messaging/mail/it/tests/
+ MailTestSupport.java Pax Exam base class
+ SimpleMailServiceIT.java OSGi integration tests
+
+ test/resources/
+ mockito-extensions/ Mockito plugin config
+ password Encrypted test password
+ *.html / *.txt / *.png Email template fixtures
+```
+
+# Development patterns & constraints
+
+- **Java 17**, OSGi R7. All source and target set via `sling.java.version=17`.
+- **OSGi DS annotations only** — use
`org.osgi.service.component.annotations.*`. Never use Felix SCR annotations.
+- `SimpleMailService` is a **factory component** (`@Designate(factory=true)`).
Multiple instances can be registered with different SMTP servers.
+- All `@Reference` fields that can change at runtime are declared `volatile`
with `DYNAMIC` policy and `GREEDY` option.
+- Password stored encrypted; always decrypt via `CryptoService.decrypt()` —
never store plaintext passwords.
+- Public API interfaces carry `@ProviderType` — do not add default methods
without a version bump.
+- Nullability: annotate with `@NotNull`/`@Nullable` from
`org.jetbrains.annotations`.
+- Every source file must have the Apache 2.0 license header.
`apache-rat-plugin` enforces this at build time.
+- Configuration property names use underscores for dots (OSGi metatype
convention): `mail_smtps_host`, `threadpool_name`.
+
+# Git workflow
+
+- Follow the [Apache Sling contribution
guidelines](https://sling.apache.org/contributing.html).
+- Branch names: `feature/<SLING-XXXXX>-short-description` or
`fix/<SLING-XXXXX>-short-description`.
+- Commit messages: start with the JIRA issue key, e.g. `SLING-12345 Fix NPE in
SimpleMailService`.
+- PRs target the `master` branch on GitHub; CI runs via Jenkins (`Jenkinsfile`
at repo root).
+- Do not push directly to `master`.
+
+# Testing guidelines
+
+- **Framework**: JUnit 4 + Mockito 5 for unit tests; Pax Exam 4 + GreenMail
for OSGi integration tests.
+- Unit tests live in `src/test/java/.../mail/internal/` and are named
`*Test.java`.
+- Integration tests live in `src/test/java/.../mail/it/tests/` and are named
`*IT.java`. They run inside a real OSGi framework (Apache Felix) provisioned by
Pax Exam.
+- GreenMail provides a local mock SMTP server for integration tests — no
external mail server required.
+- Test resources (templates, images, encrypted password) are in
`src/test/resources/`.
+- Coverage is not enforced by a specific threshold; rely on code review.
+
+# Gotchas
+
+- **TCCL swap**: `SimpleMailService.send()` replaces the thread context
classloader before `Session.getTransport()` to ensure the Jakarta Mail provider
is found. Forgetting this causes `NoProviderException` inside OSGi.
+- **Password is always encrypted**: the `password` configuration value is
ciphertext. Passing a plaintext password to `SimpleMailServiceConfiguration` in
tests requires mocking `CryptoService.decrypt()` to return it as-is.
+- **Integration tests require Maven local repo**: Pax Exam downloads bundles
via `pax-url-aether`. Build must be run with network access or a pre-populated
local repo on first run.
+- **`redirectTestOutputToFile=true`**: failsafe redirects integration test
output to `target/failsafe-reports/`. Check there, not the console, when
debugging IT failures.
+- **Checkstyle config is external**: the `configLocation` is `checks.xml`
resolved from the Checkstyle dependency `de.bildschirmarbeiter:checkstyle:3`,
not a file in this repo. Do not add a local `checks.xml`.
+- **`spotless` is disabled** (`<skip>true</skip>`) — do not rely on it for
formatting.
diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 100644
index 0000000..9a80b01
--- /dev/null
+++ b/CLAUDE.md
@@ -0,0 +1 @@
+read @AGENTS.md
diff --git a/README.md b/README.md
index c3ec49a..4cd5294 100644
--- a/README.md
+++ b/README.md
@@ -6,18 +6,40 @@
This module is part of the [Apache Sling](https://sling.apache.org) project.
-This module provides a simple layer on top of [Jakarta
Mail](https://eclipse-ee4j.github.io/mail/) 2.0 (package `jakarta.mail`)
including a message builder and a service to send mails via SMTPS.
+It provides a simple layer on top of [Jakarta
Mail](https://eclipse-ee4j.github.io/mail/) 2.0 (package `jakarta.mail`),
including:
-* Mail Service: sends MIME messages
-* Message Builder: builds plain text and HTML messages with attachments and
inline images
-* Message ID Provider: allows overwriting default message IDs by custom ones
+* **Mail Service**: sends MIME messages asynchronously
(`CompletableFuture<Void>`)
+* **Message Builder**: builds plain text and HTML messages with attachments
and inline images
+* **Message ID Provider**: allows replacing default message IDs with custom
ones
+The project is built with Java 17 and validated in CI with Java 17 and Java 21.
+
+## Build and Test
+
+```bash
+# Build and run all checks (Checkstyle, PMD, SpotBugs) + unit tests
+mvn clean verify
+
+# Skip integration tests (faster local iteration)
+mvn clean verify -DskipITs
+
+# Run only unit tests
+mvn test
+
+# Run a single unit test class
+mvn test -Dtest=SimpleMailServiceTest
+
+# Run integration tests only
+mvn failsafe:integration-test failsafe:verify
+
+# Run a single integration test class
+mvn failsafe:integration-test -Dit.test=SimpleMailServiceIT
+```
## Examples
### Configuration
-
#### MailService
Example factory configuration
([`SimpleMailServiceConfiguration`](https://github.com/apache/sling-org-apache-sling-commons-messaging-mail/blob/master/src/main/java/org/apache/sling/commons/messaging/mail/internal/SimpleMailServiceConfiguration.java))
for
[`SimpleMailService`](https://github.com/apache/sling-org-apache-sling-commons-messaging-mail/blob/master/src/main/java/org/apache/sling/commons/messaging/mail/internal/SimpleMailService.java):
@@ -51,53 +73,53 @@ Example factory configuration
([`SimpleMessageIdProviderConfiguration`](https://
Create a multipart MIME message with an attachment (`filename`: `song.flac`)
where the HTML part contains an inline image (`cid`: `ska`) and send it:
```
- @Reference
- MailService mailService;
-
- String subject = "Rudy, A Message to You";
- String text = "Stop your messing around\nBetter think of your future\nTime
you straighten right out\nCreating problems in town\n…";
- String html = […];
- byte[] attachment = […];
- byte[] inline = […];
-
- MimeMessage message = mailService.getMessageBuilder()
- .from("[email protected]", "Dandy
Livingstone")
- .to("[email protected]", "The Specials")
- .replyTo("[email protected]");
- .subject(subject)
- .text(text)
- .html(html)
- .attachment(attachment, "audio/flac", "song.flac")
- .inline(inline, "image/png", "ska")
- .build();
-
- mailService.sendMessage(message);
+@Reference
+MailService mailService;
+
+String subject = "Rudy, A Message to You";
+String text = "Stop your messing around\nBetter think of your future\nTime you
straighten right out\nCreating problems in town\n…";
+String html = […];
+byte[] attachment = […];
+byte[] inline = […];
+
+MimeMessage message = mailService.getMessageBuilder()
+ .from("[email protected]", "Dandy
Livingstone")
+ .to("[email protected]", "The Specials")
+ .replyTo("[email protected]")
+ .subject(subject)
+ .text(text)
+ .html(html)
+ .attachment(attachment, "audio/flac", "song.flac")
+ .inline(inline, "image/png", "ska")
+ .build();
+
+mailService.sendMessage(message);
```
## Dependencies
* [Sling Commons
Messaging](https://github.com/apache/sling-org-apache-sling-commons-messaging)
(API)
-* [Sling Commons
Crypto](https://github.com/apache/sling-org-apache-sling-commons-crypto) (for
decrypting encrypted SMTP passwords)
+* [Sling Commons
Crypto](https://github.com/apache/sling-org-apache-sling-commons-crypto)
(decrypting encrypted SMTP passwords)
* [Sling Commons
Threads](https://github.com/apache/sling-org-apache-sling-commons-threads)
-* [Jakarta Mail 2.0](https://jakarta.ee/specifications/mail/2.0/) and [Jakarta
Activation 2.0](https://jakarta.ee/specifications/activation/2.0/) (*OSGified*,
e.g. `org.apache.servicemix.specs.activation-api-2.0.1`)
+* [Jakarta Mail 2.0](https://jakarta.ee/specifications/mail/2.0/) and [Jakarta
Activation 2.0](https://jakarta.ee/specifications/activation/2.0/)
(OSGi-compatible APIs used by the bundle)
## Integration Tests
-Integration tests require a running SMTP server. By default a
[GreenMail](https://greenmail-mail-test.github.io/greenmail/) server is started.
-
-An external SMTP server for validating messages with real mail clients can be
used by setting required properties:
-
- mvn clean install\
- -Dsling.test.mail.smtps.server.external=true\
- -Dsling.test.mail.smtps.ssl.checkserveridentity=true\
- [email protected]\
- -Dsling.test.mail.smtps.host=localhost\
- -Dsling.test.mail.smtps.port=465\
- -Dsling.test.mail.smtps.username=username\
- -Dsling.test.mail.smtps.password=password\
- [email protected]\
- -Dsling.test.mail.from.name=From\ Sender\
- [email protected]\
- -Dsling.test.mail.to.name=To\ Recipient\
- [email protected]\
+Integration tests use
[GreenMail](https://greenmail-mail-test.github.io/greenmail/) by default.
+
+An external SMTP server (for end-to-end validation with real mail clients) can
be used by setting these properties:
+
+ mvn failsafe:integration-test failsafe:verify \
+ -Dsling.test.mail.smtps.server.external=true \
+ -Dsling.test.mail.smtps.ssl.checkserveridentity=true \
+ [email protected] \
+ -Dsling.test.mail.smtps.host=localhost \
+ -Dsling.test.mail.smtps.port=465 \
+ -Dsling.test.mail.smtps.username=username \
+ -Dsling.test.mail.smtps.password=password \
+ [email protected] \
+ -Dsling.test.mail.from.name=From\ Sender \
+ [email protected] \
+ -Dsling.test.mail.to.name=To\ Recipient \
+ [email protected] \
-Dsling.test.mail.replyTo.name=Reply\ To