act-based Gitea runner images do not ship Maven, so the publish job failed with 'mvn: command not found'. Add the Maven Wrapper (Maven 3.9.11) and use ./mvnw. Fail early with a clear message when REGISTRY_TOKEN is not available. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G71TQ5jDETVwdUJxGAwaiT
4.0 KiB
mailsender
OpenPGP encryption for Spring Boot mail: discovers recipients' keys via Web Key Directory (WKD) and sends PGP/MIME (RFC 3156), or hands mail to an encrypting relay. See docs/PLAN.md for the design and milestone status.
Requires JDK 27; the Maven Wrapper (./mvnw) downloads Maven 3.9.11. Built on Spring Boot 4.1.1 and PGPainless 2.0.
./mvnw verify
Modules
| Module | Contents |
|---|---|
mailsender-pgp-core |
WKD key discovery, caching, pinned keys, certificate validation, OpenPGP encryption, PGP/MIME (no Spring) |
mailsender-pgp-spring-boot-autoconfigure |
mail.pgp.* properties and beans |
mailsender-pgp-spring-boot-starter |
dependency bundle for applications |
mailsender-demo |
sample app that sends test mails |
Installation
Releases and snapshots are published to the Gitea Maven registry of the public owner by
.gitea/workflows/publish.yml (push to main → -SNAPSHOT, tag v1.2.3 → 1.2.3):
<repositories>
<repository>
<id>gitea-public</id>
<url>https://YOUR-GITEA-HOST/api/packages/public/maven</url>
</repository>
</repositories>
<dependency>
<groupId>pro.thinhha.mailsender</groupId>
<artifactId>mailsender-pgp-spring-boot-starter</artifactId>
<version>0.1.0</version>
</dependency>
If the packages are not public, add a <server> with id gitea-public and a token with read:package scope to
your settings.xml.
Usage
Add pro.thinhha.mailsender:mailsender-pgp-spring-boot-starter, configure spring.mail.* as usual, and send
through SecureMailSender instead of JavaMailSender:
SendReport report = secureMailSender.send(message); // MimeMessage or SimpleMailMessage
Each recipient's key is looked up via WKD (cached) and validated. The message is then sent PGP/MIME-encrypted to
recipients with a usable key and in plaintext to the rest (logged as a downgrade), or refused with
EncryptionPolicyException if a REQUIRE recipient has no key. SendReport lists the outcome per recipient.
mail:
pgp:
mode: BUILT_IN # or RELAY: hand plaintext to an encrypting gateway (mail.pgp.relay.*)
default-policy: OPPORTUNISTIC # REQUIRE | OPPORTUNISTIC | PLAINTEXT
mixed-mode: SPLIT # or FAIL
recipients:
"[*@partner.example]": REQUIRE
sender-keys: # your own PUBLIC key, so sent copies stay readable
"[noreply@example.com]": file:/etc/mail/noreply.pub.asc
Map keys that are addresses need the [...] brackets. See docs/PLAN.md for all options.
mail.pgp.protected-headers=trueencrypts the real Subject too (RFC 9788); the visible Subject becomes[...].- With Micrometer,
mail.pgp.recipients{outcome,policy,reason},mail.pgp.refused,mail.pgp.key.lookupandmail.pgp.key.cache.sizeare recorded. - With Actuator, expose
pgpkeysto inspect an address (GET /actuator/pgpkeys/{email}) or evict cached keys (DELETE /actuator/pgpkeys/{email}).
Demo app
The demo app sends DEMO_COUNT test mails (default: 1 to test@thinhha.pro) through SecureMailSender and logs
the outcome per recipient: PGP/MIME-encrypted (RFC 3156) when a valid WKD key is found, otherwise plaintext.
Set MAIL_PGP_MODE=RELAY and RELAY_HOST/RELAY_PORT/RELAY_USERNAME/RELAY_PASSWORD to send via a gateway.
./mvnw -q install -DskipTests
SMTP_HOST=smtp.example.com SMTP_PORT=587 \
SMTP_USERNAME=me@example.com SMTP_PASSWORD='app-password' \
DEMO_TO=test@thinhha.pro DEMO_COUNT=1 \
java -jar mailsender-demo/target/mailsender-demo-0.1.0-SNAPSHOT.jar
| Variable | Default | Meaning |
|---|---|---|
SMTP_HOST / SMTP_PORT |
localhost / 587 |
SMTP server |
SMTP_USERNAME / SMTP_PASSWORD |
empty | SMTP credentials |
SMTP_AUTH / SMTP_STARTTLS |
true / true |
set to false for a local test server |
DEMO_TO |
test@thinhha.pro |
recipient |
DEMO_FROM |
SMTP_USERNAME |
sender address |
DEMO_COUNT |
1 |
number of mails |