Files
mailsender/README.md
T
Claude fb52ee2c27 Target JDK 25 LTS instead of JDK 27
maven.compiler.release and the enforcer floor go to 25, and both the
GitHub CI and the Gitea publish workflow use Temurin 25.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G71TQ5jDETVwdUJxGAwaiT
2026-10-12 07:32:18 +00:00

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 25 or newer; 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=true encrypts the real Subject too (RFC 9788); the visible Subject becomes [...].
  • With Micrometer, mail.pgp.recipients{outcome,policy,reason}, mail.pgp.refused, mail.pgp.key.lookup and mail.pgp.key.cache.size are recorded.
  • With Actuator, expose pgpkeys to 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