diff --git a/.circleci/config.yml b/.circleci/config.yml
new file mode 100644
index 000000000..d2c344878
--- /dev/null
+++ b/.circleci/config.yml
@@ -0,0 +1,71 @@
+version: 2.1
+
+orbs:
+ github-maven-deploy: github-maven-deploy/github-maven-deploy@1.3.2
+
+executors:
+ java21-executor:
+ docker:
+ - image: cimg/openjdk:21.0
+
+mvn-build-test-command: &mvn-build-test-command
+ mvn-build-test-command: mvn verify -Ppublish-cli -DexcludeLiveServerTests=true -Dmaven.javadoc.skip=true -Djacoco.skip=true -Dlicense.skip=true
+
+mvn-collect-artifacts-command: &mvn-collect-artifacts-command
+ mvn-collect-artifacts-command: |
+ mkdir -p artifacts/cli
+ cp modules/cli-module/target/*standalone* artifacts/cli/
+
+mvn-deploy-command: &mvn-deploy-command
+ mvn-deploy-command: |
+ mvn -s .circleci/maven-central-settings.xml clean deploy -Ppublish-cli -DdeployAtEnd=true -DperformRelease=true -DskipTests -Dspotbugs.skip=true -Denforcer.skip=true -Djacoco.skip=true -Dossindex.skip=true
+ mvn com.mycila:license-maven-plugin:3.0:remove
+ context: RELEASE_PROFILE_BBOTTEMA
+
+workflows:
+ workflow:
+ jobs:
+ - github-maven-deploy/build-and-test:
+ <<: *mvn-build-test-command
+ <<: *mvn-collect-artifacts-command
+ filters:
+ branches:
+ only: master
+
+ - github-maven-deploy/approve-deploy-patch-version:
+ type: approval
+ requires:
+ - github-maven-deploy/build-and-test
+ - github-maven-deploy/approve-deploy-minor-version:
+ type: approval
+ requires:
+ - github-maven-deploy/build-and-test
+ - github-maven-deploy/approve-deploy-major-version:
+ type: approval
+ requires:
+ - github-maven-deploy/build-and-test
+ - github-maven-deploy/approve-deploy-as-is-version:
+ type: approval
+ requires:
+ - github-maven-deploy/build-and-test
+
+ - github-maven-deploy/deploy-patch-version:
+ executor: java21-executor
+ requires:
+ - github-maven-deploy/approve-deploy-patch-version
+ <<: *mvn-deploy-command
+ - github-maven-deploy/deploy-minor-version:
+ executor: java21-executor
+ requires:
+ - github-maven-deploy/approve-deploy-minor-version
+ <<: *mvn-deploy-command
+ - github-maven-deploy/deploy-major-version:
+ executor: java21-executor
+ requires:
+ - github-maven-deploy/approve-deploy-major-version
+ <<: *mvn-deploy-command
+ - github-maven-deploy/deploy-as-is-version:
+ executor: java21-executor
+ requires:
+ - github-maven-deploy/approve-deploy-as-is-version
+ <<: *mvn-deploy-command
diff --git a/.circleci/maven-central-settings.xml b/.circleci/maven-central-settings.xml
new file mode 100644
index 000000000..7d84bb07a
--- /dev/null
+++ b/.circleci/maven-central-settings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ central
+ ${env.CENTRAL_USERNAME}
+ ${env.CENTRAL_PASSWORD}
+
+
+
+
+
+ gpg
+
+ gpg
+ ${env.GPG_PASSPHRASE}
+
+
+
+
+
+ gpg
+
+
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 000000000..f69503aba
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1 @@
+custom: ["https://paypal.me/bennybottema", "https://www.buymeacoffee.com/bbottema"]
\ No newline at end of file
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 000000000..13cf1bb5b
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,48 @@
+# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
+
+version: 2
+updates:
+ - package-ecosystem: "maven"
+ directory: "/"
+ schedule:
+ interval: "weekly"
+ target-branch: "develop"
+ ignore:
+ - dependency-name: "org.mnode.ical4j:ical4j-vcard"
+ update-types:
+ - "version-update:semver-patch"
+ - "version-update:semver-minor"
+ - "version-update:semver-major"
+ - dependency-name: "info.picocli:picocli"
+ update-types:
+ - "version-update:semver-minor"
+ - "version-update:semver-major"
+ - dependency-name: "org.springframework:spring-framework-bom"
+ update-types:
+ - "version-update:semver-minor"
+ - "version-update:semver-major"
+ - dependency-name: "org.springframework.boot:*"
+ update-types:
+ - "version-update:semver-minor"
+ - "version-update:semver-major"
+ - dependency-name: "org.junit.jupiter:*"
+ versions:
+ - "[6,)"
+ - dependency-name: "org.junit.platform:*"
+ versions:
+ - "[6,)"
+ - dependency-name: "org.mockito:*"
+ versions:
+ - "[5,)"
+ - dependency-name: "org.junit-pioneer:junit-pioneer"
+ versions:
+ - "[2,)"
+ - dependency-name: "com.mycila:license-maven-plugin"
+ versions:
+ - "[5,)"
+ - dependency-name: "org.apache.felix:maven-bundle-plugin"
+ versions:
+ - "[6,)"
+ - dependency-name: "org.apache.karaf.tooling:karaf-maven-plugin"
+ versions:
+ - "[4.4.8,)"
diff --git a/.gitignore b/.gitignore
index 28ef4fcf2..02e5f5fd0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,56 +1,11 @@
-# Created by https://www.gitignore.io
-
-### Intellij ###
-# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm
-
-*.iml
-
-## Directory-based project format:
-.idea/
-# if you remove the above rule, at least ignore the following:
-
-# User-specific stuff:
-# .idea/workspace.xml
-# .idea/tasks.xml
-# .idea/dictionaries
-
-# Sensitive or high-churn files:
-# .idea/dataSources.ids
-# .idea/dataSources.xml
-# .idea/sqlDataSources.xml
-# .idea/dynamic.xml
-# .idea/uiDesigner.xml
-
-# Gradle:
-# .idea/gradle.xml
-# .idea/libraries
-
-# Mongo Explorer plugin:
-# .idea/mongoSettings.xml
-
-## File-based project format:
-*.ipr
-*.iws
-
-## Plugin-specific files:
-
-# IntelliJ
-/out/
-
-# mpeltonen/sbt-idea plugin
-.idea_modules/
-
-# JIRA plugin
-atlassian-ide-plugin.xml
-
-# Crashlytics plugin (for Android Studio and IntelliJ)
-com_crashlytics_export_strings.xml
-crashlytics.properties
-crashlytics-build.properties
-
+/.idea
+/maven-master-project.iml
/target
-
-# Eclipse
-/.settings
-.classpath
-.project
+/modules/jacoco-aggregator-module/target
+/modules/jacoco-aggregator-module/*.iml
+*.iml
+*.log
+/modules/simple-java-mail/src/test/resources/secure-testdata/secure-testdata/
+.atlasarc/
+/build-coverage.sh
+/.maintainer-env.ps1
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 000000000..db14f5156
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "angular-app"]
+ path = simplejavamail.org
+ url = https://github.com/simple-java-mail/simplejavamail.org.git
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 45fbf38b8..000000000
--- a/.travis.yml
+++ /dev/null
@@ -1,12 +0,0 @@
-language: java
-sudo: false
-install: mvn install -DskipFindBugs=true -DskipTests=true -Dmaven.javadoc.skip=true -B -V
-script: mvn clean verify -Dmaven.javadoc.skip=true
-cache:
- directories:
- - $HOME/.m2
-# whitelist
-branches:
- only:
- - master
- - stable
diff --git a/API_EXPANSION_WORKFLOW.md b/API_EXPANSION_WORKFLOW.md
new file mode 100644
index 000000000..3b7552125
--- /dev/null
+++ b/API_EXPANSION_WORKFLOW.md
@@ -0,0 +1,116 @@
+# API Expansion Workflow for Simple Java Mail
+
+This document serves as a blueprint for developers and coding agents when adding new fields or features to the Simple Java Mail API. Following these steps ensures that the new functionality is correctly integrated across all modules, including CLI support, message conversion, and module-specific processing.
+
+For surrounding mechanisms such as optional module loading, CLI data generation, MIME structure selection, and build instrumentation, see [PROJECT_MECHANISMS_CATALOGUE.md](PROJECT_MECHANISMS_CATALOGUE.md).
+
+---
+
+## 1. Core Model Expansion (`core-module`)
+
+The foundation of any new feature usually starts with updating the core model objects.
+
+- **Update Model Classes**: Add the new field to the relevant model class (e.g., `Email`, `Recipient`).
+ - Use Lombok `@Value` for immutability where appropriate.
+ - Ensure the class remains `Serializable`.
+ - Update `serialVersionUID` if the change breaks binary compatibility.
+- **Update Internal Interfaces**: If the model has an internal interface (e.g., `InternalEmail`), ensure it's updated if necessary.
+
+## 2. API Interface Expansion (`core-module`)
+
+New fields must be accessible through the fluent Builder API.
+
+- **Update Builder Interfaces**: Add new methods to the public builder interfaces (e.g., `EmailPopulatingBuilder`, `IRecipientsBuilder`, `IRecipientBuilder`).
+- **CLI Compatibility Rules**:
+ - **Parameter Types**: Use simple types (`String`, `boolean`, `int`, `long`) or types that have an existing `ValueInterpreter` in the `cli-module` (e.g., `X509Certificate`, `File`, `URL`, `Date`).
+ - **Avoid Collections**: Picocli mapping works best with individual values or arrays. Avoid `Collection` or `Map` in signatures intended for CLI use. Provide overloads if necessary.
+ - **Javadoc**: Provide complete Javadoc for all new methods and parameters. The CLI module uses this to generate help text.
+ - **Annotations**: Use `@Cli.ExcludeApi` for methods that should not be exposed to the CLI (e.g., those taking complex Java-only objects). Use `@Cli.OptionNameOverride` if the method name isn't ideal for a CLI flag. Use `@Cli.Optional` on parameters that may be omitted from the CLI; keep JetBrains `@Nullable` for Java/API nullability only.
+
+## 3. Core Implementation (`simple-java-mail`)
+
+Implement the new API methods and ensure data propagation.
+
+- **Update Builder Implementations**: Update `EmailPopulatingBuilderImpl`, `RecipientsBuilder`, `RecipientBuilder`, etc.
+- **CRITICAL: Data Propagation**:
+ - Ensure that "copy" methods (e.g., `withRecipient(Recipient)`) and delegation methods correctly copy the new field.
+ - Failure to do this will result in data being lost when `EmailBuilder.copying(email)` is used or when builders delegate to each other.
+- **Update Email Constructor**: Ensure the `Email` constructor copies the new field from the builder.
+- **Utility Classes**: Update `MiscUtil` if it contains helper methods for object creation or parsing (e.g., `interpretRecipient`).
+
+## 4. Message Conversion & Processing (`simple-java-mail`)
+
+The new field must eventually affect the produced `MimeMessage`.
+
+- **MimeMessageHelper**: Update this class if the new field translates directly to a standard MimeMessage header or property (e.g., a new recipient type or a standard header).
+- **SpecializedMimeMessageProducer**: Update the `populateMimeMessage` method if the new field requires logic to decide how the `MimeMessage` is constructed or if it triggers module-specific processing (like S/MIME or DKIM).
+
+## 5. Module-Specific Integration
+
+If the feature relates to a specific module, update that module.
+
+- **S/MIME (`smime-module`)**:
+ - Update `SMIMEModule` interface in `core-module`.
+ - Implement the logic in `SMIMESupport`.
+- **Outlook (`outlook-module`)**:
+ - Update `OutlookEmailConverter` if the new field has an equivalent in Outlook `.msg` files.
+- **Spring (`spring-module`)**:
+ - Update `SimpleJavaMailProperties` to include the new property.
+ - Update `SimpleJavaMailSpringSupport` to map the Spring property to the `ConfigLoader` and builders.
+
+## 6. Defaults & Overrides (EmailGovernance)
+
+Public API configuration should have parity across the Java builder API and the Java defaults/overrides mechanism. When a new user-facing field is added to `Email` or a related model and that value can be represented on a source object, integrate it with the governance layer. This allows projects that centralize behavior through default or override `Email` objects to use the same feature without per-message Java code.
+
+Only skip defaults/overrides integration when the value cannot sensibly be represented on the source model, when it depends on runtime state that cannot be copied, or when it is a per-recipient sub-field that should be set while constructing recipients instead. Document the reason in the implementing issue or PR.
+
+- Add EmailProperty entry (core-module)
+ - If the field is on Email and needs default/override resolution, add a corresponding constant to org.simplejavamail.internal.config.EmailProperty.
+ - Mark it as collection-based when the value is a collection so merging is applied instead of replacement.
+- Apply default values (simple-java-mail)
+ - In EmailGovernanceImpl.newDefaultsEmailWithDefaultDefaults(), derive a sensible default from ConfigLoader.Property if applicable and set it on the builder.
+- Apply defaults/overrides to provided Email (simple-java-mail)
+ - In EmailGovernanceImpl.produceEmailApplyingDefaultsAndOverrides(), resolve values using MiscUtil.overrideOrProvideOrDefaultProperty / overrideAndOrProvideAndOrDefaultCollection and apply them to the builder.
+ - Ensure ignoringDefaults / ignoringOverrides and the per-property suppression sets are respected (this comes for free when using the MiscUtil helpers).
+- Module-triggering fields
+ - If the new field influences downstream processing (e.g., per-recipient S/MIME), make sure SpecializedMimeMessageProducer considers the presence of the field when deciding to trigger the corresponding module.
+ - Ensure the corresponding module implementation tolerates null global config if the trigger is a per-item value.
+- Per-recipient fields
+ - Do not try to default/override sub-fields inside Recipient via governance. Instead, set them when building recipients (through IRecipientsBuilder / RecipientsBuilder) and let module logic act on their presence.
+
+## 7. Mailer Configuration API Expansion
+
+Mailer configuration API changes are separate from Email model/defaults/overrides governance. Use this path for SMTP/session/runtime behavior such as connection settings, proxy behavior, debug output, transport mode, trust settings, and other Mailer-owned state.
+
+- **Public API**: Add methods to `MailerGenericBuilder`, `MailerRegularBuilder`, or `MailerFromSessionBuilder` based on ownership. Provide complete Javadoc and CLI annotations because the CLI help text is generated from these builder APIs.
+- **Operational Ownership**: Add state to `OperationalConfig`, `ServerConfig`, `ProxyConfig`, or another existing Mailer config interface according to the behavior being configured.
+- **Property Defaults**: If the setting is property-friendly, add a `ConfigLoader.Property` entry and resolve it when creating the builder/config object. This keeps property-file driven projects configurable without Java code.
+- **Transport Strategy Mapping**: When a Mailer setting maps to Jakarta Mail properties, keep the `mail.smtp.*` / `mail.smtps.*` names behind `TransportStrategy` helper methods and apply them only after the effective strategy is known.
+- **Spring Mapping**: If the property belongs to the public configuration surface, add it to Spring support and Spring Boot metadata generation classes.
+- **Verification**: Test the Java builder path, property/config path, Spring mapping when applicable, and the final `Session` properties.
+- **Governance Boundary**: Do not wire Mailer connection/session settings into Email defaults/overrides. That mechanism applies to Email/message state and related model values.
+
+## 8. Configuration Support (`core-module`)
+
+Public API configuration should also have parity with property-backed configuration. When a Java API option represents configurable behavior and can be expressed as strings, booleans, numbers, enums, files, or other property-friendly values, expose it through configuration properties as well. This keeps property-file driven projects from needing a Java-only escape hatch for the same feature.
+
+Only skip property configuration when the value cannot be expressed safely or clearly in properties, has no sensible global default, or would require complex object construction that belongs in Java code. Document the reason in the implementing issue or PR.
+
+- **ConfigLoader**: Add a new entry to the `Property` enum.
+- **Data Resolution**: Ensure the new property is used in `EmailGovernanceImpl`, the Mailer builder/config object, or wherever defaults are applied.
+- **Spring Mapping**: If the property belongs to the public configuration surface, add the corresponding Spring property and map it through `SimpleJavaMailSpringSupport`.
+- **Dynamic Property Collections**: For collection-style namespaces such as `simplejavamail.defaults.connectionpool.clusters.*`, keep parsing and validation centralized in `ConfigLoader`. Spring support should forward the whole namespace into `ConfigLoader` and Spring Boot metadata should describe the nested shape, rather than duplicating alias/key resolution.
+
+## 9. Verification Surface Areas
+
+Always verify the following areas:
+
+- **Builder Chain**: Verify the field is preserved across multiple builder calls.
+- **Email Copying**: Use `EmailBuilder.copying(email).buildEmail()` and verify the field is still there.
+- **CLI Help**: Run the CLI with `--help` for the relevant command to ensure the new option is documented and has the correct parameter labels.
+- **End-to-End**: Verify the field actually affects the final `MimeMessage` (e.g., by inspecting the produced EML or using a dummy SMTP server).
+
+There are junit tests available to verify the above or provide a blueprint for new tests.
+
+---
+*Blueprint version 1.0*
diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md
new file mode 100644
index 000000000..0790c473b
--- /dev/null
+++ b/DEVELOPMENT.md
@@ -0,0 +1,70 @@
+# Developer Environment Setup
+
+This document records environment requirements and constraints for building Simple Java Mail.
+It is intended for both human developers and coding agents starting new sessions.
+
+For a catalogue of cross-cutting project mechanisms, see [PROJECT_MECHANISMS_CATALOGUE.md](PROJECT_MECHANISMS_CATALOGUE.md).
+For issue, Dependabot, and release handling workflows, see [MAINTAINER_WORKFLOW.md](MAINTAINER_WORKFLOW.md).
+
+---
+
+## Java Version
+
+**Simple Java Mail must remain Java 8-compatible. Use JDK 8 for dependency bumps and compatibility validation.**
+
+The system-wide `JAVA_HOME` may point to a newer JDK, but Simple Java Mail is **incompatible with Java 12+**
+for CLI metadata generation. Specifically:
+
+- The CLI module serialises `java.lang.reflect.Method` objects into `cli.data` using Kryo.
+ On Java 12+, the Java module system and internal JVM changes break this serialisation.
+- The `therapi-runtime-javadoc` Javadoc scanning used by the CLI module encounters NPEs on
+ synthetic/bridge methods exposed differently by newer JVM reflection APIs.
+
+**Before building, ensure a Java 8 JDK is active.**
+
+Use a local, gitignored `.maintainer-env.ps1` file for machine-specific paths:
+
+```powershell
+# .maintainer-env.ps1, not committed
+$env:JAVA_HOME = ""
+$env:PATH = "$env:JAVA_HOME\bin;$env:PATH"
+$env:MAVEN_OPTS = "-Djavax.net.ssl.trustStoreType=WINDOWS-ROOT"
+$env:SJM_GH = ""
+```
+
+Then load it in the shell used for builds:
+
+```powershell
+. .\.maintainer-env.ps1
+java -version # should report 1.8.x
+```
+
+---
+
+## Build
+
+Standard full build (skipping tests and slow checks):
+
+```powershell
+mvn verify -DskipTests -Dmaven.javadoc.skip=true
+```
+
+After any build that ran `license:format`, clean up auto-generated headers before committing:
+
+```powershell
+mvn com.mycila:license-maven-plugin:3.0:remove
+```
+
+---
+
+## Known Build Constraints
+
+- **ossindex** (Sonatype vulnerability scan) has been removed from the build lifecycle.
+ It is configured with `` (empty phase) in the root `pom.xml` to unbind it.
+- **junit-pioneer** is pinned to `1.9.1` because the 2.x line ships Java 11 class files.
+ JUnit artifacts may be updated only while preserving Java 8 bytecode compatibility.
+- **cli-module** uses `log4j-slf4j2-impl` (not `log4j-slf4j-impl`) because `slf4j-api`
+ is at version 2.x which requires the SLF4J 2 bridge adapter.
+- **`cli.data`** (`modules/cli-module/src/main/resources/cli.data`) is a committed binary
+ generated by the CLI module's Kryo serialisation. It must be regenerated whenever the
+ CLI API changes. **Do not regenerate it on Java 12+ - use JDK 8.**
diff --git a/src/main/webapp/LICENSE b/LICENSE
similarity index 99%
rename from src/main/webapp/LICENSE
rename to LICENSE
index 717636af3..b9225929e 100644
--- a/src/main/webapp/LICENSE
+++ b/LICENSE
@@ -1,4 +1,3 @@
-
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
@@ -187,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
- Copyright 2008 - 2016 Benny Bottema
+ Copyright 2009 Benny Bottema
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/MAINTAINER_WORKFLOW.md b/MAINTAINER_WORKFLOW.md
new file mode 100644
index 000000000..c57afb4bf
--- /dev/null
+++ b/MAINTAINER_WORKFLOW.md
@@ -0,0 +1,402 @@
+# Maintainer Workflow
+
+This document describes the normal Simple Java Mail maintenance loop for coding agents and human maintainers.
+It is intentionally one workflow with switches, so prompts like these can all follow the same backbone:
+
+- "Can you pick up #743 and release it as patch?"
+- "There are a few issues open, have a look at them and fix them without releasing."
+- "Can you handle the dependabot PRs and release as patch?"
+- "Fix up that last issue and prepare for a minor release."
+
+For API additions, read [API_EXPANSION_WORKFLOW.md](API_EXPANSION_WORKFLOW.md) as part of the implementation phase.
+For cross-cutting mechanisms such as CLI metadata, optional modules, MIME resources, and instrumentation, read
+[PROJECT_MECHANISMS_CATALOGUE.md](PROJECT_MECHANISMS_CATALOGUE.md).
+
+---
+
+## 1. Interpret the Request
+
+Classify the request before editing anything:
+
+| Request shape | Main mode | Release? |
+|------------------------------------------------------|----------------------------------|-------------------------------------------------------------------------|
+| "Pick up #N and release it as patch" | Issue-driven fix | Yes, patch release after merge |
+| "Look at open issues and fix them without releasing" | Triage and implementation | No release; keep work on `develop` |
+| "Handle dependabot PRs and release as patch" | Dependency PR batch | Yes, patch release after verification |
+| "Fix the last issue and prepare for a minor release" | Implementation plus release prep | Usually stop before approving release unless explicitly told to release |
+
+If the user explicitly says not to release, do not release.
+If the user explicitly says to release, carry the release through CircleCI approval, Maven Central verification, GitHub release notes, and final branch sync.
+
+---
+
+## 2. Start Clean
+
+Always ground the session in live state:
+
+```powershell
+git status --short --branch
+git fetch --prune --tags origin
+git branch -vv
+```
+
+Load local machine paths from the gitignored maintainer environment file when it exists:
+
+```powershell
+if (Test-Path .\.maintainer-env.ps1) {
+ . .\.maintainer-env.ps1
+}
+```
+
+Use `gh` from `PATH`, or `$env:SJM_GH` from `.maintainer-env.ps1` when the executable needs an explicit local path:
+
+```powershell
+$gh = if ($env:SJM_GH) { $env:SJM_GH } else { "gh" }
+& $gh auth status
+```
+
+Local verification should use JDK 8:
+
+```powershell
+if (-not $env:JAVA_HOME) {
+ throw "Load .maintainer-env.ps1 or set JAVA_HOME to a Java 8 JDK first."
+}
+java -version # should report 1.8.x
+```
+
+Do not work around Maven Central or TLS failures with insecure SSL flags until the Windows trust-store option above has been tried.
+
+Past correction to preserve: a retry is not permission to change repo state. If a requested retry depends on a clean/synced branch gate,
+re-check the gate and proceed only if it already passes, unless the user explicitly approves syncing or fast-forwarding first.
+
+---
+
+## 3. Choose the Work Branch
+
+Implementation work normally happens on `develop`.
+
+```powershell
+git switch develop
+git pull --ff-only origin develop
+```
+
+Release work happens by merging `develop` into `master` after the release candidate is ready:
+
+```powershell
+git switch master
+git pull --ff-only origin master
+git merge --ff-only develop
+git push origin master
+```
+
+If a fast-forward merge is not possible, stop and inspect the divergence. Do not rewrite shared branches unless the user explicitly asks.
+
+---
+
+## 4. Triage GitHub Work
+
+Inspect issues or PRs directly through `gh`.
+
+```powershell
+& $gh issue view 743 --repo bbottema/simple-java-mail --comments --json number,title,body,labels,milestone,author,url,comments
+& $gh issue list --repo bbottema/simple-java-mail --state open --limit 50 --json number,title,labels,milestone,author,url
+& $gh pr list --repo bbottema/simple-java-mail --state open --limit 50 --json number,title,author,baseRefName,headRefName,url,labels,statusCheckRollup
+```
+
+This installed `gh` does not expose a top-level milestone command; use the API:
+
+```powershell
+& $gh api repos/bbottema/simple-java-mail/milestones --paginate --jq '.[] | [.number,.title,.state,.open_issues,.closed_issues] | @tsv'
+```
+
+Use existing labels. Common labels include:
+
+- `bug`, `enhancement`, `maintenance`, `documentation`, `security`, `dependencies`, `3rdparty-problem`
+- `Priority-Low`, `Priority-Medium`, `Priority-High`
+- `invalid`, `question`, `need-user-input`, `will close soon`
+
+When an issue belongs upstream, confirm whether the fix belongs in a sibling repo first. If it does, create or update the upstream issue, fix and release the upstream library, then update Simple Java Mail.
+
+For sibling repositories:
+
+- Check hidden CI files such as `.circleci/config.yml`; do not stop at visible-file scans.
+- Verify the sibling repo is clean and aligned with its upstream before changing it.
+- Do not fast-forward, push, tag, or release sibling repositories unless that was explicitly requested or approved.
+- If a sibling repository is released as part of the fix, also complete its GitHub release bookkeeping: fixed issue comment/close,
+ milestone close, GitHub release for the tag, and any relevant usage example.
+- When copying or flattening parent/dependency configuration, verify the sibling source project is current and compare against the released Maven Central version. Do not bake stale local checkout state into this project.
+
+---
+
+## 5. Implement
+
+Read the relevant code and tests before editing. Use TDD when the issue is reproducible.
+
+For public API or config changes:
+
+- Follow [API_EXPANSION_WORKFLOW.md](API_EXPANSION_WORKFLOW.md).
+- Keep Java API, property configuration, Spring support, defaults/overrides, CLI exposure, and website/README docs aligned where applicable.
+- Do not expose low-level Jakarta Mail terminology when Simple Java Mail can provide a higher-level concept.
+- Prefer builder APIs that hide underlying property names and transport-specific details.
+
+For CLI-related changes:
+
+- CLI generation depends on Javadocs and builder reflection.
+- Regenerate and commit `modules/cli-module/src/main/resources/cli.data` and `modules/cli-module/src/main/resources/therapi.data` when the CLI surface changes.
+- Use `-Ppublish-cli` when verifying release packaging.
+- Avoid Java 12+ for local CLI metadata regeneration; use JDK 8.
+
+For dependency PRs:
+
+- Preserve Java 8 compatibility. Do not accept dependency lines that require Java 9+ or Java 11+.
+- Update `.github/dependabot.yml` ignore rules when Dependabot repeatedly proposes non-Java-8-compatible versions.
+- Keep release notes concise. Prefer one dependency-maintenance roll-up over one noisy bullet per automated PR unless the change matters to users.
+
+---
+
+## 6. Verify
+
+Use focused tests first, then full verification before release.
+
+Useful focused commands:
+
+```powershell
+mvn -pl modules/simple-java-mail -Dtest=SomeTest test
+mvn -pl modules/cli-module -am -Ppublish-cli -DskipTests package
+```
+
+Before merging to `master` for a release, run a full JDK 8 verification:
+
+```powershell
+mvn clean verify -Ppublish-cli -DexcludeLiveServerTests=true
+```
+
+If Norton or local certificate interception breaks Maven, retry with:
+
+```powershell
+$env:MAVEN_OPTS = "-Djavax.net.ssl.trustStoreType=WINDOWS-ROOT"
+```
+
+After any build that ran `license:format`, remove generated headers before committing unless the release artifact itself is being checked:
+
+```powershell
+mvn com.mycila:license-maven-plugin:3.0:remove
+```
+
+For release packaging checks, confirm the standalone CLI artifacts are built:
+
+```powershell
+Get-ChildItem modules\cli-module\target\*standalone-cli*
+```
+
+For release artifact checks, inspect the published source jars rather than committing generated headers to the working tree.
+
+---
+
+## 7. Update Documentation and Release Notes
+
+For user-facing changes:
+
+- Update `README.md` release notes.
+- Keep `RELEASE.txt` in sync with the README release notes.
+- Keep `RELEASE_HISTORY.md` complete and stand-alone.
+- Update website source under `simplejavamail.org` for API/config documentation changes, but do not push the website unless explicitly approved.
+- Add migration notes for behavior changes, removed API, changed defaults, or compatibility-impacting fixes.
+
+Release-note retention:
+
+- `RELEASE.txt` keeps the full release history.
+- `RELEASE_HISTORY.md` also keeps the full release history and must stand alone. It starts with the latest release and continues through the archive; do not move notes out of it just because README shows recent progress too.
+- `README.md` shows recent progress, not the full archive. Keep everything under one `Latest progress` heading.
+- Keep the last major release visible in `README.md` until a newer major release exists, even after minor or patch releases ship.
+- Major releases create the primary release-note story. A narrative section such as `The Short Version` is acceptable for a major release when it helps explain the release line.
+- Regular minor and patch releases should usually be concise bullets that speak for themselves and link to GitHub issues for details. Do not force the major-release narrative format onto ordinary releases.
+- Keep the latest-release notes aligned across `README.md`, `RELEASE.txt`, `RELEASE_HISTORY.md`, and the GitHub release body, with detail level adjusted to each surface. Alignment does not permit the GitHub release body to delegate its content to another file.
+- Minor releases normally create their own primary release-note entry. If a minor release follows closely in the wake of a major release and is still part of that same release wave, absorb it into the current major-line notes instead.
+- Patch releases are absorbed into their parent minor release notes in the same primary note style. Do not create a separate patch-release story unless the user explicitly asks.
+- When a patch is absorbed, place each change in the section where it belongs: bug fixes under fixes, dependency bumps under dependencies, packaging fixes under build/release maintenance, and API/docs additions under the relevant feature or enhancement section.
+- The active release-note header may be a version range, for example `v9.0.0 - v9.0.2`, while the body remains organized by feature/fix/dependency sections.
+- When a release-note heading covers more than one version, prefix every bullet with the exact version that first released that change, for example `- **v9.0.2:** ...`. A bullet may omit its version only when its heading names exactly one version.
+- Within each section of a multi-version release-note entry, order the version-prefixed bullets by release number in descending order (newest first). Keep bullets from the same version together and retain their logical editorial order within that version group.
+- Never combine changes first released in different versions into one bullet. Split mixed maintenance or dependency summaries by release version so every prefix remains unambiguous.
+- Create one GitHub release for every published tag, including patches whose repository notes are absorbed into a version range. Never omit a patch release or fold it into an adjacent tag's GitHub release.
+- Every GitHub release title and body must describe one tag only; never roll multiple versions into a GitHub release title or treat another tag's changes as part of that release.
+- Every GitHub release body, including a patch release, must be a permanent, self-contained record of that tagged release. State what changed in that version and any user-relevant compatibility decisions directly in the body.
+- Links to `README.md`, `RELEASE_HISTORY.md`, pull requests, issues, or Maven Central are supporting references only. Never use a link or wording such as "see the release notes" as a substitute for the release's own change summary.
+- A patch release can remain concise and its repository notes can still be absorbed into the parent minor range, but its GitHub release body must independently explain the patch without requiring the reader to open another page.
+- Write GitHub release notes from facts fixed at the tag. Do not depend on mutable branch content or on documentation whose visible focus will change with a later release.
+- Keep build, test, packaging-validation, and release-process evidence out of GitHub release bodies. Verification belongs in the internal release checklist; published notes should contain only changes and compatibility information readers need.
+- Attach release assets only to their matching tag. Versioned asset filenames and artifact contents must agree with the GitHub release tag.
+- For older archived release groups only, a compact secondary format with each bullet prefixed by the concrete release version is fine.
+
+The website checkout is deploy-sensitive and separate from the root repo. Keep root and website status, staging, commit, and push flows separate.
+Use the root repo as source of truth for API/config names, and patch website docs only for proven mismatches.
+
+For non-user-facing maintenance:
+
+- Keep notes short or omit them.
+- Do not bloat release notes with internal CI details unless users may hit the behavior directly.
+- Avoid release-note text that only makes sense to maintainers, such as internal heap, metadata, or "remaining work" phrasing.
+- Group routine dependency updates into a compact roll-up unless a dependency change is directly relevant to users.
+
+For GitHub comments:
+
+- Closing a user issue should include a short summary and a usage example when useful.
+- Do not sign off comments with test evidence unless the user asks for it.
+- After a release, add a short availability comment to related GitHub issues that were fixed or materially affected by the release.
+- Comments should stand alone for the issue reporter. Avoid context-dependent wording such as "remaining" unless the comment also links the related issue or commit that explains the split.
+- When a fix is split across layers, link the related GitHub issues or commits so the thread explains the whole path.
+
+---
+
+## 8. Commit and Push
+
+Stage selectively and inspect the staged diff:
+
+```powershell
+git status --short
+git diff
+git add
+git diff --cached --check
+git diff --cached --stat
+git commit -m "fix(scope): concise summary"
+```
+
+Use semantic commit subjects: `action(subject): summary, multiline allowed`
+
+Keep unrelated changes out of the commit. Split docs, release notes, build fixes, and implementation work when they are independently meaningful.
+
+For non-code-only changes such as release-note cleanup, issue-bookkeeping docs, or website TODO notes, add `[skip ci]` to the commit subject unless the user explicitly wants CI to run.
+Do not use `[skip ci]` for implementation, build, dependency, generated CLI metadata, or release-lane fixes that need CI validation.
+
+Push implementation work to `develop` unless preparing a release:
+
+```powershell
+git push origin develop
+```
+
+---
+
+## 9. Close or Update Issues Without Releasing
+
+If the user asked to fix without releasing:
+
+1. Push `develop`.
+2. Update the issue with a concise summary and usage example when relevant.
+3. Apply existing labels and the intended milestone if known.
+4. Close only issues that are fully fixed.
+5. Leave release notes in an unreleased section.
+6. Report clean status and the issue links.
+
+Do not merge to `master` or approve CircleCI release gates.
+
+---
+
+## 10. Release
+
+Only release when the user asked for it.
+
+Before release:
+
+1. Confirm `develop` is green locally with JDK 8.
+2. Confirm README and `RELEASE.txt` are in sync.
+3. Confirm no unrelated local changes remain.
+4. Merge `develop` into `master` with a fast-forward merge.
+5. Push `master`.
+
+Do not modify project POM versions to prepare a release. The CircleCI release workflow owns version bumping and tagging.
+After release, the checked-in POM version should represent the current released version, not the next possible version.
+If CircleCI successfully published to Maven Central but failed to update the repository, repair the repository manually:
+
+```powershell
+mvn versions:set "-DnewVersion=x.y.z"
+git add pom.xml modules/*/pom.xml modules/cli-module/src/main/resources/therapi.data
+git commit -m "released x.y.z [skip ci]"
+git tag x.y.z
+git push origin master --tags
+```
+
+Only use that manual version/tag repair after confirming Maven Central has the version and CircleCI failed before pushing the release commit or tag.
+
+CircleCI will run `build-and-test` on `master`. The workflow exposes four approval gates:
+
+- `approve-deploy-patch-version`
+- `approve-deploy-minor-version`
+- `approve-deploy-major-version`
+- `approve-deploy-as-is-version`
+
+Approve only the requested gate. The CircleCI CLI is useful for setup, diagnostics, config, and pipeline commands, but the installed CLI may not expose workflow approval commands.
+When approval has to be automated, use the CircleCI API with the CLI token and identify the workflow and approval job first; do not approve by guesswork.
+
+After the deploy job finishes:
+
+1. Fetch tags and branch updates.
+2. Verify the new version exists in Maven Central.
+3. Verify the published sources contain license headers.
+4. Verify `cli-module` includes `standalone-cli.tar` and `standalone-cli.zip`.
+5. Create or update the GitHub release with a self-contained, tag-specific body that permanently records that version's changes and compatibility notes without internal verification evidence.
+6. Attach the release assets: CLI standalone archives and sample logging configs.
+7. Close the release milestone after all fixed issues are closed.
+8. Fast-forward `develop` to `master` and push `develop`.
+
+If a published artifact is wrong or missing, assume the Central release is immutable. Fix the release lane and ship a patch release. Fold the patch changes into the parent repository notes using the release-note decision tree above, while giving the patch tag its own concise, self-contained GitHub release body.
+
+Useful checks:
+
+```powershell
+$version = "9.0.1"
+Invoke-WebRequest -UseBasicParsing -Uri "https://repo1.maven.org/maven2/org/simplejavamail/simple-java-mail/$version/simple-java-mail-$version.pom"
+(Invoke-WebRequest -UseBasicParsing -Uri "https://repo1.maven.org/maven2/org/simplejavamail/cli-module/$version/").Links |
+ Select-Object -ExpandProperty href |
+ Where-Object { $_ -match "standalone-cli" }
+```
+
+For a normal release, create a GitHub release for the tag:
+
+```powershell
+& $gh release create $version --repo bbottema/simple-java-mail --title "v$version" --notes-file RELEASE_NOTES.md
+```
+
+For a special packaging patch, the repository notes still roll into the parent release range, but the patch tag must always have its own GitHub release with a body that states the packaging problem and correction directly. Do not publish a pointer-only release body or attach the patch's versioned artifacts to another tag.
+
+---
+
+## 11. Dependabot Patch Release
+
+Dependabot PR handling follows the same workflow with extra Java 8 caution:
+
+1. List open PRs and identify Dependabot PRs.
+2. Check each proposed dependency for Java 8 bytecode/runtime compatibility.
+3. Update or add `.github/dependabot.yml` ignores for impossible upgrade lines.
+4. Merge compatible PRs into `develop`.
+5. Run full JDK 8 verification.
+6. Add a compact dependency-maintenance release-note entry.
+7. Release as patch only if requested.
+
+If Dependabot keeps reopening the same incompatible upgrade, fix the ignore rule before trying to out-click it.
+
+---
+
+## 12. Definition of Done
+
+For a non-release task:
+
+- Implementation committed and pushed to `develop`.
+- Relevant tests pass or skipped tests are explained.
+- GitHub issues/PRs are updated.
+- Release notes are updated when user-facing.
+- Worktree is clean.
+
+For a release task:
+
+- `master` and `develop` are aligned after release.
+- The release tag exists remotely.
+- Maven Central has the released artifacts.
+- CLI standalone ZIP/TAR exist for `cli-module`.
+- The GitHub release has the CLI standalone ZIP/TAR and sample logging config assets.
+- A separate GitHub release exists for the current tag; it is not folded into another tag's release.
+- The GitHub release body is self-contained and tag-specific: it identifies that version's changes and compatibility impact without relying on README, release-history, issue, or pull-request links for essential meaning.
+- The GitHub release body contains no build/test verification evidence or internal release-process commentary.
+- Every multi-version repository release-note section has version-prefixed bullets ordered newest first.
+- Related GitHub issues have a short release-availability comment when applicable.
+- Worktree is clean.
diff --git a/MIME_RESOURCE_NAMING_REPORT.md b/MIME_RESOURCE_NAMING_REPORT.md
new file mode 100644
index 000000000..c6a94f319
--- /dev/null
+++ b/MIME_RESOURCE_NAMING_REPORT.md
@@ -0,0 +1,279 @@
+# MIME Resource Naming And Content-ID Report
+
+This report scopes the long-running attachment, embedded image, resource name, filename, and Content-ID problem areas in Simple Java Mail. It is intended as the implementation guardrail for future fixes, so the next change can preserve the behavior that is already correct and address only the remaining ambiguity.
+
+## Current Behavioral Contract
+
+### Sending embedded images
+
+Manual embedded images still support the historical shorthand where the embedded resource name is the HTML `cid:` contract:
+
+```java
+EmailBuilder.startingBlank()
+ .withHTMLText("")
+ .withEmbeddedImage("logo", dataSource);
+```
+
+The caller-facing name passed to `withEmbeddedImage(name, dataSource)` is the value that HTML must reference as `cid:name`. It must not be silently repaired with a datasource extension. The MIME header wraps it as `Content-ID: `.
+
+The corrected API also supports an explicit Content-ID:
+
+```java
+EmailBuilder.startingBlank()
+ .withHTMLText("")
+ .withEmbeddedImage("logo.png", dataSource, "logo-2026");
+```
+
+For this overload, the resource name remains filename/resource metadata and the explicit `contentId` is the HTML reference identity. Surrounding angle brackets are tolerated at the API boundary and stripped before MIME output; CRLF and interior angle brackets are rejected as invalid header content.
+
+Current anchors:
+
+- [EmailPopulatingBuilder.java](modules/core-module/src/main/java/org/simplejavamail/api/email/EmailPopulatingBuilder.java) documents that embedded image `name` is the body reference name.
+- [EmailPopulatingBuilderImpl.java](modules/simple-java-mail/src/main/java/org/simplejavamail/email/internal/EmailPopulatingBuilderImpl.java) requires a non-empty name for byte-array embedded images and requires either an explicit name, datasource name, or explicit Content-ID for datasource-backed embedded images.
+- [AttachmentResource.java](modules/core-module/src/main/java/org/simplejavamail/api/email/AttachmentResource.java) stores optional explicit Content-ID metadata separately from the resource name.
+- [MimeMessageHelper.java](modules/simple-java-mail/src/main/java/org/simplejavamail/converter/internal/mimemessage/MimeMessageHelper.java) writes the final `Content-ID` header.
+
+### Sending attachments
+
+Attachments have two different identifiers:
+
+- The visible/download filename.
+- The MIME `Content-ID`.
+
+For visible filenames, the current fallback order is:
+
+1. explicit `AttachmentResource.getName()`
+2. `DataSource.getName()`
+3. generated `resource`
+
+For attachment Content-ID values, explicit `AttachmentResource.getContentId()` wins. If no explicit Content-ID is provided, the send-side fallback is an opaque generated ID of the form `sjm-@simplejavamail.generated`. This prevents clients from treating multiple same-name attachments as the same body part without deriving an invalid Content-ID from a user filename. Generated Simple Java Mail attachment IDs are transport-only and are dropped when parsing back into the clean `Email` model.
+
+Current anchor:
+
+- [MimeMessageHelper.java](modules/simple-java-mail/src/main/java/org/simplejavamail/converter/internal/mimemessage/MimeMessageHelper.java)
+- [EmailConverter.userProvidedContentId(...)](modules/simple-java-mail/src/main/java/org/simplejavamail/converter/EmailConverter.java)
+
+### Dynamic embedded image resolution
+
+Dynamic embedded image resolution is a separate send-side path. If HTML contains an image source that is not already `cid:...`, the builder can resolve it from file, classpath, or URL settings, generate a random CID, add an embedded image under that CID, and rewrite the HTML to `cid:`.
+
+Current anchor:
+
+- [EmailPopulatingBuilderImpl.buildEmail()](modules/simple-java-mail/src/main/java/org/simplejavamail/email/internal/EmailPopulatingBuilderImpl.java)
+
+### Receiving and parsing
+
+Parsing is deliberately more permissive than sending because real messages from Gmail, Outlook, Apple Mail, and other clients disagree about `Content-Disposition`, `Content-ID`, filenames, and `multipart/related` structure.
+
+Current parse rules:
+
+- A body part with a Content-ID can enter the CID map.
+- A body part without inline disposition, or without Content-ID, is also treated as an attachment.
+- Filename/name metadata and Content-ID metadata are parsed separately.
+- A real filename wins as the resource name; Content-ID is only a name fallback when the filename is missing or the parser's placeholder attachment name.
+- After parsing, CID-map entries not referenced by `cid:` in HTML are moved to attachments.
+- Since `#491`, a part with `Content-Disposition: attachment` and a Content-ID can be both a downloadable attachment and an embedded resource when HTML references that Content-ID.
+- Explicit/custom Content-ID values survive conversion into `AttachmentResource`; generated `sjm-...@simplejavamail.generated` values do not.
+
+Current anchors:
+
+- [MimeMessageParser.parseMimePartTree(...)](modules/simple-java-mail/src/main/java/org/simplejavamail/converter/internal/mimemessage/MimeMessageParser.java)
+- [MimeMessageParser.resolveInvalidEmbeddedImagesAsAttachments(...)](modules/simple-java-mail/src/main/java/org/simplejavamail/converter/internal/mimemessage/MimeMessageParser.java)
+- [OutlookEmailConverter.java](modules/outlook-module/src/main/java/org/simplejavamail/internal/outlooksupport/converter/OutlookEmailConverter.java)
+
+## Implementation Status - 2026-07-03
+
+The MIME resource naming repair is implemented for the central non-Outlook issues in this problem area:
+
+- [#566](https://github.com/bbottema/simple-java-mail/issues/566): custom attachment Content-ID values now survive send/parse round trips instead of being overwritten by generated fallback IDs.
+- [#597](https://github.com/bbottema/simple-java-mail/issues/597): embedded image filename/name and HTML Content-ID can now differ through `withEmbeddedImage(name, dataSource, contentId)`.
+- [#602](https://github.com/bbottema/simple-java-mail/issues/602): parsing now keeps embedded filenames and Content-ID values separate; the parsed resource name no longer collapses to the CID when a real filename exists.
+- [#607](https://github.com/bbottema/simple-java-mail/issues/607): generated attachment Content-ID values no longer derive from possibly invalid filenames. The generated form is now opaque, ASCII, and domain-qualified: `sjm-@simplejavamail.generated`.
+
+Related behavior deliberately preserved:
+
+- `withEmbeddedImage(name, dataSource)` remains the convenience shorthand where `name` is the `cid:` body reference.
+- Explicit API names still override datasource names for visible filenames/resource labels.
+- Datasource names remain useful fallback metadata.
+- Attachment filename fallback still uses explicit name, datasource name, then generated `resource`.
+- Attachment Content-ID fallback remains unique per MIME part, but is no longer filename-derived.
+- Generated Simple Java Mail attachment Content-ID values are transport details and are not treated as caller-provided model data after parsing.
+
+Deferred or out-of-scope issues:
+
+- [#541](https://github.com/bbottema/simple-java-mail/issues/541): optional Content-Type `filename`/`name` parameter control is a separate output-parameter feature request.
+- [#573](https://github.com/bbottema/simple-java-mail/issues/573): pre-encoded attachment body support is a separate body-encoding feature.
+- [#599](https://github.com/bbottema/simple-java-mail/issues/599): SMTPUTF8 parsing/session behavior is separate from resource name and Content-ID identity.
+- [#605](https://github.com/bbottema/simple-java-mail/issues/605): broader per-part Content-Transfer-Encoding fidelity remains adjacent. Parsed attachment CTE metadata is preserved by the current resource model, but text-part CTE policy is not part of this repair.
+- [#606](https://github.com/bbottema/simple-java-mail/issues/606) and [#572](https://github.com/bbottema/simple-java-mail/issues/572): Outlook-specific items explicitly excluded from this repair pass.
+
+Verification notes:
+
+- New focused regression coverage was added to `EmailConverterTest` for `#566`, `#597`, `#602`, and `#607`.
+- The full `modules/simple-java-mail -am test` suite passes under `C:\Program Files\Java\jdk1.8.0_152` with 303 tests run, 0 failures/errors, and 12 skipped.
+- The test dependency `junit-pioneer` is kept at `1.9.1` because `2.3.0` ships Java 11 class files and breaks Java 8 test compilation.
+
+## Problem Areas
+
+### 1. API override name versus datasource name
+
+Root problem: caller-provided names and `DataSource.getName()` both influenced MIME output. Some datasources, especially file and URL datasources, expose source names that are not the desired outgoing name.
+
+Related issues and commits:
+
+- [#47](https://github.com/bbottema/simple-java-mail/issues/47): URL datasource source name overrode requested attachment name.
+- [#50](https://github.com/bbottema/simple-java-mail/pull/50), `f54794d9`, `b6bbe6a0`: introduced/finalized `NamedDataSource`.
+- [#151](https://github.com/bbottema/simple-java-mail/issues/151), `80d031e4`: do not overwrite a caller-provided filename extension with an invalid datasource extension.
+- [#175](https://github.com/bbottema/simple-java-mail/issues/175), `305a2d53`: parsing back attachment names with `<>` wrapping clarified that datasource override names are not always recoverable after MIME conversion.
+
+Implementation rule:
+
+- Treat explicit API names as stronger than datasource names.
+- Treat datasource names as fallback metadata only.
+- Do not assume a round trip can recover the original datasource name after an explicit override.
+
+### 2. Embedded image CID versus filename
+
+Root problem: embedded images were sometimes treated like attachments, causing file extensions, datasource names, or filename repair to mutate the CID that HTML references.
+
+Related issues and commits:
+
+- Old Issue 5, `d48055d1`: changed Content-ID to RFC-2387-style `<...>` wrapping.
+- `9280e589`, `51e72ed5`, `d832cc45`, `dee4a9c0`, `7aada14d`: early 2016 split between Content-ID, name, and filename, including angle-bracket handling.
+- [#68](https://github.com/bbottema/simple-java-mail/issues/68): embedded image name required/safeguarded.
+- [#307](https://github.com/bbottema/simple-java-mail/issues/307), [#310](https://github.com/bbottema/simple-java-mail/issues/310), `7f9e4089`: stopped stripping extensions from resource names because Outlook embedded image CIDs were being mangled.
+- [#332](https://github.com/bbottema/simple-java-mail/issues/332), `0392691a`: test coverage for Apple Mail-style embedded image Content-ID without filename extension.
+- [#440](https://github.com/bbottema/simple-java-mail/issues/440), `d561ff9c`: stopped adding datasource-derived extensions to manually named embedded image CIDs.
+
+Implementation rule:
+
+- For inline/embedded resources, the Content-ID must remain the exact embedded image name selected by the API or parser.
+- Filename extension repair belongs to attachment display names, not embedded image CIDs.
+- HTML should reference the embedded resource name as `cid:` without angle brackets.
+
+### 3. Duplicate attachment names
+
+Root problem: data structures and Content-ID generation previously assumed names were unique. Real mail can contain multiple attachments with the same visible filename.
+
+Related issues and commits:
+
+- [#219](https://github.com/bbottema/simple-java-mail/issues/219), [#249](https://github.com/bbottema/simple-java-mail/issues/249), [#310](https://github.com/bbottema/simple-java-mail/issues/310), [#351](https://github.com/bbottema/simple-java-mail/issues/351): parser rejected or collapsed duplicate names in several forms.
+- `72256ce7`: first duplicate-name attempt.
+- `9d8dda88`, `8632308e`: proper duplicate-name handling with entry identity beyond the display name.
+- [#480](https://github.com/bbottema/simple-java-mail/issues/480), `e943d372`: attachment Content-ID now gets a generated unique suffix so clients do not render same-name attachments as the same content.
+
+Implementation rule:
+
+- Visible attachment filenames do not need to be unique.
+- Internal body-part identity must not be keyed only by visible filename.
+- Attachment Content-ID uniqueness is a transport/rendering safety measure, not a user-facing body-reference API.
+
+### 4. Encoding and header decoding
+
+Root problem: filenames, Content-ID values, Content-Description, and parsed header values crossed between raw model values, encoded MIME headers, and decoded parser output at different times.
+
+Related issues and commits:
+
+- [#58](https://github.com/bbottema/simple-java-mail/issues/58), `7096c326`: non-English attachment and embedded image names; early RFC-2047 encoding.
+- [#131](https://github.com/bbottema/simple-java-mail/issues/131), `7f2eaa12`: `NamedDataSource` implements `EncodingAware`.
+- [#226](https://github.com/bbottema/simple-java-mail/pull/226), `21fe8ed9`, `478c7566`: filenames with spaces handled through `ParameterList`.
+- [#232](https://github.com/bbottema/simple-java-mail/issues/232), `ccd2ef12`: MIME text encoding moved from email-building to message-sending, keeping the `Email` model clean.
+- [#248](https://github.com/bbottema/simple-java-mail/pull/248), `52bd831e`: Content-Type `name` should use the complete filename.
+- [#271](https://github.com/bbottema/simple-java-mail/issues/271), `948555a4`: do not encode filenames in the model; scan names for CRLF injection instead.
+- [#293](https://github.com/bbottema/simple-java-mail/issues/293), `5368d30f`: decode parsed MIME values and encode attachment descriptions on send.
+- [#404](https://github.com/bbottema/simple-java-mail/issues/404), [#405](https://github.com/bbottema/simple-java-mail/issues/405), `c8b32ed8`: support attachment `Content-Description` and explicit attachment `Content-Transfer-Encoding`.
+- [#416](https://github.com/bbottema/simple-java-mail/pull/416), [#456](https://github.com/bbottema/simple-java-mail/issues/456): lenient content-transfer-encoding handling for values found in the wild.
+
+Implementation rule:
+
+- Keep model values decoded and human-meaningful.
+- Encode only at MIME output boundaries.
+- Decode at MIME parse boundaries before validation or model population.
+- Keep CRLF/header-injection checks after decode, not as a substitute for decode.
+
+### 5. Inline-versus-attachment classification on receive
+
+Root problem: `Content-Disposition` alone is not a reliable signal for whether a body part is an embedded resource, an attachment, or both.
+
+Related issues and commits:
+
+- [#34](https://github.com/bbottema/simple-java-mail/issues/34): missing disposition originally treated as attachment.
+- [#83](https://github.com/bbottema/simple-java-mail/issues/83), `a1fc1b9f`: inline attachments without Content-ID parsed as regular attachments.
+- [#103](https://github.com/bbottema/simple-java-mail/issues/103), `5727f431`: removed invalid `size=0` Content-Disposition hack.
+- [#179](https://github.com/bbottema/simple-java-mail/issues/179), `c79dd605`: inline/CID resources not referenced in HTML are treated as attachments.
+- [#202](https://github.com/bbottema/simple-java-mail/issues/202), `e3d90694`: fixed concurrent modification while moving invalid embedded images to attachments.
+- [#346](https://github.com/bbottema/simple-java-mail/issues/346), `d417203a`: parse MimeMessage without fetching attachment data; still return named datasources.
+- [#491](https://github.com/bbottema/simple-java-mail/issues/491), `5b704fac`: attachment-disposition parts with referenced Content-ID can be both attachment and embedded image.
+
+Implementation rule:
+
+- Parse `Content-Disposition` and `Content-ID` independently.
+- Use HTML `cid:` references as evidence that a Content-ID part is embedded.
+- Allow dual classification when the MIME source says attachment but the HTML references the Content-ID.
+
+### 6. Outlook-specific CID and fallback behavior
+
+Root problem: Outlook `.msg` files carry attachment names, long filenames, short DOS-like filenames, and ContentId attributes differently from MIME `.eml`.
+
+Related issues and commits:
+
+- [#200](https://github.com/bbottema/simple-java-mail/issues/200), `885f0ecf`: Outlook attachment name falls back to filename if proper name is empty.
+- [simple-java-mail #307](https://github.com/bbottema/simple-java-mail/issues/307): Outlook MSG to EML failed because embedded image Content-ID was changed.
+- [outlook-message-parser #10](https://github.com/bbottema/outlook-message-parser/issues/10): DOS-like short names misclassified embedded images as attachments; long filename needed as fallback.
+- [outlook-message-parser #19](https://github.com/bbottema/outlook-message-parser/pull/19): use Outlook's real ContentId attribute for CID attachments.
+- [outlook-message-parser #69](https://github.com/bbottema/outlook-message-parser/issues/69), [simple-java-mail #481](https://github.com/bbottema/simple-java-mail/issues/481): empty invalid embedded images from Outlook should not crash conversion unless they are actually used.
+- Adjacent parser issues: [outlook-message-parser #3](https://github.com/bbottema/outlook-message-parser/issues/3), [#9](https://github.com/bbottema/outlook-message-parser/issues/9), [#17](https://github.com/bbottema/outlook-message-parser/issues/17), [#23](https://github.com/bbottema/outlook-message-parser/issues/23), [#26](https://github.com/bbottema/outlook-message-parser/issues/26), [#27](https://github.com/bbottema/outlook-message-parser/issues/27).
+
+Implementation rule:
+
+- Prefer a real Outlook ContentId when present.
+- Keep filename and long-filename fallback logic as classification support only; do not let it mutate a known CID.
+- Invalid or empty Outlook attachments need context: ignore/tolerate them only when they are not used as embedded images.
+
+## RFCs Referenced In This Problem Area
+
+Central RFC references:
+
+- [RFC 2387](https://www.ietf.org/rfc/rfc2387.txt), MIME `multipart/related`: related parts form an aggregate object; related processing can take precedence over `Content-Disposition`; examples use body-part `Content-ID` references.
+- [RFC 2183](https://www.ietf.org/rfc/rfc2183.txt), `Content-Disposition`: defines `inline`, `attachment`, and `filename`, but does not make disposition sufficient to classify every related body part in real messages.
+- [RFC 2047](https://www.rfc-editor.org/rfc/rfc2047), non-ASCII text in message headers: referenced by code and by the non-English name fixes.
+- [RFC 5322](https://www.rfc-editor.org/rfc/rfc5322), Internet Message Format: current standard for `msg-id` syntax behind `Content-ID`, replacing the older RFC 2822 reference.
+- [RFC 1341](https://www.rfc-editor.org/rfc/rfc1341) and [RFC 1342](https://www.rfc-editor.org/rfc/rfc1342): older MIME/header-encoding references cited in `#293`; they are historical context for MIME body and non-ASCII header handling.
+
+Adjacent RFC references found in related code/docs:
+
+- RFC 2822: older message-id and email-address format reference superseded by RFC 5322.
+- RFC 2446: calendar method names.
+- RFC 5751: S/MIME.
+- RFC 8098: disposition notifications.
+- RFC 5321: SMTP display-name comment in MIME producer support code.
+
+## Target Invariants For Future Fixes
+
+Any new implementation should preserve these invariants:
+
+1. `withEmbeddedImage(name, dataSource)` means HTML references `cid:name`.
+2. `withEmbeddedImage(name, dataSource, contentId)` means HTML references `cid:contentId`, while `name` remains filename/resource metadata.
+3. `Content-ID` headers are angle-bracket-wrapped on MIME output, but HTML `cid:` values are not.
+4. Attachment filenames are display/download names and may duplicate.
+5. Attachment Content-IDs must be unique enough for mail clients not to collapse same-name attachments.
+6. Generated attachment Content-IDs must be valid opaque IDs, not filename-derived values.
+7. Filename extension repair must not mutate embedded image CIDs.
+8. Explicit API names win over datasource names for filenames/resource labels.
+9. Explicit API Content-IDs win over all generated fallback IDs.
+10. Datasource names are fallbacks, not authoritative identity.
+11. Parsed model values should be decoded; MIME headers should be encoded at output boundaries.
+12. Receiving logic must allow `attachment` plus referenced Content-ID to classify as both attachment and embedded image.
+13. Outlook conversion should prefer real ContentId attributes and use names/filenames only as fallbacks.
+
+## Implementation Checklist
+
+Before changing this area, re-check these surfaces together:
+
+- Builder API docs and validation in `EmailPopulatingBuilder` and `EmailPopulatingBuilderImpl`.
+- Send-side filename/resource-label derivation and Content-ID derivation in `MimeMessageHelper`.
+- Content-Type parameters, Content-Disposition filename, Content-ID, Content-Description, and Content-Transfer-Encoding output in `MimeMessageHelper`.
+- Parse-side Content-ID extraction, filename parsing, header decoding, and `cidMap` versus attachment-list population in `MimeMessageParser`.
+- HTML `cid:` extraction and invalid-embedded-resource fallback.
+- Outlook conversion through `OutlookEmailConverter` and the current `outlook-message-parser` version behavior.
+- Duplicate-name tests and round-trip conversion tests, especially `#307`, `#332`, `#440`, `#480`, and `#491` cases.
diff --git a/NOTICE.txt b/NOTICE.txt
index b1a46f664..08dedb8f9 100644
--- a/NOTICE.txt
+++ b/NOTICE.txt
@@ -1,17 +1,9 @@
=========================================================================
== NOTICE file for use with the Apache License, Version 2.0 ==
=========================================================================
-
- Simple Java Mail
- Copyright 2009-2017 Benny Bottema
- http://www.simplejavamail.org
-
- This product uses no commercial products.
-
- This product uses the following external (Open Source) libraries:
-
- - activation package from jre6
- - SLF4J (http://http://www.slf4j.org/)
- - Sun Java Mail API, shipped with JavaEE or as seperate download) (http://java.sun.com/products/javamail/)
- - Email Validation regular expressions, by Les Hazlewood, Casey Connor, Benny Bottema (https://github.com/bbottema/email-rfc2822-validator)
- - DKIM signing library https://github.com/markenwerk/java-utils-mail-dkim (based on https://github.com/usrflo/DKIM-for-JavaMail)
+
+ Simple Java Mail - Master Project
+ Copyright (C) 2009 Benny Bottema (benny@bennybottema.com)
+ https://www.simplejavamail.org
+
+ This product uses no commercial products.
\ No newline at end of file
diff --git a/PROJECT_MECHANISMS_CATALOGUE.md b/PROJECT_MECHANISMS_CATALOGUE.md
new file mode 100644
index 000000000..c1f529c21
--- /dev/null
+++ b/PROJECT_MECHANISMS_CATALOGUE.md
@@ -0,0 +1,188 @@
+# Project Mechanisms Catalogue
+
+This catalogue records project mechanisms that are easy to miss because they span modules, build steps, generated files, or runtime classpath behavior. It is meant to be read alongside [DEVELOPMENT.md](DEVELOPMENT.md) and [API_EXPANSION_WORKFLOW.md](API_EXPANSION_WORKFLOW.md).
+
+## Quick Index
+
+| Mechanism | Main reason it exists | Primary anchors |
+| --- | --- | --- |
+| API expansion workflow | Keep model, builders, CLI, config, conversion, and modules in sync when the public API grows. | [API_EXPANSION_WORKFLOW.md](API_EXPANSION_WORKFLOW.md) |
+| Dynamic module loading | Keep optional features out of the core runtime until their module jars are present and used. | [ModuleLoader.java](modules/simple-java-mail/src/main/java/org/simplejavamail/internal/moduleloader/ModuleLoader.java), [modules package](modules/core-module/src/main/java/org/simplejavamail/internal/modules) |
+| CLI generation from builder Javadocs | Turn builder API methods and Javadocs into picocli options and committed binary metadata. | [Cli.java](modules/core-module/src/main/java/org/simplejavamail/api/internal/clisupport/model/Cli.java), [BuilderApiToPicocliCommandsMapper.java](modules/cli-module/src/main/java/org/simplejavamail/internal/clisupport/BuilderApiToPicocliCommandsMapper.java), [CliSupport.java](modules/cli-module/src/main/java/org/simplejavamail/internal/clisupport/CliSupport.java), `modules/cli-module/src/main/resources/cli.data`, `modules/cli-module/src/main/resources/therapi.data` |
+| Async send and batch connection pooling | Reuse SMTP transports when the batch module is present; otherwise fall back to direct session transports. | [MailerImpl.java](modules/simple-java-mail/src/main/java/org/simplejavamail/mailer/internal/MailerImpl.java), [TransportRunner.java](modules/simple-java-mail/src/main/java/org/simplejavamail/mailer/internal/util/TransportRunner.java), [BatchSupport.java](modules/batch-module/src/main/java/org/simplejavamail/internal/batchsupport/BatchSupport.java) |
+| Authenticated SOCKS proxy bridge | Work around JavaMail's anonymous-only SOCKS support by running a local anonymous bridge to an authenticated remote proxy. | [MailerImpl.java](modules/simple-java-mail/src/main/java/org/simplejavamail/mailer/internal/MailerImpl.java), [AnonymousSocks5Server.java](modules/core-module/src/main/java/org/simplejavamail/api/internal/authenticatedsockssupport/socks5server/AnonymousSocks5Server.java), [AuthenticatedSocksHelper.java](modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/AuthenticatedSocksHelper.java) |
+| Smart MIME structure selection | Choose the least complex RFC-compatible MIME structure for the actual email contents. | [MimeMessageProducerHelper.java](modules/simple-java-mail/src/main/java/org/simplejavamail/converter/internal/mimemessage/MimeMessageProducerHelper.java), [SpecializedMimeMessageProducer.java](modules/simple-java-mail/src/main/java/org/simplejavamail/converter/internal/mimemessage/SpecializedMimeMessageProducer.java), [MIME_RESOURCE_NAMING_REPORT.md](MIME_RESOURCE_NAMING_REPORT.md) |
+| Runtime non-null instrumentation | Preserve and enforce JetBrains nullability contracts through build-time bytecode instrumentation. | [pom.xml](pom.xml), `org.jetbrains.annotations.NotNull`, `org.jetbrains.annotations.Nullable` |
+
+## API Expansion Workflow
+
+The API expansion process is already documented in [API_EXPANSION_WORKFLOW.md](API_EXPANSION_WORKFLOW.md). Treat that file as the checklist for adding fields or fluent builder methods.
+
+Important connections to the other mechanisms in this catalogue:
+
+- New builder methods can automatically become CLI options if they are CLI-compatible and not annotated with `@Cli.ExcludeApi`.
+- New mail features usually need a MIME conversion decision in `MimeMessageHelper` or `SpecializedMimeMessageProducer`.
+- Module-specific features may require updates to a core module interface, a module implementation, and the runtime loader.
+- New fields that represent user-facing configuration may also need config defaults, overrides, Spring mapping, and CLI data regeneration.
+
+## Dynamic Module Loading
+
+The published `simple-java-mail` artifact declares several support modules as optional dependencies, including authenticated SOCKS, DKIM, S/MIME, batch, and Outlook support. The core implementation talks to these modules through small interfaces in [modules/core-module/src/main/java/org/simplejavamail/internal/modules](modules/core-module/src/main/java/org/simplejavamail/internal/modules), then uses reflection in [ModuleLoader.java](modules/simple-java-mail/src/main/java/org/simplejavamail/internal/moduleloader/ModuleLoader.java) to instantiate the implementation class only if the module jar is actually present.
+
+The pattern is:
+
+1. Define a stable interface in `core-module`, for example `BatchModule`, `SMIMEModule`, `DKIMModule`, `OutlookModule`, or `AuthenticatedSocksModule`.
+2. Implement that interface in the optional module, for example `BatchSupport`, `SMIMESupport`, `DKIMSigner`, `OutlookEmailConverter`, or `AuthenticatedSocksHelper`.
+3. Add a `ModuleLoader.loadXxxModule()` method with the implementation class name as a string.
+4. Use `MiscUtil.classAvailable(...)` for classpath detection where callers need an availability check.
+5. Keep optional module dependencies optional in `modules/simple-java-mail/pom.xml`; include runtime optional modules in the CLI assembly when the CLI should ship with them.
+
+Current usage:
+
+- Batch is checked with `ModuleLoader.batchModuleAvailable()` in `MailerImpl` and `TransportRunner`; when present, it registers a session pool and acquires pooled transports.
+- S/MIME and DKIM are checked or loaded by the MIME producer only when email content requests signing or encryption.
+- Outlook conversion calls `ModuleLoader.loadOutlookModule()` from `EmailConverter` when `.msg` conversion APIs are used.
+- Authenticated SOCKS support is loaded only when proxy settings include authentication.
+
+Gotchas:
+
+- `ModuleLoader` caches loaded module instances in a static map. Batch, S/MIME, and DKIM availability checks are also cached unless tests force a recheck.
+- Missing modules are a runtime failure only when the feature is requested. Do not add compile-time references from `simple-java-mail` implementation code to optional module classes.
+- Test helpers can force-disable/recheck modules through reflection because the loader is intentionally hidden from `core-module`.
+
+## CLI Generation From Builder API Javadocs
+
+The CLI is generated from the builder API rather than maintained as a fully separate option list. This gives the CLI near one-to-one feature parity with the Java builder API, including the same method documentation, but it also makes the CLI sensitive to API shape, Javadoc completeness, reflection behavior, and serialized metadata compatibility.
+
+Main flow:
+
+1. Builder API root types are listed in [CliSupport.java](modules/cli-module/src/main/java/org/simplejavamail/internal/clisupport/CliSupport.java): `EmailStartingBuilder`, `MailerRegularBuilder`, and `MailerFromSessionBuilder`.
+2. `BuilderApiToPicocliCommandsMapper.generateOptionsFromBuilderApi(...)` walks public methods on builder API nodes annotated with `@Cli.BuilderApiNode`.
+3. A method is accepted only if it passes `methodIsCliCompatible(...)`: it must be on a builder API node, must not have `@Cli.ExcludeApi`, must not be a bean accessor, must not take collection parameters, and must be convertible from string arguments.
+4. `@Cli.OptionNameOverride` can resolve name collisions or expose a CLI-specific option name.
+5. `@Cli.Optional` marks optional CLI parameters explicitly. Java nullability remains expressed with JetBrains `@Nullable`; it no longer drives CLI optionality.
+6. Method and parameter Javadocs are read through Therapi Runtime Javadoc and formatted for terminal output by `TherapiJavadocHelper` and `JavadocForCliFormatter`.
+7. Picocli command metadata is serialized with Kryo to `modules/cli-module/src/main/resources/cli.data`.
+8. Therapi lookups are cached to `modules/cli-module/src/main/resources/therapi.data`.
+
+The Javadoc part is unusual: the build uses Therapi's annotation processor to bake selected Javadoc into runtime-readable classes, then the CLI module reflects over builder methods, resolves those baked Javadocs, formats links and examples for terminal output, and stores the resulting CLI model in `cli.data` for faster startup. The result is clever and convenient, but brittle: Java version changes, bridge/synthetic methods, incomplete `@param` tags, method overload ambiguity, or stale binary metadata can all produce surprising CLI behavior.
+
+Regeneration:
+
+```powershell
+mvn -pl modules/cli-module -am -Ppublish-cli -DskipTests package
+```
+
+The `publish-cli` profile runs `demo.CliListAllSupportedOptionsDemoApp`, which calls `CliSupport.listUsagesForAllOptions()` and then persists the Therapi cache.
+
+Constraints:
+
+- Use JDK 8 for CLI data regeneration. [DEVELOPMENT.md](DEVELOPMENT.md) documents why Java 12+ breaks this path.
+- Every CLI-exposed method needs complete Javadoc, including `@param` text for every parameter. A parameter count mismatch becomes an assertion error in `TherapiJavadocHelper.getParamDescriptions(...)`.
+- Optional CLI arguments must be annotated with `@Cli.Optional`. Keep `@Nullable` as the Java/API nullability contract; do not use it as CLI metadata.
+- Methods using complex Java-only objects, collection/map parameters, ambiguous overloads, or APIs that are only a subset of a better option should be excluded with `@Cli.ExcludeApi(reason = "...")`.
+- New string-convertible types need a value converter registered in `BuilderApiToPicocliCommandsMapper`.
+
+## Async Send And Batch Connection Pooling
+
+`MailerImpl.sendMail(...)` and `MailerImpl.testConnection(...)` can run synchronously or return a `CompletableFuture`. The actual async wrapper is `AsyncOperationHelper` in `core-module`; when the batch module is available, `BatchSupport` delegates to the same helper but provides a default executor tuned for mail sending.
+
+Key pieces:
+
+- `MailerGenericBuilderImpl` chooses the executor service. With `batch-module` on the classpath, the default is `BatchModule.createDefaultExecutorService(...)`; otherwise it falls back to `Executors.newSingleThreadExecutor()`.
+- `NonJvmBlockingThreadPoolExecutor` is a fixed-size `ThreadPoolExecutor` with a `LinkedBlockingQueue`. If keep-alive time is greater than zero, core threads are allowed to time out so they do not keep the JVM alive forever.
+- `withThreadPoolSize(...)` and `simplejavamail.defaults.poolsize` limit concurrent async work, not queued backlog; the built-in executor does not expose a queue-capacity setting.
+- Bounded queues and custom rejection/backpressure behavior require `withExecutorService(...)`. Caller-provided executors are caller-owned, so Simple Java Mail leaves their lifecycle and shutdown to the application.
+- `BatchSupport.registerToCluster(...)` creates/registers SMTP connection pools using `SmtpConnectionPoolClustered`.
+- Cluster-specific property defaults are parsed from `simplejavamail.defaults.connectionpool.clusters.*` by `ConfigLoader` and overlaid on the global connection-pool defaults when `BatchSupport` registers a matching cluster key.
+- `TransportRunner` sends through `BatchModule.acquireTransport(...)` when batch is available; otherwise it opens a normal `Session.getTransport()` connection for the operation.
+- `LifecycleDelegatingTransportImpl` wraps the pooled transport so the caller can signal success with `release()` or failure with `invalidate()`.
+- `MailerImpl.shutdownConnectionPool()` shuts down the default executor if it is library-owned and delegates pool shutdown to the batch module when present.
+
+There is no direct `Phaser` usage in this repository's source tree. Batch coordination here is expressed through `CompletableFuture`, executor services, `AtomicInteger` proxy request tracking, and the external SMTP/object-pool libraries used by `batch-module`.
+
+## Authenticated SOCKS Proxy Bridge
+
+JavaMail supports SOCKS proxy properties, but not authenticated SOCKS proxy login. Simple Java Mail handles authenticated proxies by inserting a local anonymous SOCKS5 server between JavaMail and the real authenticated proxy.
+
+Flow:
+
+1. `MailerImpl.configureSessionWithProxy(...)` first writes normal SOCKS host/port settings for anonymous proxy usage.
+2. If the proxy config requires authentication, it rewrites the session SOCKS host to `localhost` and port to `proxyBridgePort`.
+3. It then loads `AuthenticatedSocksModule` and creates an `AnonymousSocks5Server`.
+4. `AuthenticatedSocksHelper` constructs `AnonymousSocks5ServerImpl` with an `AuthenticatingSocks5Bridge`.
+5. The local server accepts anonymous JavaMail SOCKS connections and the bridge opens authenticated sockets to the real remote proxy.
+6. `AbstractProxyServerSyncingClosure` starts the local bridge only while SMTP/test-connection work is active and stops it after the last in-flight SMTP request finishes.
+
+Concurrency and lifecycle:
+
+- `MailerImpl` tracks active SMTP requests with an `AtomicInteger`.
+- Bridge start/stop is synchronized around the proxy server instance.
+- The bridge server uses a fixed thread pool for accepted SOCKS sessions; each session pipes client and remote sockets until the pipe stops.
+
+Gotchas:
+
+- SMTPS plus proxy is rejected in `MailerImpl` because the underlying JavaMail combination is not supported.
+- The authenticated SOCKS module must be available when authenticated proxy settings are used.
+- `getProxyBridgePort()` exposes the local bridge port, not the remote proxy port.
+
+## Smart MIME Message Structure Selection
+
+Simple Java Mail avoids one oversized MIME structure for every email. Instead, it picks the least complex producer that matches the actual content. The selection is centralized in [MimeMessageProducerHelper.java](modules/simple-java-mail/src/main/java/org/simplejavamail/converter/internal/mimemessage/MimeMessageProducerHelper.java).
+
+The selector computes three content dimensions in [SpecializedMimeMessageProducer.java](modules/simple-java-mail/src/main/java/org/simplejavamail/converter/internal/mimemessage/SpecializedMimeMessageProducer.java):
+
+- Mixed content: attachments or forwarded email.
+- Related content: embedded images.
+- Alternative content: more than one body variant among plain text, HTML, and calendar text.
+
+Resource naming, embedded image `cid:` values, attachment filenames, duplicate attachment names, and parse-side inline/attachment classification have their own focused history report in [MIME_RESOURCE_NAMING_REPORT.md](MIME_RESOURCE_NAMING_REPORT.md).
+
+Those booleans map to eight producers:
+
+| Producer | Mixed | Related | Alternative |
+| --- | --- | --- | --- |
+| `MimeMessageProducerSimple` | no | no | no |
+| `MimeMessageProducerAlternative` | no | no | yes |
+| `MimeMessageProducerRelated` | no | yes | no |
+| `MimeMessageProducerMixed` | yes | no | no |
+| `MimeMessageProducerMixedRelated` | yes | yes | no |
+| `MimeMessageProducerMixedAlternative` | yes | no | yes |
+| `MimeMessageProducerRelatedAlternative` | no | yes | yes |
+| `MimeMessageProducerMixedRelatedAlternative` | yes | yes | yes |
+
+After the selected producer creates the body structure, `SpecializedMimeMessageProducer.populateMimeMessage(...)` applies additional wrappers in a fixed order:
+
+1. S/MIME signing.
+2. S/MIME encryption, including the per-recipient certificate path when any recipient has a `smimeCertificate`.
+3. DKIM signing.
+4. Bounce-to wrapping with `ImmutableDelegatingSMTPMessage`.
+
+Gotchas:
+
+- New body-part concepts usually require revisiting the selector dimensions and every affected producer.
+- DKIM and S/MIME are optional modules, but if the email requests them the corresponding module must be on the runtime classpath.
+- The producer starts from `MessageIdFixingMimeMessage` so custom message IDs survive later wrapping.
+
+## Runtime Non-Null Instrumentation
+
+The API and implementation use JetBrains `@NotNull` and `@Nullable` annotations heavily.
+
+`org.jetbrains:annotations` is compiled in for source-level and public API nullability annotations. Earlier versions also depended on `com.github.bbottema:jetbrains-runtime-annotations`, a runtime-retention fork of the JetBrains annotations, because the CLI inspected `@Nullable` by reflection to detect optional command arguments. CLI optionality is now represented separately with `@Cli.Optional`, so the runtime-retention fork is no longer needed.
+
+The root Maven build configures `se.eris:notnull-instrumenter-maven-plugin` to instrument main and test classes. The current configuration recognizes `org.jetbrains.annotations.Nullable` and `org.jetbrains.annotations.NotNull`, and excludes assertion helpers plus `ServerReply`.
+
+Implications:
+
+- Do not treat nullability annotations as cosmetic. They affect generated bytecode and runtime validation.
+- Adding or changing public builder API nullability can still affect the CLI ergonomics, but only when CLI optionality should follow. In that case add both `@Nullable` and `@Cli.Optional`; `BuilderApiToPicocliCommandsMapper` marks CLI parameters as required unless the parameter has `@Cli.Optional`.
+- Generated code or protocol enum-like classes may need explicit instrumenter exclusions if instrumentation changes behavior.
+
+## Related Mechanisms Worth Checking
+
+These are not expanded as separate catalogue entries yet, but they are common places to inspect when changing core behavior:
+
+- Config resolution and defaults/overrides: `ConfigLoader`, `EmailProperty`, and `EmailGovernanceImpl`.
+- Spring property mapping: `SimpleJavaMailProperties` and `SimpleJavaMailSpringSupport`.
+- Outlook and EML conversion: `EmailConverter`, `OutlookEmailConverter`, and `MimeMessageParser`.
+- Transport strategy properties: `TransportStrategy` and `MailerImpl.createMailSession(...)`.
diff --git a/README.md b/README.md
index 321db2dff..00b4d523d 100644
--- a/README.md
+++ b/README.md
@@ -1,179 +1,147 @@
-[](LICENSE) [](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.simplejavamail%22%20AND%20a%3A%22simple-java-mail%22) [](http://www.javadoc.io/doc/org.simplejavamail/simple-java-mail) [](https://travis-ci.org/bbottema/simple-java-mail) [](https://www.codacy.com/app/b-bottema/simple-java-mail)
-
-# Simple Java Mail #
-
-Simple Java Mail is the simplest to use lightweight mailing library for Java, while being able to send complex emails including **authenticated socks proxy**(!), **attachments**, **embedded images**, **custom headers and properties**, **robust address validation**, **build pattern** and even **DKIM signing** and **external configuration files** with **property overriding**. Just send your emails without dealing with RFC's.
-
-The Simple Java Mail library is a thin layer on top of the JavaMail smtp mailing API that allows users to define emails on a high abstraction level without having to deal with mumbo jumbo such a 'multipart' and 'mimemessage'.
-
-### [simplejavamail.org](http://www.simplejavamail.org) ###
-
-```java
-ConfigLoader.loadProperties("simplejavamail.properties"); // optional default
-ConfigLoader.loadProperties("overrides.properties"); // optional extra
-
-Email email = new Email();
-
-email.addRecipient("lollypop", "lolly.pop@somemail.com", Message.RecipientType.TO);
-email.setReplyToAddress("lollypop", "lolly.pop@othermail.com");
-email.addRecipient("C. Cane", "candycane@candyshop.org", Message.RecipientType.TO);
-email.addRecipient("C. Bo", "chocobo@candyshop.org", Message.RecipientType.CC);
-email.setSubject("hey");
-email.setText("We should meet up! ;)");
-email.setTextHTML("<img src='cid:wink1'><b>We should meet up!</b><img src='cid:wink2'>");
-email.addEmbeddedImage("wink1", imageByteArray, "image/png");
-email.addEmbeddedImage("wink2", imageDatesource);
-email.addAttachment("invitation", pdfByteArray, "application/pdf");
-email.addAttachment("dresscode", odfDatasource);
-
-email.signWithDomainKey(privateKeyData, "somemail.com", "selector");
-
-new Mailer(
- new ServerConfig("smtp.host.com", 587, "user@host.com", "password"),
- TransportStrategy.SMTP_TLS,
- new ProxyConfig("socksproxy.host.com", 1080, "proxy user", "proxy password")
-).sendMail(email);
-```
-
----
-
-
-Simple Java Mail is available in Maven Central:
-
-```
-
- org.simplejavamail
- simple-java-mail
- 4.1.1
-
-```
-
-### Latest Progress ###
-
-v4.1.1
-
-- [#50](https://github.com/bbottema/simple-java-mail/issues/50): bug fix for manual naming datasources
-
-
-v4.1.0
-
-- [#48](https://github.com/bbottema/simple-java-mail/issues/48): Added programmatic support trusting hosts for SSL connections
-- [#47](https://github.com/bbottema/simple-java-mail/issues/47): Honor given names, deduce extension from datasource name, and more robust support for parsing mimemessages
-
-
-v4.0.0
-
-- [#41](https://github.com/bbottema/simple-java-mail/issues/41): added support for fast parallel batch processing
-- [#42](https://github.com/bbottema/simple-java-mail/issues/42): **added support for config files**
-- [#43](https://github.com/bbottema/simple-java-mail/issues/43): removed logging implementation dependencies from distribution and documented various sample configs
-- [#39](https://github.com/bbottema/simple-java-mail/issues/39): simplified and renamed packages to reflect the domain name of the new website: [simplejavamail.org](http://www.simplejavamail.org)
-- [#38](https://github.com/bbottema/simple-java-mail/issues/38): added support for anonymous proxy
-- [#38](https://github.com/bbottema/simple-java-mail/issues/38): **added support for authenticated proxy**
-
-NOTE: All packages have been renamed to "org.simplejavamail.(..)".
-
-
-v3.1.1
-
-Major feature: DKIM support!
-
-- [#36](https://github.com/bbottema/simple-java-mail/issues/36): Added proper toString and equals methods for the Email classes
-- [#33](https://github.com/bbottema/simple-java-mail/issues/33): Added support for DKIM domain key signing
-
-
-v3.0.2
-
-- [#35](https://github.com/bbottema/simple-java-mail/issues/35): added proper .equals() and .toString() methods
-- [#34](https://github.com/bbottema/simple-java-mail/issues/34): Fixed bug when disposition is missing (assume it is an attachment)
-- #00: added findbugs support internally
-
-
-v3.0.1
-
- * [#31](https://github.com/bbottema/simple-java-mail/issues/31): Fixed EmailAddressCriteria.DEFAULT and clarified Javadoc
-
-
-v3.0.0
-
- * [#30](https://github.com/bbottema/simple-java-mail/issues/30): Improved the demonstration class to include attachments and embedded images
- * [#29](https://github.com/bbottema/simple-java-mail/issues/29): The package has been restructured for future maintenance, breaking backwards compatibility
- * [#28](https://github.com/bbottema/simple-java-mail/issues/28): Re-added improved email validation facility
- * [#22](https://github.com/bbottema/simple-java-mail/issues/22): Added conversion to and from MimeMessage. You can now consume and produce MimeMessage objects with simple-java-mail
-
-
-v2.5.1
-
- * [#25](https://github.com/bbottema/simple-java-mail/issues/25): Added finally clause that will always close socket properly in case of an exception
-
-
-v2.5
-
- * [#24](https://github.com/bbottema/simple-java-mail/issues/24): Updated dependencies SLF4J to 1.7.13 and switched to the updated javax mail package com.sun.mail:javax.mail 1.5.5
-
-
-v2.4
-
- * [#21](https://github.com/bbottema/simple-java-mail/issues/21): builder API uses CC and BCC recipient types incorrectly
-
-
-v2.3
-
- * [#19](https://github.com/bbottema/simple-java-mail/issues/19): supporting custom Session Properties now and emergency access to internal Session object.
-
-
-v2.2
-
- * [#3](https://github.com/bbottema/simple-java-mail/issues/3): turned off email regex validation by default, with the option to turn it back on
- * [#7](https://github.com/bbottema/simple-java-mail/issues/7): fixed NullPointerException when using your own Session instance
- * [#10](https://github.com/bbottema/simple-java-mail/issues/10): properly UTF-8 encode recipient addresses
- * [#14](https://github.com/bbottema/simple-java-mail/issues/14): switched to SLF4J, so you can easily use your own selected logging framework
- * [#17](https://github.com/bbottema/simple-java-mail/issues/17): Added [fluent interface](http://en.wikipedia.org/wiki/Builder_pattern) for building emails (see [manual](https://github.com/bbottema/simple-java-mail/wiki/Manual) for an example)
-
-
-v2.1
-
- * fixed character encoding for reply-to, from, to, body text and headers (to UTF-8)
- * fixed bug where Recipient was not public resulting in uncompilable code when calling email.getRecipients()
-
-
-v2.0
-
- * added support for adding open headers, such as 'X-Priority: 2'
-
-
-v1.9.1
-
- * updated for Maven support
-
-
-v1.9
-
- * added support for JavaMail's reply-to address
- * made port optional as to support port defaulting based on protocol
- * added transport strategy default in the createSession method
- * tightened up thrown exceptions (MailException instead of RuntimeException)
- * added and fixed [JavaDoc](http://simple-java-mail.googlecode.com/svn/trunk/javadoc/users/index.html)
-
-
-v1.8
-
- * Added support for TLS (tested with gmail)
-
-
-v1.7
-
-Added support for SSL! (tested with gmail)
-
- * improved argument validation when creating a Mailer without preconfigured Session instance
-
-known possible issue: SSL self-signed certificates might not work (yet). Please let me know by e-mail or create a new issue
-
-
-v1.6
-
-Completed migration to Java Simple Mail project.
-
- * removed all Vesijama references
- * updated TestMail demonstration class for clarification
- * updated readme.txt for test run instructions
- * included log4j.properties
+[](modules/simple-java-mail/LICENSE-2.0.txt)
+[](https://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.simplejavamail%22%20AND%20v%3A%229.1.3%22)
+[](https://www.javadoc.io/doc/org.simplejavamail/maven-master-project)
+[](https://app.codacy.com/gh/bbottema/simple-java-mail)
+
+
+# Simple Java Mail #
+
+Simple Java Mail is a robust Java mailing library built to make production email simple to use: rich content, recipient governance, signing and encryption, transport security, configuration, diagnostics, conversion, and high-throughput batch or clustered sending.
+
+It keeps those concerns behind a consistent high-level API, while still giving you fluent builders, property/Spring configuration, defaults and overrides, validation, logging, and lower-level Jakarta Mail escape hatches when you need them.
+
+Under the hood, Simple Java Mail sits on top of [Angus Mail](https://eclipse-ee4j.github.io/angus-mail/) (previously [Jakarta Mail](https://jakartaee.github.io/mail-api/README-JakartaMail)).
+
+Simple Java Mail remains Java 8-compatible; Java 8 is the source, target, and minimum supported runtime.
+
+### Documentation ###
+
+The full user documentation lives at [simplejavamail.org](https://www.simplejavamail.org). Start there for the minimal banner example, grand examples, feature guides, configuration reference, diagnostics, and module overview.
+
+- [Features](https://www.simplejavamail.org/features.html#navigation)
+- [Configuration and Spring support](https://www.simplejavamail.org/configuration.html#navigation)
+- [Security](https://www.simplejavamail.org/security.html#navigation)
+- [Logging and debugging](https://www.simplejavamail.org/debugging.html#navigation)
+- [Modules](https://www.simplejavamail.org/modules.html)
+- [CLI](https://www.simplejavamail.org/cli.html#navigation)
+- [9.0 migration notes](https://www.simplejavamail.org/migration-notes-9.0.0.html)
+
+### Installation ###
+
+Simple Java Mail is available in [Maven Central](https://search.maven.org/search?q=g:org.simplejavamail):
+
+```xml
+
+ org.simplejavamail
+ simple-java-mail
+ 9.1.3
+
+```
+
+Read about additional modules you can add here: [simplejavamail.org/modules](https://www.simplejavamail.org/modules.html).
+
+### Development ###
+
+- [Project mechanisms catalogue](PROJECT_MECHANISMS_CATALOGUE.md) for optional module loading, CLI metadata generation, MIME selection, proxy bridging, concurrency, and non-null instrumentation.
+- [API expansion workflow](API_EXPANSION_WORKFLOW.md) for adding public API fields or builder methods.
+- [Developer environment setup](DEVELOPMENT.md) for JDK and build constraints.
+
+### Latest progress ###
+
+[v9.1.0](https://github.com/bbottema/simple-java-mail/releases/tag/9.1.0) - [v9.1.3](https://github.com/bbottema/simple-java-mail/releases/tag/9.1.3) - [Maven Central](https://repo1.maven.org/maven2/org/simplejavamail/simple-java-mail/9.1.3/)
+
+- **v9.1.3:** [#668](https://github.com/bbottema/simple-java-mail/issues/668): **New Outlook inline images:** updated `outlook-message-parser` to 1.16.2 so native-HTML-only `.msg` files match inline `cid:` images correctly and trailing NUL terminators no longer leak into attachment metadata.
+- **v9.1.2:** **Dependency and Java 8-compatible build-tool maintenance:** updated JMail to 2.2.0 ([#663](https://github.com/bbottema/simple-java-mail/pull/663)), Zip4j to 2.11.6 ([#666](https://github.com/bbottema/simple-java-mail/pull/666)), Exec Maven Plugin to 3.6.3 ([#664](https://github.com/bbottema/simple-java-mail/pull/664)), Maven Enforcer Plugin to 3.6.3 ([#665](https://github.com/bbottema/simple-java-mail/pull/665)), and Maven JAR Plugin to 3.5.1 ([#667](https://github.com/bbottema/simple-java-mail/pull/667)).
+- **v9.1.1:** **Java 8 build-tool maintenance** ([#662](https://github.com/bbottema/simple-java-mail/pull/662)): updated annotations and Maven compiler, JAR, OSGi bundle, and Karaf tooling to Java 8-compatible versions, with Dependabot guards against newer-Java-only upgrade lines.
+- **v9.1.0:** [#653](https://github.com/bbottema/simple-java-mail/issues/653): a configurable SMTP client hostname for the `EHLO` / `HELO` command.
+- **v9.1.0:** [#654](https://github.com/bbottema/simple-java-mail/issues/654): SMTP submission receipts for reading the server acceptance response after a send.
+- **v9.1.0:** No breaking changes; existing `sendMail(...)` behavior is unchanged.
+
+[v9.0.0](https://github.com/bbottema/simple-java-mail/releases/tag/9.0.0) - [v9.0.4](https://github.com/bbottema/simple-java-mail/releases/tag/9.0.4) - [Maven Central](https://repo1.maven.org/maven2/org/simplejavamail/simple-java-mail/9.0.4/)
+
+#### The Short Version ####
+
+**Simple Java Mail has been going strong-ish for about 20 years**, and **9.0.0** rolls *roughly two years of backlog* into a new major release.
+
+```
+simple-java-mail
+└── outlook-message-parser
+ └── rtf-to-html
+└── java-utils-mail-dkim
+└── java-utils-mail-smime
+└── smtp-connection-pool
+ └── clustered-object-pool
+ └── generic-object-pool
+└── java-socks-proxy-server
+```
+
+Across Simple Java Mail and the supporting libraries that keep the stack moving, **more than 100 GitHub issues and PRs** were reviewed, fixed, merged, or closed while keeping the project **Java 8-compatible**.
+
+**Major features:** the dedicated recipient builder API, per-recipient S/MIME certificates, first-class Delivery Status Notification support, pre-encoded attachment and embedded-image sending, mailer-level DKIM defaults, and simple batch/open-connection sending without the batch module.
+**Enhancements:** broader Outlook conversion metadata, MIME resource handling, content-transfer encoding control, debug routing, local SMTP bind configuration, batch cluster configuration, and Java module support.
+
+#### Migration Note ####
+
+**This is a breaking major release.** The old recipient-addition method jungle has been cleaned up in favor of the **recipient builder API**, so code that relied on the removed recipient overloads needs to migrate. Start with the [9.0 migration notes](https://www.simplejavamail.org/migration-notes-9.0.0.html) before upgrading.
+
+#### Major Features ####
+
+- **v9.0.0:** [#613](https://github.com/bbottema/simple-java-mail/issues/613): **Recipient builder API:** added dedicated builders for constructing single recipients and recipient collections.
+- **v9.0.0:** [#297](https://github.com/bbottema/simple-java-mail/issues/297): **Per-recipient S/MIME certificates:** enabled encrypted mail for multiple recipients with different certificates.
+- **v9.0.0:** [#574](https://github.com/bbottema/simple-java-mail/issues/574): **Delivery Status Notification (DSN):** added first-class DSN configuration.
+- **v9.0.0:** [#573](https://github.com/bbottema/simple-java-mail/issues/573): **Pre-encoded resources:** added pre-encoded attachment and embedded-image APIs.
+- **v9.0.0:** [#196](https://github.com/bbottema/simple-java-mail/issues/196): **Mailer-level DKIM defaults:** added default DKIM signing configuration so DKIM can be configured once per `Mailer`.
+- **v9.0.0:** [#569](https://github.com/bbottema/simple-java-mail/issues/569): **Simple batch and open-connection sending:** added `sendMailsInSimpleBatch(...)` for sequential batch work without the batch module and `withOpenConnection(...)` for callback-scoped reuse of a single SMTP connection.
+
+#### Enhancements ####
+
+- **v9.0.2:** [#645](https://github.com/bbottema/simple-java-mail/issues/645): **Outlook last-modifier metadata:** exposed `PR_LAST_MODIFIER_NAME` / `0x3FFA` as `OutlookMessageData#getLastModifierName()` without treating it as sender identity.
+- **v9.0.0:** [#614](https://github.com/bbottema/simple-java-mail/issues/614): **Outlook conversion metadata:** added explicit result APIs for inspecting source `.msg` headers and metadata without copying structural headers into converted emails, resolving [#609](https://github.com/bbottema/simple-java-mail/issues/609).
+- **v9.0.0:** [#605](https://github.com/bbottema/simple-java-mail/issues/605): **Per-body content-transfer encoding:** added `Content-Transfer-Encoding` configuration for plain text, HTML, and calendar content.
+- **v9.0.0:** [#566](https://github.com/bbottema/simple-java-mail/issues/566), [#597](https://github.com/bbottema/simple-java-mail/issues/597), [#602](https://github.com/bbottema/simple-java-mail/issues/602), [#607](https://github.com/bbottema/simple-java-mail/issues/607): **MIME resource `Content-ID` handling:** improved explicit IDs, parsed embedded images, and generated fallback IDs.
+- **v9.0.0:** [#589](https://github.com/bbottema/simple-java-mail/issues/589): **Jakarta Mail debug output:** added configurable debug output routing.
+- **v9.0.0:** [#568](https://github.com/bbottema/simple-java-mail/issues/568): **Local SMTP bind address:** added configuration for multi-IP SMTP hosts.
+- **v9.0.0:** [#565](https://github.com/bbottema/simple-java-mail/issues/565), [#618](https://github.com/bbottema/simple-java-mail/issues/618): **Batch cluster configuration:** fixed Java API cluster configuration and added property-defined cluster configurations for property-file and Spring-configured clustered sending.
+- **v9.0.0:** [#572](https://github.com/bbottema/simple-java-mail/issues/572), [#571](https://github.com/bbottema/simple-java-mail/issues/571): **S/MIME conversion leniency:** tolerate unsupported S/MIME payloads during Outlook conversion and preserve parsed email content when signature verification fails.
+- **v9.0.0:** [#606](https://github.com/bbottema/simple-java-mail/issues/606): **MIME type sanitizing:** sanitize malformed resource MIME types before generating attachment and embedded-image headers.
+- **v9.0.0:** [#541](https://github.com/bbottema/simple-java-mail/issues/541): **Resource headers:** removed the non-standard `filename` parameter from resource `Content-Type` headers; filenames remain available through `Content-Disposition`.
+- **v9.0.0:** [#265](https://github.com/bbottema/simple-java-mail/issues/265), [#237](https://github.com/bbottema/simple-java-mail/issues/237): **Java module support:** added Java 9 module descriptors to the core and facade jars so modular applications can require `org.simplejavamail` directly.
+
+#### Fixes and Compatibility ####
+
+- **v9.0.4:** [#652](https://github.com/bbottema/simple-java-mail/issues/652): **RFC 2047 address validation:** reject encoded-word syntax inside address specs during validation while keeping encoded display names valid.
+- **v9.0.3:** [#651](https://github.com/bbottema/simple-java-mail/issues/651): **Outlook plain-text RTF rendering:** preserved line breaks without exposing browser-default `
` styling in converted HTML.
+- **v9.0.0:** [#615](https://github.com/bbottema/simple-java-mail/issues/615): **Async test connections:** fixed `MailerGenericBuilder.async()` so no-arg `testConnection()` uses the configured async default.
+- **v9.0.0:** [#611](https://github.com/bbottema/simple-java-mail/issues/611): **SMTPS custom SSL socket factories:** fixed custom SSL socket factory configuration for SMTPS mailers.
+- **v9.0.0:** [#535](https://github.com/bbottema/simple-java-mail/issues/535): **Async failure reporting:** let async send and connection-test failures surface through the returned `CompletableFuture` without duplicate framework error logs.
+- **v9.0.0:** [#583](https://github.com/bbottema/simple-java-mail/issues/583): **Java 25 CLI startup:** fixed CLI startup on Java 25.
+- **v9.0.0:** [#616](https://github.com/bbottema/simple-java-mail/issues/616): **CLI optional-argument detection:** removed the runtime JetBrains annotation fork from CLI optional-argument detection.
+- **v9.0.0:** **Standalone CLI command cleanup:** `send`, `connect`, and `validate` now wait for command work and close mailer resources, preventing batch-module resources from keeping the process alive.
+
+#### Dependency and Supporting-Library Updates ####
+
+- **v9.0.3:** **Angus runtime alignment:** bumped Angus Mail to 2.0.5 and added Angus Activation 2.0.3.
+- **v9.0.3:** **Logging dependencies:** bumped Log4j from 2.25.4 to 2.26.1.
+- **v9.0.2:** **Jakarta API alignment:** bumped Jakarta Mail API to 2.1.5 and Jakarta Activation API to 2.1.4.
+- **v9.0.0:** **Core dependency maintenance:** bumped JMail to 2.1.0 ([#634](https://github.com/bbottema/simple-java-mail/pull/634)), commons-io to 2.22.0 ([#579](https://github.com/bbottema/simple-java-mail/pull/579), [#627](https://github.com/bbottema/simple-java-mail/pull/627)), Kryo to 5.6.2 ([#586](https://github.com/bbottema/simple-java-mail/pull/586)), Zip4j to 2.11.5 ([#587](https://github.com/bbottema/simple-java-mail/pull/587)), SubEthaSMTP to 7.2.2 ([#593](https://github.com/bbottema/simple-java-mail/pull/593), [#632](https://github.com/bbottema/simple-java-mail/pull/632)), Angus Mail to 2.0.4 ([#604](https://github.com/bbottema/simple-java-mail/pull/604)), Objenesis to 3.5 ([#580](https://github.com/bbottema/simple-java-mail/pull/580), [#635](https://github.com/bbottema/simple-java-mail/pull/635)), Lombok to 1.18.46 ([#636](https://github.com/bbottema/simple-java-mail/pull/636)), AssertJ Core to 3.27.7 ([#622](https://github.com/bbottema/simple-java-mail/pull/622)), and SpotBugs annotations to 4.10.2 ([#629](https://github.com/bbottema/simple-java-mail/pull/629)).
+- **v9.0.0:** **Logging dependencies:** aligned Log4j to 2.25.4 ([#624](https://github.com/bbottema/simple-java-mail/pull/624)) and SLF4J API to 2.0.18 ([#631](https://github.com/bbottema/simple-java-mail/pull/631)), keeping the Log4j bridge on `log4j-slf4j2-impl` for SLF4J 2.x.
+
+##### Supporting Libraries #####
+
+- **v9.0.3:** **`outlook-message-parser` 1.16.1 / `rtf-to-html` 2.0.2:** fixed browser-default `
` styling in Outlook plain-text RTF conversion ([#651](https://github.com/bbottema/simple-java-mail/issues/651)).
+- **v9.0.2:** **`outlook-message-parser` 1.16.0:** added source last-modifier metadata used by `OutlookMessageData#getLastModifierName()`.
+- **v9.0.0:** **`utils-mail-dkim` 3.3.0:** added configurable DNS provider URL support for DKIM domain-key TXT lookups, fixed the published automatic module name, and kept packaged artifacts free of JaCoCo probes.
+- **v9.0.0:** **`clustered-object-pool` 4.0.1** ([#6](https://github.com/bbottema/clustered-object-pool/issues/6)): added cluster-specific Java configuration for pool defaults, claim timeout, and load balancing.
+- **v9.0.0:** **`smtp-connection-pool` 3.0.1** ([#8](https://github.com/simple-java-mail/smtp-connection-pool/issues/8)): pulled in `clustered-object-pool` 4.0.1 so the batch-module fix for [#565](https://github.com/bbottema/simple-java-mail/issues/565) can keep connection-pool defaults per cluster key.
+- **v9.0.0:** **`smtp-connection-pool` 3.0.0:** made clustered SMTP pools generic over their cluster-key type and kept already-unusable connections from surfacing as generic pool error logs during transport close.
+- **v9.0.0:** **`java-socks-proxy-server` 4.2.0:** updated SOCKS live tests to use dynamic proxy ports instead of fixed ports.
+- **v9.0.0:** **`outlook-message-parser` 1.15.0:** improved Outlook `.msg` conversion by preserving nested message attachment metadata, fixing sent-date extraction ([#534](https://github.com/bbottema/simple-java-mail/issues/534)), fixing recipient bucket parsing ([#504](https://github.com/bbottema/simple-java-mail/issues/504)), broadening S/MIME detection, improving RTF-only body conversion ([#576](https://github.com/bbottema/simple-java-mail/issues/576)), and updating Apache POI.
+
+##### Build and Test Maintenance #####
+
+- **v9.0.3:** **Build maintenance:** bumped Maven Source Plugin to 3.4.0, NotNull Instrumenter Maven Plugin to 1.1.1, and Mycila License Maven Plugin to 4.6.
+- **v9.0.2:** **Build maintenance:** bumped Maven Assembly Plugin to 3.8.0 and Nexus Staging Maven Plugin to 1.7.0, and extended Dependabot guards for Java 11-only plugin lines.
+- **v9.0.1:** **Release packaging:** restored generated license headers in published source JARs and enabled publication of the standalone CLI ZIP and TAR classifier artifacts.
+- **v9.0.0:** **Build plugins and test stack:** bumped Maven Surefire Plugin to 3.5.6 ([#592](https://github.com/bbottema/simple-java-mail/pull/592), [#625](https://github.com/bbottema/simple-java-mail/pull/625)), Maven Clean Plugin to 3.5.0 ([#626](https://github.com/bbottema/simple-java-mail/pull/626)), Appassembler Maven Plugin to 2.1.0 ([#581](https://github.com/bbottema/simple-java-mail/pull/581)), Exec Maven Plugin to 3.5.0 ([#582](https://github.com/bbottema/simple-java-mail/pull/582)), Maven Deploy Plugin to 3.1.4 ([#619](https://github.com/bbottema/simple-java-mail/pull/619)), Maven Install Plugin to 3.1.4 ([#639](https://github.com/bbottema/simple-java-mail/pull/639)), Maven Javadoc Plugin to 3.12.0 ([#637](https://github.com/bbottema/simple-java-mail/pull/637)), Maven GPG Plugin to 3.2.8 ([#621](https://github.com/bbottema/simple-java-mail/pull/621)), and JaCoCo Maven Plugin to 0.8.15 ([#638](https://github.com/bbottema/simple-java-mail/pull/638)); aligned JUnit Platform/Jupiter at 1.14.4/5.14.4 while preserving Java 8 compatibility ([#596](https://github.com/bbottema/simple-java-mail/pull/596), [#633](https://github.com/bbottema/simple-java-mail/pull/633)); kept JUnit Pioneer on 1.9.1 because 2.x is Java 11 bytecode ([#630](https://github.com/bbottema/simple-java-mail/pull/630)); added Java 8 Dependabot guards; and replaced live embedded-image URL tests with deterministic local coverage ([#617](https://github.com/bbottema/simple-java-mail/issues/617)).
+
+The full stand-alone release history is maintained in [RELEASE_HISTORY.md](RELEASE_HISTORY.md).
diff --git a/RELEASE.txt b/RELEASE.txt
index 8e0023d07..fab7bdbdd 100644
--- a/RELEASE.txt
+++ b/RELEASE.txt
@@ -1,137 +1,850 @@
-http://www.simplejavamail.org
-
-
- org.simplejavamail
- simple-java-mail
- 4.1.1
-
-
-RELEASE NOTES Java Simple Mail
-
-v4.1.1
-
-- #50: bug fix for manual naming datasources
-
-
-v4.1.0
-
-- #48: Added programmatic support trusting hosts for SSL connections
-- #47: Honor given names, deduce extension from datasource name, and more robust support for parsing mimemessages
-
-
-v4.0.0
-
-- #41: added support for fast parallel batch processing
-- #42: **added support for config files**
-- #43: removed logging implementation dependencies from distribution and documented various sample configs
-- #39: simplified and renamed packages to reflect the domain name of the new website: simplejavamail.org
-- #38: added support for anonymous proxy
-- #38: **added support for authenticated proxy**
-
-NOTE: All packages have been renamed to "org.simplejavamail.(..)".
-
-
-v3.1.1
-
-Major feature: DKIM support!
-
-- #36: Added proper toString and equals methods for the Email classes
-- #33: Added support for DKIM domain key signing
-
-
-v3.0.2
-
-- #35: added proper .equals() and .toString() methods
-- #34: Fixed bug when disposition is missing (assume it is an attachment)
-- #00: added findbugs support internally
-
-
-v3.0.1
-
-- #31: Fixed EmailAddressCriteria.DEFAULT and clarified Javadoc
-
-
-v3.0.0
-
-- #30: Improved the demonstration class to include attachments and embedded images
-- #29: The package has been restructured for future maintenance, breaking backwards compatibility
-- #28: Re-added improved email validation facility
-- #22: Added conversion to and from MimeMessage. You can now consume and produce MimeMessage objects with simple-java-mail
-
-
-v2.5.1
-
-- #25: Added finally clausule that will always close socket properly in case of an exception
-
-
-v2.5
-
-- #24: Updated dependencies SLF4J to 1.7.13 and switched to the updated javax mail package com.sun.mail:javax.mail 1.5.5
-
-
-v2.4
-
-- #21: Builder API uses CC and BCC recipient types incorrectly
-
-
-v2.3
-
-- #19: supporting custom Session Properties now and emergency access to internal Session object.
-
-
-v2.2
-
-- #3: turned off email regex validation by default, with the option to turn it back on
-- #7: fixed NullPointerException when using your own Session instance
-- #10: properly UTF-8 encode recipient addresses
-- #14: switched to SLF4J, so you can easily use your own selected logging framework
-- #17: Added fluent interface for building emails
-
-
-v2.1
-
-- fixed character encoding for reply-to, from, to, body text and headers (to UTF-8)
-- fixed bug where Recipient was not public resulting in uncompilable code when calling email.getRecipients()
-
-
-v2.0
-
-- added support for open headers (such as X-Priority)
-
-
-v1.9.1
-
-- updated for Maven support (library hasn't changed, but 1.9 was released incorrectly to Maven Central)
-
-
-v1.9
-
-- added support for JavaMail's reply-to address
-- made port optional as to support port defaulting based on protocol
-- added transport strategy default in the createSession method
-- tightened up thrown exceptions (MailException instead of RuntimeException)
-- added and fixed JavaDoc
-
-
-v1.8
-
-Added support for TLS (tested with gmail)
-
-
-v1.7
-
-Added support for SSL! (tested with gmail)
-
-- improved argument validation when creating a Mailer without preconfigured Session instance
-
-know possible issue: SSL self-signed certificates might not work (yet). Please let me know by e-mail or create a new issue
-
-
-v1.6
-
-Completed migration to Java Simple Mail project.
-
-- removed all Vesijama references
-- updated TestMail demonstration class for clarification
-- updated readme.txt for test run instructions
-- included log4j.properties
+https://www.simplejavamail.org
+
+
+ org.simplejavamail
+ simple-java-mail
+ 9.1.3
+
+
+v9.1.0 - v9.1.3
+
+- **v9.1.3:** #668: **New Outlook inline images:** updated outlook-message-parser to 1.16.2 so native-HTML-only .msg files match inline cid: images correctly and trailing NUL terminators no longer leak into attachment metadata.
+- **v9.1.2:** **Dependency and Java 8-compatible build-tool maintenance:** updated JMail to 2.2.0 (#663), Zip4j to 2.11.6 (#666), Exec Maven Plugin to 3.6.3 (#664), Maven Enforcer Plugin to 3.6.3 (#665), and Maven JAR Plugin to 3.5.1 (#667).
+- **v9.1.1:** **Java 8 build-tool maintenance** (#662): updated annotations and Maven compiler, JAR, OSGi bundle, and Karaf tooling to Java 8-compatible versions, with Dependabot guards against newer-Java-only upgrade lines.
+- **v9.1.0:** #653: a configurable SMTP client hostname for the EHLO / HELO command.
+- **v9.1.0:** #654: SMTP submission receipts for reading the server acceptance response after a send.
+- **v9.1.0:** No breaking changes; existing sendMail(...) behavior is unchanged.
+
+
+v9.0.0 - v9.0.4
+
+#### The Short Version ####
+
+**Simple Java Mail has been going strong-ish for about 20 years**, and **9.0.0** rolls *roughly two years of backlog* into a new major release.
+
+```
+simple-java-mail
+└── outlook-message-parser
+ └── rtf-to-html
+└── java-utils-mail-dkim
+└── java-utils-mail-smime
+└── smtp-connection-pool
+ └── clustered-object-pool
+ └── generic-object-pool
+└── java-socks-proxy-server
+```
+
+Across Simple Java Mail and the supporting libraries that keep the stack moving, **more than 100 GitHub issues and PRs** were reviewed, fixed, merged, or closed while keeping the project **Java 8-compatible**.
+
+**Major features:** the dedicated recipient builder API, per-recipient S/MIME certificates, first-class Delivery Status Notification support, pre-encoded attachment and embedded-image sending, mailer-level DKIM defaults, and simple batch/open-connection sending without the batch module.
+**Enhancements:** broader Outlook conversion metadata, MIME resource handling, content-transfer encoding control, debug routing, local SMTP bind configuration, batch cluster configuration, and Java module support.
+
+#### Migration Note ####
+
+**This is a breaking major release.** The old recipient-addition method jungle has been cleaned up in favor of the **recipient builder API**, so code that relied on the removed recipient overloads needs to migrate. Start with the 9.0 migration notes before upgrading: https://www.simplejavamail.org/migration-notes-9.0.0.html
+
+#### Major Features ####
+
+- **v9.0.0:** #613: **Recipient builder API:** added dedicated builders for constructing single recipients and recipient collections.
+- **v9.0.0:** #297: **Per-recipient S/MIME certificates:** enabled encrypted mail for multiple recipients with different certificates.
+- **v9.0.0:** #574: **Delivery Status Notification (DSN):** added first-class DSN configuration.
+- **v9.0.0:** #573: **Pre-encoded resources:** added pre-encoded attachment and embedded-image APIs.
+- **v9.0.0:** #196: **Mailer-level DKIM defaults:** added default DKIM signing configuration so DKIM can be configured once per Mailer.
+- **v9.0.0:** #569: **Simple batch and open-connection sending:** added sendMailsInSimpleBatch(...) for sequential batch work without the batch module and withOpenConnection(...) for callback-scoped reuse of a single SMTP connection.
+
+#### Enhancements ####
+
+- **v9.0.2:** #645: **Outlook last-modifier metadata:** exposed PR_LAST_MODIFIER_NAME / 0x3FFA as OutlookMessageData#getLastModifierName() without treating it as sender identity.
+- **v9.0.0:** #614: **Outlook conversion metadata:** added explicit result APIs for inspecting source .msg headers and metadata without copying structural headers into converted emails, resolving #609.
+- **v9.0.0:** #605: **Per-body content-transfer encoding:** added Content-Transfer-Encoding configuration for plain text, HTML, and calendar content.
+- **v9.0.0:** #566, #597, #602, #607: **MIME resource Content-ID handling:** improved explicit IDs, parsed embedded images, and generated fallback IDs.
+- **v9.0.0:** #589: **Jakarta Mail debug output:** added configurable debug output routing.
+- **v9.0.0:** #568: **Local SMTP bind address:** added configuration for multi-IP SMTP hosts.
+- **v9.0.0:** #565, #618: **Batch cluster configuration:** fixed Java API cluster configuration and added property-defined cluster configurations for property-file and Spring-configured clustered sending.
+- **v9.0.0:** #572, #571: **S/MIME conversion leniency:** tolerate unsupported S/MIME payloads during Outlook conversion and preserve parsed email content when signature verification fails.
+- **v9.0.0:** #606: **MIME type sanitizing:** sanitize malformed resource MIME types before generating attachment and embedded-image headers.
+- **v9.0.0:** #541: **Resource headers:** removed the non-standard filename parameter from resource Content-Type headers; filenames remain available through Content-Disposition.
+- **v9.0.0:** #265, #237: **Java module support:** added Java 9 module descriptors to the core and facade jars so modular applications can require org.simplejavamail directly.
+
+#### Fixes and Compatibility ####
+
+- **v9.0.4:** #652: **RFC 2047 address validation:** reject encoded-word syntax inside address specs during validation while keeping encoded display names valid.
+- **v9.0.3:** #651: **Outlook plain-text RTF rendering:** preserved line breaks without exposing browser-default
styling in converted HTML.
+- **v9.0.0:** #615: **Async test connections:** fixed MailerGenericBuilder.async() so no-arg testConnection() uses the configured async default.
+- **v9.0.0:** #611: **SMTPS custom SSL socket factories:** fixed custom SSL socket factory configuration for SMTPS mailers.
+- **v9.0.0:** #535: **Async failure reporting:** let async send and connection-test failures surface through the returned CompletableFuture without duplicate framework error logs.
+- **v9.0.0:** #583: **Java 25 CLI startup:** fixed CLI startup on Java 25.
+- **v9.0.0:** #616: **CLI optional-argument detection:** removed the runtime JetBrains annotation fork from CLI optional-argument detection.
+- **v9.0.0:** **Standalone CLI command cleanup:** send, connect, and validate now wait for command work and close mailer resources, preventing batch-module resources from keeping the process alive.
+
+#### Dependency and Supporting-Library Updates ####
+
+- **v9.0.3:** **Angus runtime alignment:** bumped Angus Mail to 2.0.5 and added Angus Activation 2.0.3.
+- **v9.0.3:** **Logging dependencies:** bumped Log4j from 2.25.4 to 2.26.1.
+- **v9.0.2:** **Jakarta API alignment:** bumped Jakarta Mail API to 2.1.5 and Jakarta Activation API to 2.1.4.
+- **v9.0.0:** **Core dependency maintenance:** bumped JMail to 2.1.0 (#634), commons-io to 2.22.0 (#579, #627), Kryo to 5.6.2 (#586), Zip4j to 2.11.5 (#587), SubEthaSMTP to 7.2.2 (#593, #632), Angus Mail to 2.0.4 (#604), Objenesis to 3.5 (#580, #635), Lombok to 1.18.46 (#636), AssertJ Core to 3.27.7 (#622), and SpotBugs annotations to 4.10.2 (#629).
+- **v9.0.0:** **Logging dependencies:** aligned Log4j to 2.25.4 (#624) and SLF4J API to 2.0.18 (#631), keeping the Log4j bridge on log4j-slf4j2-impl for SLF4J 2.x.
+
+##### Supporting Libraries #####
+
+- **v9.0.3:** **outlook-message-parser 1.16.1 / rtf-to-html 2.0.2:** fixed browser-default
styling in Outlook plain-text RTF conversion (#651).
+- **v9.0.2:** **outlook-message-parser 1.16.0:** added source last-modifier metadata used by OutlookMessageData#getLastModifierName().
+- **v9.0.0:** **utils-mail-dkim 3.3.0:** added configurable DNS provider URL support for DKIM domain-key TXT lookups, fixed the published automatic module name, and kept packaged artifacts free of JaCoCo probes.
+- **v9.0.0:** **clustered-object-pool 4.0.1** (#6): added cluster-specific Java configuration for pool defaults, claim timeout, and load balancing.
+- **v9.0.0:** **smtp-connection-pool 3.0.1** (#8): pulled in clustered-object-pool 4.0.1 so the batch-module fix for #565 can keep connection-pool defaults per cluster key.
+- **v9.0.0:** **smtp-connection-pool 3.0.0:** made clustered SMTP pools generic over their cluster-key type and kept already-unusable connections from surfacing as generic pool error logs during transport close.
+- **v9.0.0:** **java-socks-proxy-server 4.2.0:** updated SOCKS live tests to use dynamic proxy ports instead of fixed ports.
+- **v9.0.0:** **outlook-message-parser 1.15.0:** improved Outlook .msg conversion by preserving nested message attachment metadata, fixing sent-date extraction (#534), fixing recipient bucket parsing (#504), broadening S/MIME detection, improving RTF-only body conversion (#576), and updating Apache POI.
+
+##### Build and Test Maintenance #####
+
+- **v9.0.3:** **Build maintenance:** bumped Maven Source Plugin to 3.4.0, NotNull Instrumenter Maven Plugin to 1.1.1, and Mycila License Maven Plugin to 4.6.
+- **v9.0.2:** **Build maintenance:** bumped Maven Assembly Plugin to 3.8.0 and Nexus Staging Maven Plugin to 1.7.0, and extended Dependabot guards for Java 11-only plugin lines.
+- **v9.0.1:** **Release packaging:** restored generated license headers in published source JARs and enabled publication of the standalone CLI ZIP and TAR classifier artifacts.
+- **v9.0.0:** **Build plugins and test stack:** bumped Maven Surefire Plugin to 3.5.6 (#592, #625), Maven Clean Plugin to 3.5.0 (#626), Appassembler Maven Plugin to 2.1.0 (#581), Exec Maven Plugin to 3.5.0 (#582), Maven Deploy Plugin to 3.1.4 (#619), Maven Install Plugin to 3.1.4 (#639), Maven Javadoc Plugin to 3.12.0 (#637), Maven GPG Plugin to 3.2.8 (#621), and JaCoCo Maven Plugin to 0.8.15 (#638); aligned JUnit Platform/Jupiter at 1.14.4/5.14.4 while preserving Java 8 compatibility (#596, #633); kept JUnit Pioneer on 1.9.1 because 2.x is Java 11 bytecode (#630); added Java 8 Dependabot guards; and replaced live embedded-image URL tests with deterministic local coverage (#617).
+
+v8.12.0 - v8.12.6
+
+- v8.12.6 (18-April-2025): #595: [bug] Spring configuration - fix support for simplejavamail.extraproperties
+- v8.12.5 (05-March-2025): Bumped PATCH versions of various dependencies (#553, #554, #555, #562, #567)
+- v8.12.4 (12-December-2024): #558: [bug] Mailer.close() exception because it attempts to shutdown batch-module connection pools, even if not available on the classpath
+- v8.12.3 (25-November-2024): #563: [enhancement] Add getter for Authenticated SOCKS server port
+- v8.12.2 (05-October-2024): #552: [bug] support iCalendar events with METHOD defined in body instead of Content-Type
+- v8.12.1 (02-October-2024): #533: [maintenance] Bump com.github.therapi:therapi-runtime-javadoc-scribe from 0.13.0 to 0.15.0
+- v8.12.1 (02-October-2024): #532: [maintenance] Bump com.sanctionco.jmail:jmail from 1.4.1 to 1.6.3
+- v8.12.1 (02-October-2024): #531: [maintenance] Bump com.github.bbottema:java-socks-proxy-server from 4.0.0 to 4.1.2
+- v8.12.1 (02-October-2024): #528: [maintenance] Bump com.github.davidmoten:subethasmtp from 7.0.1 to 7.1.1
+- v8.12.1 (02-October-2024): #522: [maintenance] Bump jakarta.annotation:jakarta.annotation-api from 1.3.5 to 3.0.0
+- v8.12.0 (26-September-2024): #550: [bug] Environment variables are not being loaded properly
+- v8.12.0 (26-September-2024): #538: [bug] System properties are only read if configuration file exists in class path
+- v8.12.0 (26-September-2024): #546: [Enhancement] Trim whitespace in encoder values for Content-Encoding
+
+
+v8.11.0 - v8.11.3
+
+- v8.11.3 (15-September-2024): #543: [Enhancement] reduce log spam from the batch-module
+- v8.11.2 (08-June-2024): #530: [Bug] After converting Outlook .msg to EML, bullet lists have duplicate numbering HTML converted from RTF
+- v8.11.1 (28-May-2024): #529: Bump smtp-connection-pool from 2.3.2 to 2.3.3 which improves performance and fixes a rare ConcurrentModificationException
+- v8.11.1 (28-May-2024): #527: Bump org.slf4j:slf4j-api from 2.0.9 to 2.0.13
+- v8.11.1 (28-May-2024): #523: Bump org.jacoco:jacoco-maven-plugin from 0.8.5 to 0.8.12
+- v8.11.0 (25-May-2024): #526: When reading .msg files the RTF converted to HTML is garbled in some cases where the appropriate charset is not detected properly
+
+NOTE: v8.11.0 contains many (minor) dependency updates to resolve CVE issues, including:
+ - parent POM upgrade: Upgrades test dependencies as well as SLF4J versions
+ - outlook-message-parser 1.13.2 -> 1.14.0
+ - java-reflection 4.0.1 -> 4.0.2
+ - smtp-connection-pool 2.3.1 -> 2.3.2
+ - utils-mail-dkim 3.1.0 -> 3.2.0
+ - jakarta.mail-api 2.1.2 -> 2.1.3
+ - angus-mail 2.0.2 -> 2.0.3
+ - therapi-runtime-javadoc 0.13.0 -> 0.15.0
+ - kryo 5.0.0-RC1 -> 5.6.0
+ - maven-assembly-plugin 3.1.0 -> 3.7.1 (only for the CLI module during build)
+
+
+v8.10.0 - v8.10.1
+
+- v8.10.1 (04-May-2024): #510: Update upstream dependency generic-object-pool, which solves a critical bug when there are exceptions during allocation
+- v8.10.0 (30-April-2024): #508: [enhancement+bug] Make EmailConverter API more consistent regarding Session parameter, don't use `Session.getDefaultInstance` anymore and fix bug where `emlToEmailBuilder` used `emlToMimeMessage`
+
+
+v8.10.0 (30-April-2024)
+
+- #508: [enhancement+bug] Make EmailConverter API more consistent regarding Session parameter, don't use `Session.getDefaultInstance` anymore and fix bug where `emlToEmailBuilder` used `emlToMimeMessage`
+
+
+v8.9.0 (26-April-2024)
+
+- #507: [security] Update 3rd party dependencies to get rid of all currently known CVE issues (see issue for details)
+
+
+v8.8.0 - v8.8.4
+
+- v8.8.4 (23-April-2024): #506: Upgrade utils-mail-smime dependency to 2.3.2, to resolve CVE issue in bouncycastle
+- v8.8.3 (13-April-2024): #502: [Bug] Message headers not treated with case insensitivity as per RFC, causing deviating headers to slip through the filters
+- v8.8.2 (05-April-2024): #495: Add config support for 'verifyingServerIdentity' with SMTP, also: since Angus 1.1.0 server identity checks are on by default and can be countered by mailerBuilder.verifyingServerIdentity(false)
+- v8.8.2 (05-April-2024): #501: [dependency] Update outlook-message-parser dependency, which has improved support for X500 addresses
+- v8.8.1 (04-April-2024): #500: [bug] Fix parsing addresses from headers in EML files, like a Disposition-Notification-To with umlaut
+- v8.8.0 (22-March-2024): #499: [Enhancement] Expose finer-grained DKIM configuration through the builder api and disable 'l-param' by default)
+
+NOTE: this release changes the default for DKIM signing from 'l-param' true to false. If you rely on this feature, you need to enable it explicitly (see the updated https://www.simplejavamail.org/security.html#section-sending-dkim).
+
+
+v8.7.0 - v8.7.1
+
+- v8.7.1 (20-March-2024): #498: [Enhancement] Make S/MIME algorithms configurable (signature algorithm for signing, key encapsulation and cipher algorithms for encryption)
+- v8.7.1 (20-March-2024): #497: [Bug] Order of attachments is lost when converting a MimeMessage to an Email
+- v8.7.0 (20-March-2024): don't use this version: versioning messed up
+
+NOTE: this breaks the API for S/MIME related builder methods. Refer to the [S/MIME documentation](https://www.simplejavamail.org/security.html#section-sending-smime) for the new API.
+
+
+v8.6.0 - v8.6.3
+
+- v8.6.3 (13-February-2024): #491: [bug] Attachment body parts should separately parse Content-Disposition and ContentID, possible resulting in an downloadable attachment that is also embedded
+- v8.6.2 (27-January-2024): #493: [bug] don't require smime-module when adding collection of headers (also used when copying email)
+- v8.6.1 (18-January-2024): #487: Move header filtering from MimeMessageParser to EmailConverter, thereby enabling access to all parsed headers when using MimeMessageParser directly
+- v8.6.1 (18-January-2024): #489: Finished update to Angus Mail by updating activation dependency
+- v8.6.0 (17-January-2024): #489: Update to Angus Mail
+
+NOTE: this release switches to Angus Mail which should be a transparent change, but if you encounter any issues, please report them.
+ One known issue is that Angus, since 1.1.0, performs server identity checks by default, which was previously disabled for SMTP. If you encounter issues with this, you can disable it with `mailerBuilder.verifyingServerIdentity(false)` and starting from 8.8.2, this also works with SMTP transport strategy (see #495).
+
+
+v8.5.0 - v8.5.1
+
+- v8.5.1 (15-December-2023): #486: [dependency] Handle Outlook's Non-Standard S/MIME Signed Messages
+- v8.5.0 (13-December-2023): #484: [bug] Addresses passed as string are not always interpreted correctly
+
+
+v8.4.0 (12-December-2023)
+
+- #483: Enhancement: add native support for overriding envelope-level receiver(s)
+
+
+v8.3.0 - v8.3.5
+
+- v8.3.5 (10-December-2023): #482: Bug: 'IllegalArgumentException: emailAddressList is required' when parsing mail with incorrect recipients from Outlook message
+- v8.3.4 (08-December-2023): #481: Enhancement: don't crash on invalid empty attachments when parsing Outlook messages
+- v8.3.3 (03-December-2023): #477: Enhancement: Support Exchange proprietary addresses (X.500 DAP)
+- v8.3.2 (26-November-2023): #480: Bug: Multiple attachments with same name get the same Content-ID, causing them to refer to the same file content
+- v8.3.1 (09-October-2023): #440: Bug: names manually specified for embedded images are overridden and have extension added, breaking cid: references in HTML body
+- v8.3.0 (09-October-2023): #475: Enhancement: Add configuration metadata for Spring Boot application properties
+
+
+v8.2.0 (02-October-2023)
+
+- #473: Bugfix: Add missing support for multiple reply-to addresses
+
+
+v8.1.0 - v8.1.3
+
+- v8.1.3 (14-July-2023): #467: Security: Medium severity vulnerability is detected in org.bouncycastle transitive dependency
+- v8.1.3 (14-July-2023): #466: Maintenance: Let Mailer implement AutoCloseable, so it shuts down the connection pool automatically when disposed of by Spring
+- v8.1.2 (23-June-2023): #465: Regression bug #461: Simple Java Mail always requires DKIM/SMIME modules
+- v8.1.1 (07-June-2023): #461: Bugfix: Fixed MessageID not preserved when signing/encrypting with S/MIME and/or DKIM
+- v8.1.0 (15-April-2023): #458: Missing osgi headers (#288) and added support for Apache Karaf
+- v8.1.0 (15-April-2023): #288: Maintenance: missing OSGI package-exports from core-module
+
+
+v8.0.0 - v8.0.1
+
+- v8.0.1 (30-April-2023): #456: Enhancement: make Content-Transfer encoder detection more lenient, supporting more values from the wild
+- v8.0.0 (08-March-2023): #451: Feature: Make defaults and overrides a first class feature
+- v8.0.0 (08-March-2023): #452: Enhancement: with ".disableAllClientValidation(true)", also ignore errors from the completeness check
+- v8.0.0 (08-March-2023): #450: Bug: when using dispositionNotificationTo or returnReceiptTo mode, when the corresponding emails are not filled, it fails even though it should fall back to replyTo or From
+- v8.0.0 (08-March-2023): #449: Bug: IllegalArgumentException on parsing empty header name and value (when parsing Outlook message)
+- v8.0.0 (08-March-2023): #448: Bug: withEmailDefaults and withEmailOverrides does not work with CustomMailer
+- v8.0.0 (08-March-2023): #447: Enhancement: allow defaults/overrides to ignore individual fields (turn off for specific properties)
+- v8.0.0 (08-March-2023): #446: Enhancement: add missing defaults properties for DKIM
+
+This release changes how Email instances are built, or more specifically, when defaults and overrides are applied.
+There are now overloaded build methods that provide similar behaviour as previous versions.
+
+
+v7.9.0 - v7.9.1
+
+- v7.9.1 (22-February-2023): #444: Bugfix: encoded delimited recipients in EML not parsed properly
+- v7.9.0 (21-February-2023): #344: Enhancement: make DKIM signing more flexible by allowing header exclusions in DKIM signature
+
+
+v7.8.0 - v7.8.3
+
+- v7.8.3 (21-February-2023): #293: Bugfix: Decoding missing in a few placed when parsing MimeMessage or sending an Email
+- v7.8.2 (09-February-2023): #442: Enhancement: Simple Java Mail should throw an exception when trying to utilize S/MIME with smime-module on the classpath
+- v7.8.1 (01-February-2023): #438: Bug: properly Fail-Fast in case of Transport claim timeout in the batch-module, rather than running into NPE further down the line
+- v7.8.0 (24-January-2023): #436: Enhancement: add mailerBuilder.withTransportModeLoggingOnly() as mailer API entry point
+- v7.8.0 (24-January-2023): #435: Enhancement: SMTP server config should be optional in case a CustomMailer is used
+- v7.8.0 (24-January-2023): #427: Feature: set a maximum email size on Mailer level which throws EmailToBig exception when exceeded
+
+
+v7.7.0 - [v7.7.1](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C7.7.1%7Cjar)
+
+- v7.7.1 (18-January-2023): #434: Regression bug in #430: Email parameter missing in CustomMailer interface
+- v7.7.0 (17-January-2023): #430: Enhancement: auto-reconnect (if needed) when reclaiming a Transport connection from the SMTP connection
+- v7.7.0 (17-January-2023): #383: Feature: be able to set defaults and overrides on the Mailer level, rather than email or global level
+
+7.7.0 moves the conversion of Email to MimeMessage to after a Transport instance has been selected (in case of a cluster of SMTP servers),
+so we can apply defaults/overrides on the Mailer level, meaning you can configure 'global' values for individual SMTP servers
+(like a fixed FROM per server).
+
+
+v7.6.0 (05-January-2022)
+
+- #421: Enhancement: Add support for OAUTH2 authentication
+
+
+v7.5.0 - v7.5.2
+
+- v7.5.2 (25-December-2022): #429: Bug: wrong username property used when password authentication is not needed
+- v7.5.1 (12-December-2022): #416: Bug: Support encoder names regardless of their case ("base64" is the same as "BASE64")
+- v7.5.1 (12-December-2022): #424: Maintenance: bump JMail dependency from 1.2.1 to 1.4.1
+- v7.5.0 (28-July-2022): #411: Enhancement: expose validation sub steps in the MailerHelper class for the completeness check, CRLF inject scans and address validations
+- v7.5.0 (28-July-2022): #410: Bug: CRLF injection scan missing for dispositionNotificationTo and returnReceiptTo
+- v7.5.0 (28-July-2022): #390: Enhancement: make client sided validation optional, turning off address validation and CRLF injection detection
+
+
+v7.4.0 (19-July-2022)
+
+- #407: Enhancement: Process all Outlook message headers, either copying the as-is or translating them to respective Simple Java Mail API calls
+- #404: Minor bugfix: the new attachment's contentDescription was missing in Email.toString()
+
+
+v7.3.0 (15-July-2022)
+
+- #405: Feature: Expand email builder API to support forced content Content-Transfer-Encoding for attachments, like quoted-printable, base64, 7BIT and others
+- #404: Feature: Expand email builder API to support Content-Description on attachments
+
+
+v7.2.0 - v7.2.1
+
+- v7.2.1 (13-July-2022): #396: Enhancement: make Outlook support tolerant of invalid/empty nested Outlook message attachments
+- v7.2.0 (13-July-2022): #399: Feature: Expand email builder API to support selective content encoding, like quoted-printable, base64, 7BIT and others
+
+
+v7.1.0 - v7.1.3
+- v7.1.3 (12-July-2022): #403: Security: Bump zip4j (only used during testing)
+- v7.1.2 (12-July-2022): #401: Enhancement: Add HEIC and WEBP support when dynamically resolving embedded images from classpath
+- v7.1.2 (12-July-2022): #402: Security: Update Log4j to 2.17.1
+- v7.1.2 (12-July-2022): #393: Security: Update Apache POI and POI Scratchpad
+- v7.1.1 (27-March-2022): #387: Bug: memory leak in SMPT connection pool when 3rd party deallocation failed with exception
+- v7.1.0 (25-January-2022): #379: Maintenance: Adjust dependencies and make Java 9+ friendly
+
+
+v7.0.1 - v7.0.2
+
+- v7.0.2 (25-January-2022): #329: Enhancement: Exceptions cause error-level logging in addition to rethrowing the exception, but should just include the message in a custom exception
+- v7.0.2 (25-January-2022): #378: Bug: package org.simplejavamail.internal.modules causes split package problem in Java9+
+- v7.0.1 (22-January-2022): #375: Bug: [batch-module](https://www.simplejavamail.org/features.html#section-sending-asynchronously) gives error when there is a [custom mailer](https://www.simplejavamail.org/features.html#section-custom-mailer)
+
+
+v7.0.0 (2-January-2022)
+
+It has been two years since the last major release, but 7.0.0 finally here!
+
+#### What's new ####
+
+Major features:
+- #322: Simple Java Mail migrated to Java 8 finally (see notes below)
+- #295: And also switched to JavaMail's successor Jakarta Mail 2.0.1 (see notes below)
+- #323: Solved the great CLI performance problem (now executes near instantly)
+- #319: Replaced the underlying regex-based email-address validation library with the lexer based [JMail](https://github.com/RohanNagar/jmail), which is faster, correcter, documented better and is more up-to-date with RFC's
+- #367: The sendMail/testConnection methods now has proper support for `CompletableFuture`
+
+Bugfixes:
+- #352: Bug: names regex groups are not supported in Android JVM
+- #326: Bug: NullPointer when parsing Outlook Message with nested empty Outlook message
+- #330: Bug: cli expected --mailer arguments duplicated 3 times
+- #324: Bug: Add back missing log4j2 for CLI library
+
+Maintenance:
+- #368: Resolve log4j (Java8) [vulnerability](https://logging.apache.org/log4j/2.x/security.html) in Simple Java Mail's CLI module
+- #330: Improved feedback from failing CLI commands
+- #327: Implement toString() for Mailer instances for debugging purposes
+
+#### About the migration ####
+
+Updating to Java8/Jakarta 2.0.1 posed a challenge as the 3rd party S/MIME library https://github.com/markenwerk/java-utils-mail-smime has been abandoned/archived while developing Simple Java Mail. Furthermore, it was still under LGPL3 license while everything else is ApacheV2.
+
+Thankfully, I obtained permissions from the maintainers -as well as original developers from decades ago on SourceForge- to take both java-utils-mail-smime and java-utils-mail-dkim under my wings at Simple Java Mail and change the licensing model! You can now post issues and pull requests here:
+- https://github.com/simple-java-mail/java-utils-mail-smime
+- https://github.com/simple-java-mail/java-utils-mail-dkim
+
+
+v6.7.0 - v6.7.6
+
+- v6.7.6 (22-January-2022): #375: Bug: batch-module gives error when there is a custom mailer
+- v6.7.5 (26-December-2021): #338: Enhancement: Also return AsyncResponse from plain Mailer.sendEmail(singleArgument) as async can be configured through MailerBuilder now
+- v6.7.4 (25-December-2021): #331: Enhancement: Coalesce empty SMTP server arguments to null to support CLI better
+- v6.7.3 (25-December-2021): #335: Bugfix: Precondition nonNull check also checks nonEmpty and breaks on clearEmailAddressCriteria
+- v6.7.2 (25-December-2021): #318: Maintenance: Allow zero data attachments so Outlook message conversions don't crash and burn
+- v6.7.1 (25-December-2021): #346: Bugfix: Add option to parse MimeMessage without fetching attachment data from server - Properly return named datasource without fetching all the data if unwanted
+- v6.7.0 (25-December-2021): #356: Enhancement: Improve for support for Android < 8.0 (Fix NoClassDefFoundError)
+- v6.7.0 (25-December-2021): #351: Bugfix: emlToEmail() and mimeMessageToEmail() break on mesages with duplicate names and legacy empty nested messages
+- v6.7.0 (25-December-2021): #347: Maintenance: Reduce log-spam and prevent exception on every module availability check
+- v6.7.0 (25-December-2021): #346: Feature: Add option to parse MimeMessage without fetching attachment data from server
+
+
+v6.6.0 - v6.6.2
+
+- v6.6.2 (23-December-2021): #365: Resolve log4j vulnerability in Simple Java Mail
+- v6.6.1 (12-June-2021): #321: Ignore malformed recipient addresses and continue parsing email data
+- v6.6.0 (1-June-2021): #320: Added default S/MIME signing to Mailer lever and fixed crippling performance bug
+
+
+v6.5.0 - v6.5.4
+
+- v6.5.4 (22-May-2021): #315: Enhancement: Nested attachments of Outlook message attachments are now preserved as standard EML MimeMessage attachments
+ **NOTE:** This _removes_ the Kryo dependency
+- v6.5.3 (4-May-2021): #314: Bugfix: Nested attachments of Outlook message attachments are now preserved, by utilizing Kryo
+ **NOTE:** This add Kryo as extra dependency to the outlook-module (and is subsequently removed in 6.5.4)
+- v6.5.2 (15-April-2021): #307: Bugfix: text/calendar as string -> ClassCastException (if calendar type is not Inputstream)
+- v6.5.1 (10-April-2021): #307 / #310: Bugfix: embedded image name got mangled if they included an extension
+- v6.5.0 (16-February-2021): #298: Enhancement: Nested Outlook messages aren't discarded anymore, but parsed to serialized Email objects
+- v6.5.0 (16-February-2021): #292: Bugfix: NullPointerException in SmimeUtilFixed when protocol is missing (which is valid)
+- v6.5.0 (16-February-2021): #289: Bugfix: Support multiple headers with same key
+
+This release breaks all GET/SET api regarding headers used as map (Map -> Map>)
+This release might break api in the rare case you relied on the attachment list and you have nested Outlook .msg attachments (previously omitted in the results)
+
+
+v6.4.0 - v6.4.5
+
+- v6.4.5 (13-Februari-2021): #306: Maintenance: Update outlook-message-parser to 1.7.9
+- v6.4.5 (13-Februari-2021): #304: Regression bugfix: batch-module needed for sending mails async, basic version should work without
+- v6.4.5 (13-Februari-2021): #303: Bugfix: EML Attachments are modified/have the wrong size
+- v6.4.4 (25-October-2019): #294: Always invoke async success/exception handlers even if set after sending email (behaving more like promises/futures)
+- v6.4.4 (25-October-2019): #291: On Exception only log the email ID at error level and log the whole email at trace level
+- v6.4.4 (25-October-2019): #290: Only perform expensive logging logic if respective logging level is enabled
+- v6.4.3 (6-August-2019): #284: Improved support for Calendar attachments created by gMail
+- v6.4.3 (6-August-2019): #283: Bugfix: Fix support for reading Calendar attachments with quoted-printable transfer-type
+- v6.4.2 (3-August-2019): #281: Bugfix: Fix support for reading Calendar attachments
+- v6.4.1 (26-July-2019): #252: Bugfix: Added missing support for S/MIME envloped signing
+- v6.4.0 (19-July-2019): #268: Bugfix: Immediately resolve InputStreams when building emails, don't reuse (which resulted in errors)
+ * This primarily affects the builder api for S/MIME and DKIM signing / encryption.
+
+
+v6.3.0 - v6.3.2 (11-July-2020 - 12-July-2020)
+
+- #271: Bugfix: Attachment (file)names with special characters should not be encoded
+- #248: Bugfix: MimeMessageHelper: use complete filename as resource name
+- #279: Allow extra Session properties configured through simplejavamail.properties
+- #277: Add API for using custom SSLSocketFactory
+
+
+v6.2.0 (6-July-2020)
+
+This release adds the following major new feature:
+
+- #260: Add support for dynamic datasource resolution (file/url/classpath) for embedded images in HTML body
+
+
+v6.1.0 (5-July-2020)
+
+- #264: Switch from AssertionError to IllegalStateException
+- Bumped outlook-message-parser from 1.7.3 to 1.7.5
+ - bugfix for parsing chinese unsent Outlook messages
+ - bugfix Outlook attachments with special characters in the name
+- Bumped email-rfc2822-validator from 2.1.3 to 2.2.0
+ - bugfix properly handle brackets in email addresses when allowed
+- Bumped log4j-core from 2.6.1 to 2.13.2
+
+
+v6.0.2 - v6.0.5 (21-Januari-2020 - 13-June-2020)
+
+- #270: Bug: CLI module missing Jetbrains @Nullable annotation dependency needed in runtime
+- #262: Bug: Executor settings passed to the builder are ignored
+- #249: Bug: MimeMessageParser doesn't handle multiple attachments with the same name correctly
+- #245: Bug: JDK9+ Incorrect JPMS Automatic-Module-Name
+- #246: Bug: Sending async emails with and without the Batch module cause lingering threads
+
+
+v6.0.0-rc1 - v6.0.1 (18-December-2019 - 24-January-2020)
+
+After almost two years of development the next major release 6.0.0 is finally here! And what a doozy it is, with the following major new features:
+
+The core library is now even smaller compared to the 5.x.x series going from 183kb to 134kb!
+
+- [CLI support!!](https://github.com/bbottema/simple-java-mail/issues/156),
+- major performance improvement with [advanced batch processing](https://github.com/bbottema/simple-java-mail/issues/214) including support for mail server clusters.
+- You can now replace the final sending of emails with [your own logic](https://github.com/bbottema/simple-java-mail/issues/121), using a 3rd party service of your choice.
+- 6.0.0 also includes support for [S/MIME signed and encrypted emails](https://github.com/bbottema/simple-java-mail/issues/187)!
+- All 3rd party dependencies have been made optional by splitting up Simple Java Mail into easy to use [modules](https://github.com/bbottema/simple-java-mail/issues/183).
+- You can now monitor and [handle async processing](https://github.com/bbottema/simple-java-mail/issues/148) using Futures.
+- MimeMessage results are now [structurally matched](https://github.com/bbottema/simple-java-mail/issues/144) to specific needs (only using alternative/mixed etc. when needed)
+
+Here's the complete list of changes:
+
+#### New features and enhancements ####
+- #183: To manage all the optional dependencies and related code, Simple Java Mail should be split up into modules
+- #156: Add CLI support
+- #214: Support more advanced batch processing use cases
+- #187: Simple Java Mail should have optional support for signed S/MIME attachments
+- #121: Introduce interfaces for validation and sending, so these steps can be customized
+- #144: Simple Java Mail should tailor the MimeMessage structure to specific needs
+- #138: Add support for Calendar events (iCalendar vEvent)
+- #235: Be able to fix the sent date for a new email
+- #232: Improve encoding of attachment file names
+- #222: Add config property support for trusting hosts and verifying server identity
+- #212: Authenticated proxy server started even if already running, raising exception
+- #207: Implement more comprehensive ThreadPoolExecutor and expose config options
+- #211: SpringSupport should expose the intermediate builder for customization
+- #193: Simple Java Mail should use default server ports when not provided by the user
+
+#### Bugs solved ####
+- #242: Renamed log4j2.xml to log4j2_example.xml so it doesn't clash with project config
+- #241: EmailConverter.outlookMsgToEmail duplicates recipients
+- #239: List of Recipients not ordered as added (insertion order not maintained)
+- #236: Message ID should be mapped from Outlook messages as well
+- #210: Connection/session timeout properties not set when not sending in batch mode
+- #201: When parsing Outlook message, FROM address should default to a dummy address when missing
+- #200: When parsing Outlook message, attachment name doesn't fallback on filename if proper name is empty
+- #161: When reading (chinese) .msg files, HTML converted from RTF is completely garbled (encoding issue)
+- #159: Can not parse email with blank email address headers
+- #139: Multiple Bodyparts of same Content-Type not supported for text/html & text/plain within Multipart/mixed or Multipart/alternative
+- #151: Attachment's file extension overwritten by resource's invalid extension
+
+#### Maintenance updates ####
+- #165: Move away from Findbugs (unofficial JSR-305) annotations
+- #164: The DKIM dependency has been updated to benefit from the newer Apache V2 license
+- #164: The DKIM dependency has been updated to benefit from the newer Apache V2 license
+- #184: Update JavaMail dependency to 1.6.2, adding support for UTF-8 charset
+- #186: Update JavaMail dependency to 1.6.2, adding support for authenticated HTTP web proxy
+- #146: Added OSGI manifest and switched to spotbugs
+
+#### Included changes from the outlook-message-parser dependency ####
+- v6.0.1, v1.7.3: #27: When from name/address are not available (unsent emails), these fields are filled with binary garbage
+- v6.0.1, v1.7.2: #26: To email address is not handled properly when name is omitted
+- v6.0.0, v1.7.1: #25: NPE on ClientSubmitTime when original message has not been sent yet
+- v6.0.0, v1.7.1: #23: Bug: __nameid_ directory should not be parsed (and causing invalid HTML body)
+- v6.0.0, v1.7.0: #18: Upgrade Apache POI 3.9 -> 4.x (but managed back for Simple Java Mail due to incompatibility with Java 7)
+- v6.0.0, v1.6.0: #21: Multiple TO recipients are not handles properly
+- v6.0.0, v1.5.0: #20: CC and BCC recipients are not parsed properly
+- v6.0.0, v1.5.0: #19: Use real Outlook ContentId Attribute to resolve CID Attachments
+- v6.0.0, v1.4.1: #17: Fixed encoding error for UTF-8's Windows legacy name (cp)65001
+- v6.0.0, v1.4.0: #9: Replaced the RFC to HTML converter with a brand new RFC-compliant convert! (thanks to @fadeyev!)
+- v6.0.0, v1.3.0: #14: Dependency problem with Java9+, missing Jakarta Activation Framework
+- v6.0.0, v1.3.0: #13: HTML start tags with extra space not handled correctly
+- v6.0.0, v1.3.0: #11: SimpleRTF2HTMLConverter inserts too many tags
+- v6.0.0, v1.3.0: #10: Embedded images with DOS-like names are classified as attachments
+- v6.0.0, v1.3.0: #9: SimpleRTF2HTMLConverter removes some valid tags during conversion
+- v6.0.0, v1.2.1: Ignore non S/MIME related content types when extracting S/MIME metadata
+- v6.0.0, v1.2.1: Added toString and equals methods to the S/MIME data classes
+- v6.0.0, v1.1.21: Upgraded mediatype recognition based on file extension for incomplete attachments
+- v6.0.0, v1.1.21: Added / improved support for public S/MIME meta data
+- v6.0.0, v1.1.20: #7: Fix missing S/MIME header details that are needed to determine the type of S/MIME application
+- v6.0.0, v1.1.19: Log rtf compression error, but otherwise ignore it and keep going and extract what we can.
+
+**A big shout out to @dnault ([runtime javadoc](https://github.com/dnault/therapi-runtime-javadoc)), @remkop ([picocli](https://picocli.info/)) and @markenwerk
+([S/MIME](https://github.com/markenwerk/java-utils-mail-smime) and [DKIM](https://github.com/markenwerk/java-utils-mail-dkim)) for working with me to make the
+libraries work with JDK7+ and do what Simple Java Mail needed! Finally a great many thanks the numerous contributors on Simple Java Mail as well as
+[outlook-message-parser](https://github.com/bbottema/outlook-message-parser) - this release would not be there without you.**
+
+
+v5.5.0 - [v5.5.1](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C5.5.1%7Cjar)
+
+- v5.5.1 (20-October-2019): #230: Bugfix: Missing address value in address headers (ie. Return-Path) not handled properly, resulting in Exception
+- v5.5.0 (15-October-2019): #229: Bugfix: Timeouts not working for synchronous sendMail calls.
+
+ If you had connection properties configured for non-async send jobs, only now they will actually start to take effect.
+
+
+v5.4.0 (28-August-2019)
+
+- #221: API bugfix: server identity verification should not be tied to host trusting
+- #226: Bug fix: Attachments with spaces in name are not handled properly
+- #218: Enhancement: make Email serializable
+- #227: Enhancement: Make parsing recipients from EML file more lenient
+- #225: Enhancement: Clarify dependency on Jakarta Activation: DataSources no longer work on Java 9+
+
+
+v5.3.0 (16-August-2019)
+
+- #215: Enhancement: Make DKIM header canonicalization RELAXED instead of SIMPLE
+
+Note this release should have no impact, but nonetheless is a minor update so you can determine for yourself if this update would cause issues.
+The release changes DKIM header canonicalization from SIMPLE to RELAXED.
+
+
+v5.2.1 (16-August-2019)
+
+- #219: Bug: MimeMessageParser rejects attachments with duplicate names
+
+
+v5.2.0 (7-July-2019)
+
+- #213: Update from javax.mail:1.6.0 to jakarta.mail:1.6.3
+
+Note that dependencies that switched as well have been updated as part of this change. This includes the optional DKIM library and the email validation library:
+- net.markenwerk:utils-mail-dkim (1.1.10 -> 1.2.0)
+- com.github.bbottema:emailaddress-rfc2822 (1.1.2 -> 2.1.3)
+
+
+v5.1.1 - v5.1.7
+
+- v5.1.7 (22-May-2019): #171 Header validation tripping on known safe emails due to References header
+- v5.1.6 (27-April-2019): #204A Concurrent exception when an async process starts when the previous connection pool didn't shutdown in time
+- v5.1.6 (27-April-2019): #204B Exceptions in threads are now caught and logged and don't bubble up anymore
+- v5.1.5 (24-April-2019): #202 Fixed ConcurrentModificationException when moving invalid embedded images as regular attachments
+- v5.1.4 (5-April-2019): Fixed missing mimetype for attachments when parsing Outlook messages where mimeTag was not included
+- v5.1.3 (15-Januari-2019): Updated to newer rfc-validator version, which fixed a regression bug in that library
+- v5.1.2 (9-Januari-2019): #189 Bugfix for missing timeout config for .testConnection() function
+- v5.1.1 (22-December-2018): #190 Fix for transitive dependency clash because of emailaddress-rfc2822 library
+
+
+v5.1.0 (21-November-2018)
+
+- #179 You can now test the connection to the SMTP server
+
+
+v5.0.1 - v5.0.8
+
+- v5.0.8 (27-Oktober-2018): #178 Fix the annoying vulnerability Github report about spring-core
+- v5.0.7 (27-Oktober-2018): #175 Attachment names are not always parsed properly from MimeMessage
+- v5.0.6 (3-Oktober-2018): #167 Email addresses validated despite cleared validation validation criteria
+- v5.0.5 (3-Oktober-2018): #137 When replying to an email with HTML, the result body is empty
+- v5.0.4 (22-September-2018): #168 Properties aquired through ConfigLoader should be typed explicitly and converted if necessary
+- v5.0.3 (11-April-2018): #136 ServerConfig class should be public API
+- v5.0.2 (7-April-2018): #135 trustingAllHosts should be public on the Builder API
+- v5.0.2 (7-April-2018): #131 NamedDataSource should implement EncodingAware
+- v5.0.1 (10-March-2018): #130 java.lang.ClassNotFoundException: net.markenwerk.utils.mail.dkim.DkimMessage. Solves the issue of missing optional class DKIM even when not used
+
+
+v5.0.0 (14-Februari-2018)
+
+Also see the migrating notes (https://www.simplejavamail.org/migration-notes-5.0.0.html#navigation)
+
+New features
+- #116 You can now test the connection to the SMTP server
+- #115 Create mailers with a very robust MailerBuilder API, able to ignore defaults as well
+- #114 Create emails with a very robust EmailBuilder API, able to ignore defaults as well. Now includes support for InternetAddress. Also copy
+emails.
+- #107 You can now easily forward or reply to emails!
+
+Maintenance updates
+
+Complete JavaDoc overhaul. Navigating the JavaDoc should be much more consistent now (builder API being the single *public* source of truth).
+
+- #122 The email-rfc2822-validator library has been made a proper Maven dependency (not packaged along anymore)
+- #120 The DKIM library has been made an optional proper Maven dependency (not packaged along anymore)
+- #119 Switched optional Spring dependency version to property and now testing with 4.3.11.RELEASE
+- #113 Updated the underlying JavaMail to 1.6.0
+
+Security updates
+- #111 Protocol properties for SMTPS are now applied properly
+- #105 SMTP tries to upgrade to TLS while SMTP_TLS now enforces it and for both SMTP_TLS and SMTPS, mail.smtp.ssl.checkserveridentity is set
+to true (https://javaee.github.io/javamail/docs/api/com/sun/mail/smtp/package-summary.html)
+
+Bugfixes
+- #110 Trusted hosts should be space-delimited
+- #109 Email headers should be allowed to be empty (now conversion errors can occur as well)
+- #103 Converting to MimeMessage results in an invalid Content-Disposition for attachments
+
+
+v4.4.5 (2-September-2017)
+
+- #101 API backwards compatibility update, reinstate old addRecipient API as deprecated (sorry for removing it abruptly)
+
+
+v4.4.4 (21-August-2017)
+
+API usability release. *This relase streamlined the recipient setters, breaking backwards compatibility (but straightforward to fix)*
+
+- #95 Feature: Add support native API for setting Return-Receipt-To header
+- #93 Feature: Add support native API for setting Disposition-Notification-To header
+- #91 *Feature: Add support for parsing preformatted email addresses that include both name and address*
+- #94 Bugfix: A single EmailBuilder would build emails that all share the same collections for recipients, attachments and embedded images
+- #98 Bugfix: Subject and body content should be optional
+
+v4.3.0 (12-August-2017)
+
+Security and timeout release.
+
+This version safeguards against SMTP injection attack from external values entering the library through *Email* instance. Also, this release
+introduces default/configurable timeouts for connecting, reading and writing when sending an email.
+
+- #89 Support multiple delimited recipient addresses sharing the same TO/CC/BCC name
+- #88 Safeguard subject property (and others) against SMTP CRLF injection attacks
+- #85 Apply configurable timeouts when sending emails
+- #83 Parse INLINE attachments without ID as regular attachments when converting (mostly applicable to Apple emails)
+
+
+v4.2.3 (21-May-2017)
+
+- #79: Enhancement: define custom message ID on the Email object
+- #74: v4.2.3-java-6-release: A java6 version with limited capabilities:
+ I've released a customised java6 release with a customised outlook-message-parser 1.1.16-java6-release. This is the last java6 release I will do,
+ as it is simply too much manual labor to create a limited second edition.
+
+ For this edition, I've removed the JDK7 Phaser completely which has the following consequences:
+
+ - If authenticated proxy is used, the bridging proxy server will not be shut down automatically (and might not run the second time)
+ - If mails are sent in async mode, the connection pool will not be shut down anymore by itself
+
+ This means your server/application might not stop properly due to lingering processes. To be completely safe, only send emails in sync mode (used by default) and don't use authenticated proxy config.
+
+
+v4.2.2 (10-May-2017)
+
+- #73: Patch: fix for sending emails in async mode, which makes sure the connection pool is always closed when the last *known* email has been sent. Without
+this fix, the connection pool keeps any parent process running (main thread or Tomcat for example) until a hard kill.
+
+
+v4.2.1 (12-Feb-2017)
+
+Patch: streamlined convenience methods for adding recipients.
+
+
+v4.2.0 (12-Feb-2017)
+
+Major feature: Using the EmailConverter you can now convert between Outlook .msg, EML, MimeMessage and Email!
+
+- #66: Feature: convert email to EML
+- #65: Feature: read outlook messages from .msg file
+- #64: Feature: Added support for logging-only mode that skips the actual sending of emails
+- #63: Feature: Already including in previous patch update: Spring support (read properties from Spring context)
+- #69: Enhancement: Expanded EmailBuilder API to inlude more options for setting (multiple) recipients
+- #70: Enhancement: Most public API now have defensive null-checks for required fields (Fail Fast support)
+- #68: Bugfix: Name should be required for embedded images (added safeguards)
+- #67: Bugfix: Error when name was omitted for attachment
+- minor: added methods on AttachmentResource that reads back the content as (encoded) String
+- other: internal testing is now done using Wiser SMTP test server for testing live sending emails
+
+Note: Starting this release, there will always be a Java6 compatible release as well versioned: "x.y.z-java6-release"
+
+
+v4.1.3 (28-Jan-2017)
+
+- #61: Feature: Add support for providing your own Properties object
+- #63: Feature: Spring support (read properties from Spring context)
+- #58: Bugfix: Add support for non-English attachment and embedded image names
+- #62: Bugfix: Empty properties loaded from config should be considered null
+
+NOTE: ConfigLoader moved from /internal/util to /util
+
+
+v4.1.2 (07-Nov-2016)
+
+- #52: bug fix for windows / linux disparity when checking socket status
+- #56: bug fix for IOException when signing dkim with a File reference
+
+
+v4.1.1 (30-Jul-2016)
+
+- #50: bug fix for manual naming datasources
+
+
+v4.1.0 (22-Jul-2016)
+
+- #48: Added programmatic support trusting hosts for SSL connections
+- #47: Honor given names, deduce extension from datasource name, and more robust support for parsing mimemessages
+
+
+v4.0.0 (05-Jul-2016)
+
+- #41: added support for fast parallel batch processing
+- #42: **added support for config files**
+- #43: removed logging implementation dependencies from distribution and documented various sample configs
+- #39: simplified and renamed packages to reflect the domain name of the new website: simplejavamail.org
+- #38: added support for anonymous proxy
+- #38: **added support for authenticated proxy**
+
+NOTE: All packages have been renamed to "org.simplejavamail.(..)"
+NOTE: Switched to Java 7
+
+
+v3.1.1 (11-May-2016)
+
+Major feature: DKIM support!
+
+- #36: Added proper toString and equals methods for the Email classes
+- #33: Added support for DKIM domain key signing
+
+NOTE: this is the last release still using Java 6. Next release will be using Java 7.
+/edit: starting with 4.2.0 every release will now have a "x.y.z-java6-release" release as well
+
+
+v3.0.2 (07-May-2016)
+
+- #35: added proper .equals() and .toString() methods
+- #34: Fixed bug when disposition is missing (assume it is an attachment)
+- #00: added findbugs support internally
+
+
+v3.0.1 (29-Feb-2016)
+
+- #31: Fixed EmailAddressCriteria.DEFAULT and clarified Javadoc
+
+
+v3.0.0 (26-Feb-2016)
+
+- #30: Improved the demonstration class to include attachments and embedded images
+- #29: The package has been restructured for future maintenance, breaking backwards compatibility
+- #28: Re-added improved email validation facility
+- #22: Added conversion to and from MimeMessage. You can now consume and produce MimeMessage objects with simple-java-mail
+
+
+v2.5.1 (19-Jan-2016)
+
+- #25: Added finally clausule that will always close socket properly in case of an exception
+
+
+v2.5 (19-Jan-2016)
+
+- #24: Updated dependencies SLF4J to 1.7.13 and switched to the updated javax mail package com.sun.mail:javax.mail 1.5.5
+
+
+v2.4 (12-Aug-2015)
+
+- #21: Builder API uses CC and BCC recipient types incorrectly
+
+
+v2.3 (21-Jul-2015)
+
+- #19: supporting custom Session Properties now and emergency access to internal Session object.
+
+
+v2.2 (09-May-2015)
+
+- #3: turned off email regex validation by default, with the option to turn it back on
+- #7: fixed NullPointerException when using your own Session instance
+- #10: properly UTF-8 encode recipient addresses
+- #14: switched to SLF4J, so you can easily use your own selected logging framework
+- #17: Added fluent interface for building emails
+
+
+v2.1 (09-Aug-2012)
+
+- fixed character encoding for reply-to, from, to, body text and headers (to UTF-8)
+- fixed bug where Recipient was not public resulting in uncompilable code when calling email.getRecipients()
+
+
+v2.0 (20-Aug-2011)
+
+- added support for open headers (such as X-Priority)
+
+
+v1.9.1 (08-Aug-2011)
+
+- updated for Maven support (library hasn't changed, but 1.9 was released incorrectly to Maven Central)
+
+
+v1.9 (6-Aug-2011)
+
+- added support for JavaMail's reply-to address
+- made port optional as to support port defaulting based on protocol
+- added transport strategy default in the createSession method
+- tightened up thrown exceptions (MailException instead of RuntimeException)
+- added and fixed JavaDoc
+
+
+v1.8
+
+Added support for TLS (tested with gmail)
+
+
+v1.7 (22-Mar-2011)
+
+Added support for SSL! (tested with gmail)
+
+- improved argument validation when creating a Mailer without preconfigured Session instance
+
+know possible issue: SSL self-signed certificates might not work (yet). Please let me know by e-mail or create a new issue
+
+
+v1.6
+
+Completed migration to Java Simple Mail project.
+
+- removed all Vesijama references
+- updated TestMail demonstration class for clarification
+- updated readme.txt for test run instructions
+- included log4j.properties
+
+
+v1.4 (15-Jan-2011)
+
+
+vX.X (26-Apr-2009)
+
+- Initial upload to Google Code.
diff --git a/RELEASE_HISTORY.md b/RELEASE_HISTORY.md
new file mode 100644
index 000000000..86d6f6769
--- /dev/null
+++ b/RELEASE_HISTORY.md
@@ -0,0 +1,858 @@
+# Release History
+
+Full Simple Java Mail release history. [README.md](README.md#latest-progress) also mirrors recent progress for quick scanning.
+
+[v9.1.0](https://github.com/bbottema/simple-java-mail/releases/tag/9.1.0) - [v9.1.3](https://github.com/bbottema/simple-java-mail/releases/tag/9.1.3) - [Maven Central](https://repo1.maven.org/maven2/org/simplejavamail/simple-java-mail/9.1.3/)
+
+- **v9.1.3:** [#668](https://github.com/bbottema/simple-java-mail/issues/668): **New Outlook inline images:** updated `outlook-message-parser` to 1.16.2 so native-HTML-only `.msg` files match inline `cid:` images correctly and trailing NUL terminators no longer leak into attachment metadata.
+- **v9.1.2:** **Dependency and Java 8-compatible build-tool maintenance:** updated JMail to 2.2.0 ([#663](https://github.com/bbottema/simple-java-mail/pull/663)), Zip4j to 2.11.6 ([#666](https://github.com/bbottema/simple-java-mail/pull/666)), Exec Maven Plugin to 3.6.3 ([#664](https://github.com/bbottema/simple-java-mail/pull/664)), Maven Enforcer Plugin to 3.6.3 ([#665](https://github.com/bbottema/simple-java-mail/pull/665)), and Maven JAR Plugin to 3.5.1 ([#667](https://github.com/bbottema/simple-java-mail/pull/667)).
+- **v9.1.1:** **Java 8 build-tool maintenance** ([#662](https://github.com/bbottema/simple-java-mail/pull/662)): updated annotations and Maven compiler, JAR, OSGi bundle, and Karaf tooling to Java 8-compatible versions, with Dependabot guards against newer-Java-only upgrade lines.
+- **v9.1.0:** [#653](https://github.com/bbottema/simple-java-mail/issues/653): a configurable SMTP client hostname for the `EHLO` / `HELO` command.
+- **v9.1.0:** [#654](https://github.com/bbottema/simple-java-mail/issues/654): SMTP submission receipts for reading the server acceptance response after a send.
+- **v9.1.0:** No breaking changes; existing `sendMail(...)` behavior is unchanged.
+
+
+[v9.0.0](https://github.com/bbottema/simple-java-mail/releases/tag/9.0.0) - [v9.0.4](https://github.com/bbottema/simple-java-mail/releases/tag/9.0.4) - [Maven Central](https://repo1.maven.org/maven2/org/simplejavamail/simple-java-mail/9.0.4/)
+
+#### The Short Version ####
+
+**Simple Java Mail has been going strong-ish for about 20 years**, and **9.0.0** rolls *roughly two years of backlog* into a new major release.
+
+```
+simple-java-mail
+└── outlook-message-parser
+ └── rtf-to-html
+└── java-utils-mail-dkim
+└── java-utils-mail-smime
+└── smtp-connection-pool
+ └── clustered-object-pool
+ └── generic-object-pool
+└── java-socks-proxy-server
+```
+
+Across Simple Java Mail and the supporting libraries that keep the stack moving, **more than 100 GitHub issues and PRs** were reviewed, fixed, merged, or closed while keeping the project **Java 8-compatible**.
+
+**Major features:** the dedicated recipient builder API, per-recipient S/MIME certificates, first-class Delivery Status Notification support, pre-encoded attachment and embedded-image sending, mailer-level DKIM defaults, and simple batch/open-connection sending without the batch module.
+**Enhancements:** broader Outlook conversion metadata, MIME resource handling, content-transfer encoding control, debug routing, local SMTP bind configuration, batch cluster configuration, and Java module support.
+
+#### Migration Note ####
+
+**This is a breaking major release.** The old recipient-addition method jungle has been cleaned up in favor of the **recipient builder API**, so code that relied on the removed recipient overloads needs to migrate. Start with the [9.0 migration notes](https://www.simplejavamail.org/migration-notes-9.0.0.html) before upgrading.
+
+#### Major Features ####
+
+- **v9.0.0:** [#613](https://github.com/bbottema/simple-java-mail/issues/613): **Recipient builder API:** added dedicated builders for constructing single recipients and recipient collections.
+- **v9.0.0:** [#297](https://github.com/bbottema/simple-java-mail/issues/297): **Per-recipient S/MIME certificates:** enabled encrypted mail for multiple recipients with different certificates.
+- **v9.0.0:** [#574](https://github.com/bbottema/simple-java-mail/issues/574): **Delivery Status Notification (DSN):** added first-class DSN configuration.
+- **v9.0.0:** [#573](https://github.com/bbottema/simple-java-mail/issues/573): **Pre-encoded resources:** added pre-encoded attachment and embedded-image APIs.
+- **v9.0.0:** [#196](https://github.com/bbottema/simple-java-mail/issues/196): **Mailer-level DKIM defaults:** added default DKIM signing configuration so DKIM can be configured once per `Mailer`.
+- **v9.0.0:** [#569](https://github.com/bbottema/simple-java-mail/issues/569): **Simple batch and open-connection sending:** added `sendMailsInSimpleBatch(...)` for sequential batch work without the batch module and `withOpenConnection(...)` for callback-scoped reuse of a single SMTP connection.
+
+#### Enhancements ####
+
+- **v9.0.2:** [#645](https://github.com/bbottema/simple-java-mail/issues/645): **Outlook last-modifier metadata:** exposed `PR_LAST_MODIFIER_NAME` / `0x3FFA` as `OutlookMessageData#getLastModifierName()` without treating it as sender identity.
+- **v9.0.0:** [#614](https://github.com/bbottema/simple-java-mail/issues/614): **Outlook conversion metadata:** added explicit result APIs for inspecting source `.msg` headers and metadata without copying structural headers into converted emails, resolving [#609](https://github.com/bbottema/simple-java-mail/issues/609).
+- **v9.0.0:** [#605](https://github.com/bbottema/simple-java-mail/issues/605): **Per-body content-transfer encoding:** added `Content-Transfer-Encoding` configuration for plain text, HTML, and calendar content.
+- **v9.0.0:** [#566](https://github.com/bbottema/simple-java-mail/issues/566), [#597](https://github.com/bbottema/simple-java-mail/issues/597), [#602](https://github.com/bbottema/simple-java-mail/issues/602), [#607](https://github.com/bbottema/simple-java-mail/issues/607): **MIME resource `Content-ID` handling:** improved explicit IDs, parsed embedded images, and generated fallback IDs.
+- **v9.0.0:** [#589](https://github.com/bbottema/simple-java-mail/issues/589): **Jakarta Mail debug output:** added configurable debug output routing.
+- **v9.0.0:** [#568](https://github.com/bbottema/simple-java-mail/issues/568): **Local SMTP bind address:** added configuration for multi-IP SMTP hosts.
+- **v9.0.0:** [#565](https://github.com/bbottema/simple-java-mail/issues/565), [#618](https://github.com/bbottema/simple-java-mail/issues/618): **Batch cluster configuration:** fixed Java API cluster configuration and added property-defined cluster configurations for property-file and Spring-configured clustered sending.
+- **v9.0.0:** [#572](https://github.com/bbottema/simple-java-mail/issues/572), [#571](https://github.com/bbottema/simple-java-mail/issues/571): **S/MIME conversion leniency:** tolerate unsupported S/MIME payloads during Outlook conversion and preserve parsed email content when signature verification fails.
+- **v9.0.0:** [#606](https://github.com/bbottema/simple-java-mail/issues/606): **MIME type sanitizing:** sanitize malformed resource MIME types before generating attachment and embedded-image headers.
+- **v9.0.0:** [#541](https://github.com/bbottema/simple-java-mail/issues/541): **Resource headers:** removed the non-standard `filename` parameter from resource `Content-Type` headers; filenames remain available through `Content-Disposition`.
+- **v9.0.0:** [#265](https://github.com/bbottema/simple-java-mail/issues/265), [#237](https://github.com/bbottema/simple-java-mail/issues/237): **Java module support:** added Java 9 module descriptors to the core and facade jars so modular applications can require `org.simplejavamail` directly.
+
+#### Fixes and Compatibility ####
+
+- **v9.0.4:** [#652](https://github.com/bbottema/simple-java-mail/issues/652): **RFC 2047 address validation:** reject encoded-word syntax inside address specs during validation while keeping encoded display names valid.
+- **v9.0.3:** [#651](https://github.com/bbottema/simple-java-mail/issues/651): **Outlook plain-text RTF rendering:** preserved line breaks without exposing browser-default `
` styling in converted HTML.
+- **v9.0.0:** [#615](https://github.com/bbottema/simple-java-mail/issues/615): **Async test connections:** fixed `MailerGenericBuilder.async()` so no-arg `testConnection()` uses the configured async default.
+- **v9.0.0:** [#611](https://github.com/bbottema/simple-java-mail/issues/611): **SMTPS custom SSL socket factories:** fixed custom SSL socket factory configuration for SMTPS mailers.
+- **v9.0.0:** [#535](https://github.com/bbottema/simple-java-mail/issues/535): **Async failure reporting:** let async send and connection-test failures surface through the returned `CompletableFuture` without duplicate framework error logs.
+- **v9.0.0:** [#583](https://github.com/bbottema/simple-java-mail/issues/583): **Java 25 CLI startup:** fixed CLI startup on Java 25.
+- **v9.0.0:** [#616](https://github.com/bbottema/simple-java-mail/issues/616): **CLI optional-argument detection:** removed the runtime JetBrains annotation fork from CLI optional-argument detection.
+- **v9.0.0:** **Standalone CLI command cleanup:** `send`, `connect`, and `validate` now wait for command work and close mailer resources, preventing batch-module resources from keeping the process alive.
+
+#### Dependency and Supporting-Library Updates ####
+
+- **v9.0.3:** **Angus runtime alignment:** bumped Angus Mail to 2.0.5 and added Angus Activation 2.0.3.
+- **v9.0.3:** **Logging dependencies:** bumped Log4j from 2.25.4 to 2.26.1.
+- **v9.0.2:** **Jakarta API alignment:** bumped Jakarta Mail API to 2.1.5 and Jakarta Activation API to 2.1.4.
+- **v9.0.0:** **Core dependency maintenance:** bumped JMail to 2.1.0 ([#634](https://github.com/bbottema/simple-java-mail/pull/634)), commons-io to 2.22.0 ([#579](https://github.com/bbottema/simple-java-mail/pull/579), [#627](https://github.com/bbottema/simple-java-mail/pull/627)), Kryo to 5.6.2 ([#586](https://github.com/bbottema/simple-java-mail/pull/586)), Zip4j to 2.11.5 ([#587](https://github.com/bbottema/simple-java-mail/pull/587)), SubEthaSMTP to 7.2.2 ([#593](https://github.com/bbottema/simple-java-mail/pull/593), [#632](https://github.com/bbottema/simple-java-mail/pull/632)), Angus Mail to 2.0.4 ([#604](https://github.com/bbottema/simple-java-mail/pull/604)), Objenesis to 3.5 ([#580](https://github.com/bbottema/simple-java-mail/pull/580), [#635](https://github.com/bbottema/simple-java-mail/pull/635)), Lombok to 1.18.46 ([#636](https://github.com/bbottema/simple-java-mail/pull/636)), AssertJ Core to 3.27.7 ([#622](https://github.com/bbottema/simple-java-mail/pull/622)), and SpotBugs annotations to 4.10.2 ([#629](https://github.com/bbottema/simple-java-mail/pull/629)).
+- **v9.0.0:** **Logging dependencies:** aligned Log4j to 2.25.4 ([#624](https://github.com/bbottema/simple-java-mail/pull/624)) and SLF4J API to 2.0.18 ([#631](https://github.com/bbottema/simple-java-mail/pull/631)), keeping the Log4j bridge on `log4j-slf4j2-impl` for SLF4J 2.x.
+
+##### Supporting Libraries #####
+
+- **v9.0.3:** **`outlook-message-parser` 1.16.1 / `rtf-to-html` 2.0.2:** fixed browser-default `
` styling in Outlook plain-text RTF conversion ([#651](https://github.com/bbottema/simple-java-mail/issues/651)).
+- **v9.0.2:** **`outlook-message-parser` 1.16.0:** added source last-modifier metadata used by `OutlookMessageData#getLastModifierName()`.
+- **v9.0.0:** **`utils-mail-dkim` 3.3.0:** added configurable DNS provider URL support for DKIM domain-key TXT lookups, fixed the published automatic module name, and kept packaged artifacts free of JaCoCo probes.
+- **v9.0.0:** **`clustered-object-pool` 4.0.1** ([#6](https://github.com/bbottema/clustered-object-pool/issues/6)): added cluster-specific Java configuration for pool defaults, claim timeout, and load balancing.
+- **v9.0.0:** **`smtp-connection-pool` 3.0.1** ([#8](https://github.com/simple-java-mail/smtp-connection-pool/issues/8)): pulled in `clustered-object-pool` 4.0.1 so the batch-module fix for [#565](https://github.com/bbottema/simple-java-mail/issues/565) can keep connection-pool defaults per cluster key.
+- **v9.0.0:** **`smtp-connection-pool` 3.0.0:** made clustered SMTP pools generic over their cluster-key type and kept already-unusable connections from surfacing as generic pool error logs during transport close.
+- **v9.0.0:** **`java-socks-proxy-server` 4.2.0:** updated SOCKS live tests to use dynamic proxy ports instead of fixed ports.
+- **v9.0.0:** **`outlook-message-parser` 1.15.0:** improved Outlook `.msg` conversion by preserving nested message attachment metadata, fixing sent-date extraction ([#534](https://github.com/bbottema/simple-java-mail/issues/534)), fixing recipient bucket parsing ([#504](https://github.com/bbottema/simple-java-mail/issues/504)), broadening S/MIME detection, improving RTF-only body conversion ([#576](https://github.com/bbottema/simple-java-mail/issues/576)), and updating Apache POI.
+
+##### Build and Test Maintenance #####
+
+- **v9.0.3:** **Build maintenance:** bumped Maven Source Plugin to 3.4.0, NotNull Instrumenter Maven Plugin to 1.1.1, and Mycila License Maven Plugin to 4.6.
+- **v9.0.2:** **Build maintenance:** bumped Maven Assembly Plugin to 3.8.0 and Nexus Staging Maven Plugin to 1.7.0, and extended Dependabot guards for Java 11-only plugin lines.
+- **v9.0.1:** **Release packaging:** restored generated license headers in published source JARs and enabled publication of the standalone CLI ZIP and TAR classifier artifacts.
+- **v9.0.0:** **Build plugins and test stack:** bumped Maven Surefire Plugin to 3.5.6 ([#592](https://github.com/bbottema/simple-java-mail/pull/592), [#625](https://github.com/bbottema/simple-java-mail/pull/625)), Maven Clean Plugin to 3.5.0 ([#626](https://github.com/bbottema/simple-java-mail/pull/626)), Appassembler Maven Plugin to 2.1.0 ([#581](https://github.com/bbottema/simple-java-mail/pull/581)), Exec Maven Plugin to 3.5.0 ([#582](https://github.com/bbottema/simple-java-mail/pull/582)), Maven Deploy Plugin to 3.1.4 ([#619](https://github.com/bbottema/simple-java-mail/pull/619)), Maven Install Plugin to 3.1.4 ([#639](https://github.com/bbottema/simple-java-mail/pull/639)), Maven Javadoc Plugin to 3.12.0 ([#637](https://github.com/bbottema/simple-java-mail/pull/637)), Maven GPG Plugin to 3.2.8 ([#621](https://github.com/bbottema/simple-java-mail/pull/621)), and JaCoCo Maven Plugin to 0.8.15 ([#638](https://github.com/bbottema/simple-java-mail/pull/638)); aligned JUnit Platform/Jupiter at 1.14.4/5.14.4 while preserving Java 8 compatibility ([#596](https://github.com/bbottema/simple-java-mail/pull/596), [#633](https://github.com/bbottema/simple-java-mail/pull/633)); kept JUnit Pioneer on 1.9.1 because 2.x is Java 11 bytecode ([#630](https://github.com/bbottema/simple-java-mail/pull/630)); added Java 8 Dependabot guards; and replaced live embedded-image URL tests with deterministic local coverage ([#617](https://github.com/bbottema/simple-java-mail/issues/617)).
+
+
+v8.12.0 - [v8.12.6](https://repo1.maven.org/maven2/org/simplejavamail/simple-java-mail/8.12.6/)
+
+- v8.12.6 (18-April-2025): [#595](https://github.com/bbottema/simple-java-mail/issues/595): [bug] Spring configuration - fix support for simplejavamail.extraproperties
+- v8.12.5 (05-March-2025): Bumped PATCH versions of various dependencies ([#553](https://github.com/bbottema/simple-java-mail/issues/553), [#554](https://github.com/bbottema/simple-java-mail/issues/554), [#555](https://github.com/bbottema/simple-java-mail/issues/555), [#562](https://github.com/bbottema/simple-java-mail/issues/562), [#567](https://github.com/bbottema/simple-java-mail/issues/567))
+- v8.12.4 (12-December-2024): [#558](https://github.com/bbottema/simple-java-mail/issues/558): [bug] Mailer.close() exception because it attempts to shutdown batch-module connection pools, even if not available on the classpath
+- v8.12.3 (25-November-2024): [#563](https://github.com/bbottema/simple-java-mail/issues/563): [enhancement] Add getter for Authenticated SOCKS server port
+- v8.12.2 (05-October-2024): [#552](https://github.com/bbottema/simple-java-mail/issues/552): [bug] support iCalendar events with METHOD defined in body instead of Content-Type
+- v8.12.1 (02-October-2024): [#533](https://github.com/bbottema/simple-java-mail/issues/533): [maintenance] Bump com.github.therapi:therapi-runtime-javadoc-scribe from 0.13.0 to 0.15.0
+- v8.12.1 (02-October-2024): [#532](https://github.com/bbottema/simple-java-mail/issues/532): [maintenance] Bump com.sanctionco.jmail:jmail from 1.4.1 to 1.6.3
+- v8.12.1 (02-October-2024): [#531](https://github.com/bbottema/simple-java-mail/issues/531): [maintenance] Bump com.github.bbottema:java-socks-proxy-server from 4.0.0 to 4.1.2
+- v8.12.1 (02-October-2024): [#528](https://github.com/bbottema/simple-java-mail/issues/528): [maintenance] Bump com.github.davidmoten:subethasmtp from 7.0.1 to 7.1.1
+- v8.12.1 (02-October-2024): [#522](https://github.com/bbottema/simple-java-mail/issues/522): [maintenance] Bump jakarta.annotation:jakarta.annotation-api from 1.3.5 to 3.0.0
+- v8.12.0 (26-September-2024): [#550](https://github.com/bbottema/simple-java-mail/issues/550): [bug] Environment variables are not being loaded properly
+- v8.12.0 (26-September-2024): [#538](https://github.com/bbottema/simple-java-mail/issues/538): [bug] System properties are only read if configuration file exists in class path
+- v8.12.0 (26-September-2024): [#546](https://github.com/bbottema/simple-java-mail/issues/546): [Enhancement] Trim whitespace in encoder values for Content-Encoding
+
+
+v8.11.0 - [v8.11.3](https://repo1.maven.org/maven2/org/simplejavamail/simple-java-mail/8.11.3/)
+
+- v8.11.3 (15-September-2024): [#543](https://github.com/bbottema/simple-java-mail/issues/543): [Enhancement] reduce log spam from the batch-module
+- v8.11.2 (08-June-2024): [#530](https://github.com/bbottema/simple-java-mail/pull/530): [Bug] After converting Outlook .msg to EML, bullet lists have duplicate numbering HTML converted from RTF
+- v8.11.1 (28-May-2024): [#529](https://github.com/bbottema/simple-java-mail/pull/529): Bump smtp-connection-pool from 2.3.2 to 2.3.3 which improves performance and fixes a rare ConcurrentModificationException
+- v8.11.1 (28-May-2024): [#527](https://github.com/bbottema/simple-java-mail/pull/527): Bump org.slf4j:slf4j-api from 2.0.9 to 2.0.13
+- v8.11.1 (28-May-2024): [#523](https://github.com/bbottema/simple-java-mail/pull/523): Bump org.jacoco:jacoco-maven-plugin from 0.8.5 to 0.8.12
+- v8.11.0 (25-May-2024): [#526](https://github.com/bbottema/simple-java-mail/pull/526): When reading .msg files the RTF converted to HTML is garbled in some cases where the appropriate charset is not detected properly
+
+NOTE: v8.11.0 contains many (minor) dependency updates to resolve CVE issues, including:
+ - parent POM upgrade: Upgrades test dependencies as well as SLF4J versions
+ - outlook-message-parser 1.13.2 -> 1.14.0
+ - java-reflection 4.0.1 -> 4.0.2
+ - smtp-connection-pool 2.3.1 -> 2.3.2
+ - utils-mail-dkim 3.1.0 -> 3.2.0
+ - jakarta.mail-api 2.1.2 -> 2.1.3
+ - angus-mail 2.0.2 -> 2.0.3
+ - therapi-runtime-javadoc 0.13.0 -> 0.15.0
+ - kryo 5.0.0-RC1 -> 5.6.0
+ - maven-assembly-plugin 3.1.0 -> 3.7.1 (only for the CLI module during build)
+
+
+v8.10.0 - [v8.10.1](https://repo1.maven.org/maven2/org/simplejavamail/simple-java-mail/8.10.1/)
+
+- v8.10.1 (04-May-2024): [#510](https://github.com/bbottema/simple-java-mail/pull/510): Update upstream dependency generic-object-pool, which solves a critical bug when there are exceptions during allocation
+- v8.10.0 (30-April-2024): [#508](https://github.com/bbottema/simple-java-mail/pull/508): [enhancement+bug] Make EmailConverter API more consistent regarding Session parameter, don't use `Session.getDefaultInstance` anymore and fix bug where `emlToEmailBuilder` used `emlToMimeMessage`
+
+
+[v8.9.0](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C8.9.0%7Cjar) (26-April-2024)
+
+- [#507](https://github.com/bbottema/simple-java-mail/issues/507): [security] Update 3rd party dependencies to get rid of all currently known CVE issues (see issue for details)
+
+
+v8.8.0 - [v8.8.4](https://repo1.maven.org/maven2/org/simplejavamail/simple-java-mail/8.8.4/)
+
+- v8.8.4 (23-April-2024): [#506](https://github.com/bbottema/simple-java-mail/pull/506): [CVE] Upgrade utils-mail-smime dependency to 2.3.2, to resolve CVE issue in bouncycastle
+- v8.8.3 (13-April-2024): [#502](https://github.com/bbottema/simple-java-mail/issues/502): [Bug] Message headers not treated with case insensitivity as per RFC, causing deviating headers to slip through the filters
+- v8.8.2 (05-April-2024): [#495](https://github.com/bbottema/simple-java-mail/issues/495): Add config support for 'verifyingServerIdentity' with SMTP, also: since Angus 1.1.0 (8.6.0) server identity checks are on by default and can be countered by mailerBuilder.verifyingServerIdentity(false)
+- v8.8.2 (05-April-2024): [#501](https://github.com/bbottema/simple-java-mail/issues/501): [dependency] Update outlook-message-parser dependency, which has improved support for X500 addresses
+- v8.8.2 (05-April-2024): [#499 (fix)](https://github.com/bbottema/simple-java-mail/issues/499): [maintenance] Added missing finer-grained DKIM Spring Boot properties
+- v8.8.1 (04-April-2024): [#500](https://github.com/bbottema/simple-java-mail/issues/500): [bug] Fix parsing addresses from headers in EML files, like a Disposition-Notification-To with umlaut
+- v8.8.0 (22-March-2024): [#499](https://github.com/bbottema/simple-java-mail/issues/499): [Enhancement] Expose finer-grained DKIM configuration through the builder api and disable 'l-param' by default)
+
+NOTE: release 8.8.0 changes the default for DKIM signing from 'l-param' true to false. If you rely on this feature, you need to enable it explicitly. Refer to the [DKIM documentation](https://www.simplejavamail.org/security.html#section-sending-dkim) for the update.
+
+
+v8.7.0 - [v8.7.1](https://repo1.maven.org/maven2/org/simplejavamail/simple-java-mail/8.7.1/)
+
+- v8.7.1 (20-March-2024): [#498](https://github.com/bbottema/simple-java-mail/issues/498): Make S/MIME algorithms configurable (signature algorithm for signing, key encapsulation and cipher algorithms for encryption)
+- v8.7.1 (20-March-2024): [#497](https://github.com/bbottema/simple-java-mail/issues/497): Order of attachments is lost when converting a MimeMessage to an Email
+- v8.7.0 (20-March-2024): don't use this version: versioning messed up
+
+NOTE: this breaks the API for S/MIME related builder methods. Refer to the [S/MIME documentation](https://www.simplejavamail.org/security.html#section-sending-smime) for the new API.
+
+
+v8.6.0 - [v8.6.3](https://repo1.maven.org/maven2/org/simplejavamail/simple-java-mail/8.6.3/)
+
+- v8.6.3 (13-February-2024): [#491](https://github.com/bbottema/simple-java-mail/issues/491): [bug] Attachment body parts should separately parse Content-Disposition and ContentID, possible resulting in a downloadable attachment that is also embedded
+- v8.6.2 (27-January-2024): [#493](https://github.com/bbottema/simple-java-mail/issues/493): [bug] don't require smime-module when adding collection of headers (also used when copying email)
+- v8.6.1 (18-January-2024): [#487](https://github.com/bbottema/simple-java-mail/issues/487): Move header filtering from MimeMessageParser to EmailConverter, thereby enabling access to all parsed headers when using MimeMessageParser directly
+- v8.6.1 (18-January-2024): [#489](https://github.com/bbottema/simple-java-mail/issues/489): Finished update to Angus Mail by updating activation dependency
+- v8.6.0 (17-January-2024): [#489](https://github.com/bbottema/simple-java-mail/issues/489): Update to Angus Mail
+
+NOTE: this release switches to Angus Mail which should be a transparent change, but if you encounter any issues, please report them.
+ One known issue is that Angus, since 1.1.0, performs server identity checks by default, which was previously disabled for SMTP. If you encounter issues with this, you can disable it with `mailerBuilder.verifyingServerIdentity(false)` and starting from 8.8.2, this also works with SMTP transport strategy (see [#495](https://github.com/bbottema/simple-java-mail/issues/495)).
+
+
+v8.5.0 - [v8.5.1](https://repo1.maven.org/maven2/org/simplejavamail/simple-java-mail/8.5.1/)
+
+- v8.5.1 (15-December-2023): [#486](https://github.com/bbottema/simple-java-mail/issues/486): [dependency] Handle Outlook's Non-Standard S/MIME Signed Messages
+- v8.5.0 (13-December-2023): [#484](https://github.com/bbottema/simple-java-mail/issues/484): [bug] Addresses passed as string are not always interpreted correctly
+
+
+[v8.4.0](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C8.4.0%7Cjar) (12-December-2023)
+
+- [#483](https://github.com/bbottema/simple-java-mail/issues/483): Enhancement: add native support for overriding envelope-level receiver(s)
+
+
+v8.3.0 - [v8.3.5](https://repo1.maven.org/maven2/org/simplejavamail/simple-java-mail/8.3.5/)
+
+- v8.3.5 (10-December-2023): [#482](https://github.com/bbottema/simple-java-mail/issues/482) Bug: 'IllegalArgumentException: emailAddressList is required' when parsing mail with incorrect recipients from Outlook message
+- v8.3.4 (08-December-2023): [#481](https://github.com/bbottema/simple-java-mail/issues/481) Enhancement: don't crash on invalid empty embedded images when parsing Outlook messages
+- v8.3.3 (03-December-2023): [#477](https://github.com/bbottema/simple-java-mail/issues/477) Enhancement: Support Exchange proprietary addresses (X.500 DAP)
+- v8.3.2 (26-November-2023): [#480](https://github.com/bbottema/simple-java-mail/issues/480) Bug: Multiple attachments with same name get the same Content-ID, causing them to refer to the same file content
+- v8.3.1 (09-October-2023): [#440](https://github.com/bbottema/simple-java-mail/issues/440) Bug: names manually specified for embedded images are overridden and have extension added, breaking cid: references in HTML body
+- v8.3.0 (09-October-2023): [#475](https://github.com/bbottema/simple-java-mail/issues/475) Enhancement: Add configuration metadata for Spring Boot application properties
+
+
+[v8.2.0](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C8.2.0%7Cjar) (02-October-2023)
+
+- [#473](https://github.com/bbottema/simple-java-mail/issues/473) Bugfix: Add missing support for multiple reply-to addresses
+
+
+v8.1.0 - [v8.1.3](https://repo1.maven.org/maven2/org/simplejavamail/simple-java-mail/8.1.3/)
+
+- v8.1.3 (14-July-2023): [#467](https://github.com/bbottema/simple-java-mail/issues/467) Security: Medium severity vulnerability is detected in org.bouncycastle transitive dependency
+- v8.1.3 (14-July-2023): [#466](https://github.com/bbottema/simple-java-mail/issues/466) Maintenance: Let Mailer implement AutoCloseable, so it shuts down the connection pool automatically when disposed of by Spring
+- v8.1.2 (23-June-2023): [#465](https://github.com/bbottema/simple-java-mail/issues/465) Regression bug #461: Simple Java Mail always requires DKIM/SMIME modules
+- v8.1.1 (07-June-2023): [#461](https://github.com/bbottema/simple-java-mail/issues/461) Bugfix: Fixed MessageID not preserved when signing/encrypting with S/MIME and/or DKIM
+- v8.1.0 (15-April-2023): [#458](https://github.com/bbottema/simple-java-mail/pull/458) Missing osgi headers (#288) and added support for Apache Karaf
+- v8.1.0 (15-April-2023): [#288](https://github.com/bbottema/simple-java-mail/issues/288) Maintenance: missing OSGI package-exports from core-module
+
+
+v8.0.0 - [v8.0.1](https://repo1.maven.org/maven2/org/simplejavamail/simple-java-mail/8.0.1/)
+
+- v8.0.1 (30-April-2023): [#456](https://github.com/bbottema/simple-java-mail/issues/456): Enhancement: make Content-Transfer encoder detection more lenient, supporting more values from the wild
+- v8.0.0 (08-March-2023): [#451](https://github.com/bbottema/simple-java-mail/issues/451): Feature: Make defaults and overrides a first class feature
+- v8.0.0 (08-March-2023): [#452](https://github.com/bbottema/simple-java-mail/issues/452): Enhancement: with ".disableAllClientValidation(true)", also ignore errors from the completeness check
+- v8.0.0 (08-March-2023): [#450](https://github.com/bbottema/simple-java-mail/issues/450): Bug: when using dispositionNotificationTo or returnReceiptTo mode, when the corresponding emails are not filled, it fails even though it should fall back to replyTo or From
+- v8.0.0 (08-March-2023): [#449](https://github.com/bbottema/simple-java-mail/issues/449): Bug: IllegalArgumentException on parsing empty header name and value (when parsing Outlook message)
+- v8.0.0 (08-March-2023): [#448](https://github.com/bbottema/simple-java-mail/issues/448): Bug: withEmailDefaults and withEmailOverrides does not work with CustomMailer
+- v8.0.0 (08-March-2023): [#447](https://github.com/bbottema/simple-java-mail/issues/447): Enhancement: allow defaults/overrides to ignore individual fields (turn off for specific properties)
+- v8.0.0 (08-March-2023): [#446](https://github.com/bbottema/simple-java-mail/issues/446): Enhancement: add missing defaults properties for DKIM
+
+**This release changes how Email instances are built, or more specifically, when defaults and overrides are applied.
+There are now overloaded build methods that provide similar behaviour as previous versions.**
+
+
+v7.9.0 - [v7.9.1](https://repo1.maven.org/maven2/org/simplejavamail/simple-java-mail/7.9.1/)
+
+- v7.9.1 (22-February-2023): [#444](https://github.com/bbottema/simple-java-mail/issues/444) Bugfix: encoded delimited recipients in EML not parsed properly
+- v7.9.0 (21-February-2023): [#344](https://github.com/bbottema/simple-java-mail/issues/344) Enhancement: make DKIM signing more flexible by allowing header exclusions in DKIM signature
+
+
+v7.8.0 - [v7.8.3](https://repo1.maven.org/maven2/org/simplejavamail/simple-java-mail/7.8.3/)
+
+- v7.8.3 (21-February-2023): [#293](https://github.com/bbottema/simple-java-mail/issues/293) Bugfix: Decoding missing in a few placed when parsing MimeMessage or sending an Email
+- v7.8.2 (09-February-2023): [#442](https://github.com/bbottema/simple-java-mail/issues/442) Enhancement: Simple Java Mail should throw an exception when trying to utilize S/MIME with smime-module on the classpath
+- v7.8.1 (01-February-2023): [#438](https://github.com/bbottema/simple-java-mail/issues/438) Bug: properly Fail-Fast in case of Transport claim timeout in the batch-module, rather than running into NPE further down the line
+- v7.8.0 (24-January-2023): [#436](https://github.com/bbottema/simple-java-mail/issues/436) Enhancement: add mailerBuilder.withTransportModeLoggingOnly() as mailer API entry point
+- v7.8.0 (24-January-2023): [#435](https://github.com/bbottema/simple-java-mail/issues/435) Enhancement: SMTP server config should be optional in case a CustomMailer is used
+- v7.8.0 (24-January-2023): [#427](https://github.com/bbottema/simple-java-mail/issues/427) Feature: set a maximum email size on Mailer level which throws EmailToBig exception when exceeded
+
+
+v7.7.0 - [v7.7.1](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C7.7.1%7Cjar)
+
+- v7.7.1 (18-January-2023): [#434](https://github.com/bbottema/simple-java-mail/issues/434) Regression bug in #430: Email parameter missing in CustomMailer interface
+- v7.7.0 (17-January-2023): [#430](https://github.com/bbottema/simple-java-mail/issues/430) Enhancement: auto-reconnect (if needed) when reclaiming a Transport connection from the SMTP connection
+- v7.7.0 (17-January-2023): [#383](https://github.com/bbottema/simple-java-mail/issues/383) Feature: be able to set defaults and overrides on the Mailer level, rather than email or global level
+
+7.7.0 moves the conversion of Email to MimeMessage to after a Transport instance has been selected (in case of a cluster of SMTP servers),
+so we can apply defaults/overrides on the Mailer level, meaning you can configure 'global' values for individual SMTP servers
+(like a fixed FROM per server).
+
+
+[v7.6.0](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C7.6.0%7Cjar) (05-January-2023)
+
+- [#421](https://github.com/bbottema/simple-java-mail/issues/421) Enhancement: Add support for OAUTH2 authentication
+
+
+v7.5.0 - [v7.5.2](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C7.5.2%7Cjar)
+
+- v7.5.2 (25-December-2022): [#429](https://github.com/bbottema/simple-java-mail/issues/429) Bug: wrong username property used when password authentication is not needed
+- v7.5.1 (12-December-2022): [#416](https://github.com/bbottema/simple-java-mail/issues/416) Bug: Support encoder names regardless of their case ("base64" is the same as "BASE64")
+- v7.5.1 (12-December-2022): [#424](https://github.com/bbottema/simple-java-mail/issues/424) Maintenance: bump JMail dependency from 1.2.1 to 1.4.1
+- v7.5.0 (28-July-2022): [#411](https://github.com/bbottema/simple-java-mail/issues/411) Enhancement: expose validation sub steps in the MailerHelper class for the completeness check, CRLF inject scans and address validations
+- v7.5.0 (28-July-2022): [#410](https://github.com/bbottema/simple-java-mail/issues/410) Bug: CRLF injection scan missing for dispositionNotificationTo and returnReceiptTo
+- v7.5.0 (28-July-2022): [#390](https://github.com/bbottema/simple-java-mail/issues/390) Enhancement: make client sided validation optional, turning off address validation and CRLF injection detection
+
+
+[v7.5.1](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C7.5.1%7Cjar) (12-December-2022)
+
+- [#416](https://github.com/bbottema/simple-java-mail/issues/416) Bug: Support encoder names regardless of their case ("base64" is the same as "BASE64")
+- [#424](https://github.com/bbottema/simple-java-mail/issues/424) Maintenance: bump JMail dependency from 1.2.1 to 1.4.1
+
+
+[v7.5.0](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C7.5.0%7Cjar) (28-July-2022)
+
+- [#411](https://github.com/bbottema/simple-java-mail/issues/411) Enhancement: expose validation sub steps in the MailerHelper class for the completeness check, CRLF inject scans and address validations
+- [#410](https://github.com/bbottema/simple-java-mail/issues/410) Bug: CRLF injection scan missing for dispositionNotificationTo and returnReceiptTo
+- [#390](https://github.com/bbottema/simple-java-mail/issues/390) Enhancement: make client sided validation optional, turning off address validation and CRLF injection detection
+
+
+[v7.4.0](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C7.4.0%7Cjar) (19-July-2022)
+
+- [#407](https://github.com/bbottema/simple-java-mail/issues/407) Enhancement: Process all Outlook message headers, either copying the as-is or translating them to respective Simple Java Mail API calls
+- [#404](https://github.com/bbottema/simple-java-mail/issues/404) Minor bugfix: the new attachment's contentDescription was missing in Email.toString()
+
+
+[v7.3.0](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C7.3.0%7Cjar) (15-July-2022)
+
+- [#405](https://github.com/bbottema/simple-java-mail/issues/405) Feature: Expand email builder API to support forced content Content-Transfer-Encoding for attachments, like quoted-printable, base64, 7BIT and others
+- [#404](https://github.com/bbottema/simple-java-mail/issues/404) Feature: Expand email builder API to support Content-Description on attachments
+
+
+v7.2.0 - [v7.2.1](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C7.2.1%7Cjar)
+
+- v7.2.1 (13-July-2022): [#396](https://github.com/bbottema/simple-java-mail/issues/396) Enhancement: make Outlook support tolerant of invalid/empty nested Outlook message attachments
+- v7.2.0 (13-July-2022): [#399](https://github.com/bbottema/simple-java-mail/issues/399) Feature: Expand email builder API to support [selective content encoding](https://www.simplejavamail.org/features.html#section-content-transfer-encoding), like quoted-printable, base64, 7BIT and others
+
+
+v7.1.0 - [v7.1.3](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C7.1.3%7Cjar)
+
+- v7.1.3 (12-July-2022): [#403](https://github.com/bbottema/simple-java-mail/issues/403) Security: Bump zip4j (only used during testing)
+- v7.1.2 (12-July-2022): [#401](https://github.com/bbottema/simple-java-mail/issues/401) Enhancement: Add HEIC and WEBP support when dynamically resolving embedded images from classpath
+- v7.1.2 (12-July-2022): [#402](https://github.com/bbottema/simple-java-mail/issues/402) Security: Update Log4j to 2.17.1
+- v7.1.2 (12-July-2022): [#393](https://github.com/bbottema/simple-java-mail/issues/393) Security: Update Apache POI and POI Scratchpad
+- v7.1.1 (27-March-2022): [#387](https://github.com/bbottema/simple-java-mail/issues/387) Bug: memory leak in SMPT connection pool when 3rd party deallocation failed with exception
+- v7.1.0 (25-January-2022): [#379](https://github.com/bbottema/simple-java-mail/issues/379) Maintenance: Adjust dependencies and make Java 9+ friendly
+
+
+v7.0.1 - [v7.0.2](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C7.0.2%7Cjar)
+
+- v7.0.2 (25-January-2022): [#329](https://github.com/bbottema/simple-java-mail/issues/329) Enhancement: Exceptions cause error-level logging in addition to rethrowing the exception, but should just include the message in a custom exception
+- v7.0.2 (25-January-2022): [#378](https://github.com/bbottema/simple-java-mail/issues/378) Bug: package org.simplejavamail.internal.modules causes split package problem in Java9+
+- v7.0.1 (22-January-2022): [#375](https://github.com/bbottema/simple-java-mail/issues/375) Bug: [batch-module](https://www.simplejavamail.org/features.html#section-sending-asynchronously) gives error when there is a [custom mailer](https://www.simplejavamail.org/features.html#section-custom-mailer)
+
+
+[v7.0.0](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C7.0.0%7Cjar) (2-January-2022)
+
+It has been two years since the last major release, but 7.0.0 finally here!
+
+#### What's new ####
+
+Major features:
+- [#322](https://github.com/bbottema/simple-java-mail/issues/322) Simple Java Mail migrated to Java 8 finally (see notes below)
+- [#295](https://github.com/bbottema/simple-java-mail/issues/295) And also switched to JavaMail's successor Jakarta Mail 2.0.1 (see notes below)
+- [#323](https://github.com/bbottema/simple-java-mail/issues/323) Solved the great CLI performance problem (now executes near instantly)
+- [#319](https://github.com/bbottema/simple-java-mail/issues/319) Replaced the underlying regex-based email-address validation library with the lexer based [JMail](https://github.com/RohanNagar/jmail), which is faster, [correcter](https://www.rohannagar.com/jmail/), documented better and is more up-to-date with RFC's
+- [#367](https://github.com/bbottema/simple-java-mail/issues/367) The sendMail/testConnection methods now have proper support for `CompletableFuture`
+
+Bugfixes:
+- [#352](https://github.com/bbottema/simple-java-mail/issues/352) Bug: names regex groups are not supported in Android JVM
+- [#326](https://github.com/bbottema/simple-java-mail/issues/326) Bug: NullPointer when parsing Outlook Message with nested empty Outlook message
+- [#330](https://github.com/bbottema/simple-java-mail/issues/330) Bug: cli expected --mailer arguments duplicated 3 times
+- [#324](https://github.com/bbottema/simple-java-mail/issues/324) Bug: Add back missing log4j2 for CLI library
+
+Maintenance:
+- [#368](https://github.com/bbottema/simple-java-mail/issues/368) Resolve log4j (Java8) [vulnerability](https://logging.apache.org/log4j/2.x/security.html) in Simple Java Mail's CLI module
+- [#330](https://github.com/bbottema/simple-java-mail/issues/330) Improved feedback from failing CLI commands
+- [#327](https://github.com/bbottema/simple-java-mail/issues/327) Implement toString() for Mailer instances for debugging purposes
+
+#### About the migration ####
+
+Updating to Java8/Jakarta 2.0.1 posed a challenge as the 3rd party S/MIME library [java-utils-mail-smime](https://github.com/markenwerk/java-utils-mail-smime) has been abandoned/archived while developing Simple Java Mail. Furthermore, it was still under LGPL3 license while everything else is ApacheV2.
+
+Thankfully, I obtained permissions from the maintainers -as well as original developers from decades ago on SourceForge- to take both java-utils-mail-smime and java-utils-mail-dkim under my wings at Simple Java Mail and change the licensing model! You can now post issues and pull requests here:
+- [simple-java-mail/java-utils-mail-smime](https://github.com/simple-java-mail/java-utils-mail-smime)
+- [simple-java-mail/java-utils-mail-dkim](https://github.com/simple-java-mail/java-utils-mail-dkim)
+
+
+
+v6.7.0 - [v6.7.6](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C6.7.6%7Cjar)
+
+- v6.7.6 (22-January-2022): [#375](https://github.com/bbottema/simple-java-mail/issues/375) Bug: [batch-module](https://www.simplejavamail.org/features.html#section-sending-asynchronously) gives error when there is a [custom mailer](https://www.simplejavamail.org/features.html#section-custom-mailer)
+- v6.7.5 (26-December-2021): [#338](https://github.com/bbottema/simple-java-mail/issues/338) Enhancement: Also return AsyncResponse from plain Mailer.sendEmail(singleArgument) as async can be configured through MailerBuilder now
+- v6.7.4 (25-December-2021): [#331](https://github.com/bbottema/simple-java-mail/issues/331) Enhancement: Coalesce empty SMTP server arguments to null to support CLI better
+- v6.7.3 (25-December-2021): [#335](https://github.com/bbottema/simple-java-mail/issues/335) Bugfix: Precondition nonNull check also checks nonEmpty and breaks on clearEmailAddressCriteria
+- v6.7.2 (25-December-2021): [#318](https://github.com/bbottema/simple-java-mail/issues/318) Maintenance: Allow zero data attachments so Outlook message conversions don't crash and burn
+- v6.7.1 (25-December-2021): [#346](https://github.com/bbottema/simple-java-mail/issues/346) Bugfix: Add option to parse MimeMessage without fetching attachment data from server - Properly return named datasource without fetching all the data if unwanted
+- v6.7.0 (25-December-2021): [#356](https://github.com/bbottema/simple-java-mail/issues/356) Enhancement: Improve for support for Android < 8.0 (Fix NoClassDefFoundError)
+- v6.7.0 (25-December-2021): [#351](https://github.com/bbottema/simple-java-mail/issues/351) Bugfix: emlToEmail() and mimeMessageToEmail() break on mesages with duplicate names and legacy empty nested messages
+- v6.7.0 (25-December-2021): [#347](https://github.com/bbottema/simple-java-mail/issues/347) Maintenance: Reduce log-spam and prevent exception on every module availability check
+- v6.7.0 (25-December-2021): [#346](https://github.com/bbottema/simple-java-mail/issues/346) Feature: Add option to parse MimeMessage [without fetching attachment data](https://www.simplejavamail.org/features.html#section-converting) from server
+
+
+v6.6.0 - [v6.6.2](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C6.6.2%7Cjar)
+
+- v6.6.2 (23-December-2021): [#365](https://github.com/bbottema/simple-java-mail/issues/365) Security: Resolve log4j vulnerability in Simple Java Mail
+- v6.6.1 (12-June-2021): [#321](https://github.com/bbottema/simple-java-mail/issues/321) Enhancement: Ignore malformed recipient addresses and continue parsing email data
+- v6.6.0 (1-June-2021): [#320](https://github.com/bbottema/simple-java-mail/issues/320) Enhancement: Added [default S/MIME signing](https://www.simplejavamail.org/features.html#section-sending-smime) to Mailer level and fixed crippling performance bug
+
+
+v6.5.0 - [v6.5.4](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C6.5.4%7Cjar)
+
+- v6.5.4 (22-May-2021): [#315](https://github.com/bbottema/simple-java-mail/issues/315) Enhancement: Nested attachments of Outlook message attachments are now preserved as standard EML MimeMessage attachments
+
+ **NOTE:** This _removes_ the Kryo dependency
+
+- v6.5.3 (4-May-2021): [#314](https://github.com/bbottema/simple-java-mail/issues/314) Bugfix: Nested attachments of Outlook message attachments are now preserved, by utilizing Kryo
+
+ **NOTE:** This add Kryo as extra dependency to the outlook-module (and is subsequently removed in 6.5.4)
+
+- v6.5.2 (15-April-2021): [#311](https://github.com/bbottema/simple-java-mail/issues/311) Bugfix: text/calendar as string -> ClassCastException (if calendar type is not Inputstream)
+- v6.5.1 (10-April-2021): [#307](https://github.com/bbottema/simple-java-mail/issues/307) / [#310](https://github.com/bbottema/simple-java-mail/issues/310) Bugfix: embedded image resource name got mangled
+- v6.5.0 (16-February-2021): [#298](https://github.com/bbottema/simple-java-mail/issues/298) Enhancement: Nested Outlook messages aren't discarded anymore, but parsed to serialized Email objects
+- v6.5.0 (16-February-2021): [#292](https://github.com/bbottema/simple-java-mail/issues/292) Bugfix: NullPointerException in SmimeUtilFixed when protocol is missing (which is valid)
+- v6.5.0 (16-February-2021): [#289](https://github.com/bbottema/simple-java-mail/issues/289) Bugfix: Support multiple headers with same key
+
+This release breaks all GET/SET api regarding headers used as map (Map<String, T> -> Map<String, Collection<T>>)
+This release might break api in the rare case you relied on the attachment list and you have nested Outlook .msg attachments (previously omitted in the results)
+
+
+v6.4.0 - [v6.4.5](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C6.4.5%7Cjar)
+
+- v6.4.5 (13-Februari-2021): [#306](https://github.com/bbottema/simple-java-mail/issues/306) Maintenance: Update outlook-message-parser to 1.7.9
+- v6.4.5 (13-Februari-2021): [#304](https://github.com/bbottema/simple-java-mail/issues/304) Regression bugfix: batch-module needed for sending mails async, basic version should work without
+- v6.4.5 (13-Februari-2021): [#303](https://github.com/bbottema/simple-java-mail/issues/303) Bugfix: EML Attachments are modified/have the wrong size
+- v6.4.4 (25-October-2020): [#294](https://github.com/bbottema/simple-java-mail/issues/294) Always invoke async success/exception handlers even if set after sending email (behaving more like promises/futures)
+- v6.4.4 (25-October-2020): [#291](https://github.com/bbottema/simple-java-mail/issues/291) On Exception only log the email ID at error level and log the whole email at trace level
+- v6.4.4 (25-October-2020): [#290](https://github.com/bbottema/simple-java-mail/issues/290) Only perform expensive logging logic if respective logging level is enabled
+- v6.4.3 (6-August-2020): [#284](https://github.com/bbottema/simple-java-mail/issues/284) Improved support for Calendar attachments created by gMail
+- v6.4.3 (6-August-2020): [#283](https://github.com/bbottema/simple-java-mail/issues/283) Bugfix: Fix support for reading Calendar attachments with quoted-printable transfer-type
+- v6.4.2 (3-August-2020): [#281](https://github.com/bbottema/simple-java-mail/issues/281) Bugfix: Fix support for reading Calendar attachments
+- v6.4.1 (26-July-2020): [#252](https://github.com/bbottema/simple-java-mail/issues/252) Bugfix: Added missing support for S/MIME enveloped signing
+- v6.4.0 (19-July-2020): [#268](https://github.com/bbottema/simple-java-mail/issues/268) Immediately resolve InputStreams when building emails, don't reuse
+ * This primarily affects the builder api for S/MIME and DKIM signing / encryption.
+
+
+v6.3.0 - [v6.3.2](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C6.3.2%7Cjar) (11-July-2020 - 12-July-2020)
+
+- [#271](https://github.com/bbottema/simple-java-mail/issues/271) Bugfix: Attachment (file)names with special characters should not be encoded
+- [#248](https://github.com/bbottema/simple-java-mail/issues/248) Bugfix: MimeMessageHelper: use complete filename as resource name
+- [#279](https://github.com/bbottema/simple-java-mail/issues/279) Allow [extra Session properties](https://www.simplejavamail.org/features.html#section-custom-properties) configured through simplejavamail.properties
+- [#277](https://github.com/bbottema/simple-java-mail/issues/277) Add API for using [custom SSLSocketFactory](http://localhost:3000/features.html#section-ssl-tls)
+
+
+[v6.2.0](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C6.2.0%7Cjar) (9-July-2020)
+
+This release adds the following major new feature:
+
+- [#260](https://github.com/bbottema/simple-java-mail/issues/260) **Add support for [dynamic datasource resolution](https://www.simplejavamail.org/features.html#section-embedding)** (file/url/classpath) for embedded images in HTML body
+
+
+[v6.1.0](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C6.1.0%7Cjar) (5-July-2020)
+
+- [#264](https://github.com/bbottema/simple-java-mail/issues/264) Switch from AssertionError to IllegalStateException
+- Bumped outlook-message-parser from 1.7.3 to 1.7.5
+ - bugfix for parsing chinese unsent Outlook messages
+ - bugfix Outlook attachments with special characters in the name
+- Bumped email-rfc2822-validator from 2.1.3 to 2.2.0
+ - bugfix properly handle brackets in email addresses when allowed
+- Bumped log4j-core from 2.6.1 to 2.13.2
+
+
+v6.0.2 - [v6.0.5](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C6.0.5%7Cjar) (21-January-2020 - 13-June-2020)
+
+- [#270](https://github.com/bbottema/simple-java-mail/issues/270) Bug: CLI module missing Jetbrains @Nullable annotation dependency needed in runtime
+- [#262](https://github.com/bbottema/simple-java-mail/issues/262) Bug: Executor settings passed to the builder are ignored
+- [#249](https://github.com/bbottema/simple-java-mail/issues/249) Bug: MimeMessageParser doesn't handle multiple attachments with the same name correctly
+- [#245](https://github.com/bbottema/simple-java-mail/issues/245) Bug: JDK9+ Incorrect JPMS Automatic-Module-Name
+- [#246](https://github.com/bbottema/simple-java-mail/issues/246) Bug: Sending async emails with and without the Batch module cause lingering threads
+
+
+v6.0.0-rc1 - [v6.0.1](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C6.0.1%7Cjar) (18-December-2019 - 24-January-2020)
+
+After almost two years of development the next major release 6.0.0 is finally here! And what a doozy it is, with the following major new features:
+
+The core library is now even smaller compared to the 5.x.x series going from 183kb to 134kb!
+
+- [CLI support!!](https://www.simplejavamail.org/cli.html#navigation),
+- major performance improvement with [advanced batch processing](https://www.simplejavamail.org/configuration.html#section-batch-and-clustering) including support for mail server clusters.
+- You can now replace the final sending of emails with [your own logic](https://www.simplejavamail.org/features.html#section-custom-mailer), using a 3rd party service of your choice.
+- 6.0.0 also includes support for [S/MIME signed and encrypted emails](https://www.simplejavamail.org/features.html#section-smime)!
+- All 3rd party dependencies have been made optional by splitting up Simple Java Mail into easy to use [modules](https://www.simplejavamail.org/modules.html#navigation).
+- You can now monitor and [handle async processing](https://www.simplejavamail.org/features.html#section-handling-async-result) using Futures.
+- MimeMessage results are now [structurally matched](https://www.simplejavamail.org/rfc-compliant.html#section-explore-multipart) to specific needs (only using alternative/mixed etc. when needed)
+
+Here's the complete list of changes:
+
+#### New features and enhancements ####
+- [#183](https://github.com/bbottema/simple-java-mail/issues/183) To manage all the optional dependencies and related code, Simple Java Mail should be [split up into modules](https://www.simplejavamail.org/modules.html#navigation)
+- [#156](https://github.com/bbottema/simple-java-mail/issues/156) Add [CLI support](https://www.simplejavamail.org/cli.html#navigation)
+- [#214](https://github.com/bbottema/simple-java-mail/issues/214) Support more [advanced batch processing](https://www.simplejavamail.org/features.html#section-sending-asynchronously) use cases
+- [#187](https://github.com/bbottema/simple-java-mail/issues/187) Simple Java Mail should have optional support for signed [S/MIME attachments](https://www.simplejavamail.org/modules.html#smime-module)
+- [#121](https://github.com/bbottema/simple-java-mail/issues/121) Introduce interfaces for validation and sending, so these steps can be customized
+- [#144](https://github.com/bbottema/simple-java-mail/issues/144) Simple Java Mail should [tailor the MimeMessage structure](https://www.simplejavamail.org/migration-notes-6.0.0.html#mimemessage-structure) to specific needs
+- [#138](https://github.com/bbottema/simple-java-mail/issues/138) Add support for [Calendar events](https://www.simplejavamail.org/features.html#section-icalendar-vevent) (iCalendar vEvent)
+- [#235](https://github.com/bbottema/simple-java-mail/issues/235) Be able to [fix the sent date](https://www.simplejavamail.org/features.html#section-custom-sentdate) for a new email
+- [#232](https://github.com/bbottema/simple-java-mail/issues/232) Improve encoding of attachment file names
+- [#222](https://github.com/bbottema/simple-java-mail/issues/222) Add config property support for trusting hosts and verifying server identity
+- [#212](https://github.com/bbottema/simple-java-mail/issues/212) Authenticated proxy server started even if already running, raising exception
+- [#207](https://github.com/bbottema/simple-java-mail/issues/207) Implement more comprehensive ThreadPoolExecutor and expose config options
+- [#211](https://github.com/bbottema/simple-java-mail/issues/211) SpringSupport should expose the intermediate builder for customization
+- [#193](https://github.com/bbottema/simple-java-mail/issues/193) Simple Java Mail should use default server ports when not provided by the user
+
+#### Bugs solved ####
+- [#242](https://github.com/bbottema/simple-java-mail/issues/242) Renamed log4j2.xml to log4j2_example.xml, so it doesn't clash with project config
+- [#241](https://github.com/bbottema/simple-java-mail/issues/241) EmailConverter.outlookMsgToEmail duplicates recipients
+- [#239](https://github.com/bbottema/simple-java-mail/issues/239) List of Recipients not ordered as added (insertion order not maintained)
+- [#236](https://github.com/bbottema/simple-java-mail/issues/236) Message ID should be mapped from Outlook messages as well
+- [#210](https://github.com/bbottema/simple-java-mail/issues/210) Connection/session timeout properties not set when not sending in batch mode
+- [#201](https://github.com/bbottema/simple-java-mail/issues/201) When parsing Outlook message, FROM address should default to a dummy address when missing
+- [#200](https://github.com/bbottema/simple-java-mail/issues/200) When parsing Outlook message, attachment name doesn't fall back on filename if proper name is empty
+- [#161](https://github.com/bbottema/simple-java-mail/issues/161) When reading (chinese) .msg files, HTML converted from RTF is completely garbled (encoding issue)
+- [#159](https://github.com/bbottema/simple-java-mail/issues/159) Can not parse email with blank email address headers
+- [#139](https://github.com/bbottema/simple-java-mail/issues/139) Multiple Bodyparts of same Content-Type not supported for text/html & text/plain within Multipart/mixed or Multipart/alternative
+- [#151](https://github.com/bbottema/simple-java-mail/issues/151) Attachment's file extension overwritten by resource's invalid extension
+
+#### Maintenance updates ####
+- [#165](https://github.com/bbottema/simple-java-mail/issues/165) Move away from Findbugs (unofficial JSR-305) annotations
+- [#164](https://github.com/bbottema/simple-java-mail/issues/164) The DKIM dependency has been updated to benefit from the newer Apache V2 license
+- [#164](https://github.com/bbottema/simple-java-mail/issues/164) The DKIM dependency has been updated to benefit from the newer Apache V2 license
+- [#184](https://github.com/bbottema/simple-java-mail/issues/184) Update JavaMail dependency to 1.6.2, adding support for UTF-8 charset
+- [#186](https://github.com/bbottema/simple-java-mail/issues/186) Update JavaMail dependency to 1.6.2, adding support for authenticated HTTP web proxy
+- [#146](https://github.com/bbottema/simple-java-mail/issues/146) Added OSGI manifest and switched to spotbugs
+
+#### Included changes from outlook-message-parser ####
+- v6.0.1, v1.7.3: [#27](https://github.com/bbottema/outlook-message-parser/issues/27) When from name/address are not available (unsent emails), these fields are filled with binary garbage
+- v6.0.1, v1.7.2: [#26](https://github.com/bbottema/outlook-message-parser/issues/26) To email address is not handled properly when name is omitted
+- v6.0.0, v1.7.1: [#25](https://github.com/bbottema/outlook-message-parser/issues/25) NPE on ClientSubmitTime when original message has not been sent yet
+- v6.0.0, v1.7.1: [#23](https://github.com/bbottema/outlook-message-parser/issues/23) Bug: __nameid_ directory should not be parsed (and causing invalid HTML body)
+- v6.0.0, v1.7.0: [#18](https://github.com/bbottema/outlook-message-parser/issues/18) Upgrade Apache POI 3.9 -> 4.x (but managed back for Simple Java Mail due to incompatibility with Java 7)
+- v6.0.0, v1.6.0: [#21](https://github.com/bbottema/outlook-message-parser/issues/21) Multiple TO recipients are not handles properly
+- v6.0.0, v1.5.0: [#20](https://github.com/bbottema/outlook-message-parser/issues/20) CC and BCC recipients are not parsed properly
+- v6.0.0, v1.5.0: [#19](https://github.com/bbottema/outlook-message-parser/issues/19) Use real Outlook ContentId Attribute to resolve CID Attachments
+- v6.0.0, v1.4.1: [#17](https://github.com/bbottema/outlook-message-parser/issues/17) Fixed encoding error for UTF-8's Windows legacy name (cp)65001
+- v6.0.0, v1.4.0: [#9](https://github.com/bbottema/outlook-message-parser/issues/9) Replaced the RFC to HTML converter with a brand new RFC-compliant convert! (thanks to @fadeyev!)
+- v6.0.0, v1.3.0: [#14](https://github.com/bbottema/outlook-message-parser/issues/14) Dependency problem with Java9+, missing Jakarta Activation Framework
+- v6.0.0, v1.3.0: [#13](https://github.com/bbottema/outlook-message-parser/issues/13) HTML start tags with extra space not handled correctly
+- v6.0.0, v1.3.0: [#11](https://github.com/bbottema/outlook-message-parser/issues/11) SimpleRTF2HTMLConverter inserts too many tags
+- v6.0.0, v1.3.0: [#10](https://github.com/bbottema/outlook-message-parser/issues/10) Embedded images with DOS-like names are classified as attachments
+- v6.0.0, v1.3.0: [#9](https://github.com/bbottema/outlook-message-parser/issues/9) SimpleRTF2HTMLConverter removes some valid tags during conversion
+- v6.0.0, v1.2.1: Ignore non S/MIME related content types when extracting S/MIME metadata
+- v6.0.0, v1.2.1: Added toString and equals methods to the S/MIME data classes
+- v6.0.0, v1.1.21: Upgraded mediatype recognition based on file extension for incomplete attachments
+- v6.0.0, v1.1.21: Added / improved support for public S/MIME meta data
+- v6.0.0, v1.1.20: [#7](https://github.com/bbottema/outlook-message-parser/issues/7) Fix missing S/MIME header details that are needed to determine the type of S/MIME application
+- v6.0.0, v1.1.19: Log rtf compression error, but otherwise ignore it and keep going and extract what we can.
+
+**A big shout-out to @dnault ([runtime javadoc](https://github.com/dnault/therapi-runtime-javadoc)), @remkop ([picocli](https://picocli.info/)) and @markenwerk
+([S/MIME](https://github.com/markenwerk/java-utils-mail-smime) and [DKIM](https://github.com/markenwerk/java-utils-mail-dkim)) for working with me to make the
+libraries work with JDK7+ and do what Simple Java Mail needed! Finally, a great many thanks the numerous contributors on Simple Java Mail as well as
+[outlook-message-parser](https://github.com/bbottema/outlook-message-parser) - this release would not be there without you.**
+
+
+v5.5.0 - [v5.5.1](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C5.5.1%7Cjar)
+
+- v5.5.1 (20-October-2019): [#230](https://github.com/bbottema/simple-java-mail/issues/230) Bugfix: Missing address value in address headers (i.e. Return-Path) not handled properly, resulting in Exception
+- v5.5.0 (15-October-2019): [#229](https://github.com/bbottema/simple-java-mail/issues/229) Bugfix: Timeouts not working for synchronous sendMail calls.
+
+ If you had connection properties configured for non-async send jobs, only now they will actually start to take effect.
+
+
+[v5.4.0](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C5.4.0%7Cjar) (28-August-2019)
+
+- [#221](https://github.com/bbottema/simple-java-mail/issues/221) API bugfix: server identity verification should not be tied to host trusting
+- [#226](https://github.com/bbottema/simple-java-mail/issues/226) Bug fix: Attachments with spaces in name are not handled properly
+- [#218](https://github.com/bbottema/simple-java-mail/issues/218) Enhancement: make Email serializable
+- [#227](https://github.com/bbottema/simple-java-mail/issues/227) Enhancement: Make parsing recipients from EML file more lenient
+- [#225](https://github.com/bbottema/simple-java-mail/issues/225) Enhancement: Clarify dependency on Jakarta Activation: DataSources no longer work on Java 9+
+
+
+[v5.3.0](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C5.3.0%7Cjar) (16-August-2019)
+
+- [#215](https://github.com/bbottema/simple-java-mail/issues/215) Bug: Current DKIM header canonicalization can lead to invalid DKIM
+
+Note this release should have no impact, but nonetheless is a minor update, so you can determine for yourself if this update would cause issues.
+The release changes DKIM header canonicalization from SIMPLE to RELAXED.
+
+
+[v5.2.1](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C5.2.1%7Cjar) (16-August-2019)
+
+- [#219](https://github.com/bbottema/simple-java-mail/issues/219) Bug: MimeMessageParser rejects attachments with duplicate names
+
+
+[v5.2.0](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C5.2.0%7Cjar) (7-July-2019)
+
+- [#213](https://github.com/bbottema/simple-java-mail/issues/213) Update from javax.mail:1.6.0 to jakarta.mail:1.6.3
+
+Note that dependencies that switched as well have been updated as part of this change. This includes the optional DKIM library and the email validation library:
+- net.markenwerk:utils-mail-dkim (1.1.10 -> 1.2.0)
+- com.github.bbottema:emailaddress-rfc2822 (1.1.2 -> 2.1.3)
+
+
+v5.1.1 - [v5.1.7](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C5.1.7%7Cjar)
+
+- v5.1.7 (22-May-2019): [#171](https://github.com/bbottema/simple-java-mail/issues/171) Header validation tripping on known safe emails due to References header
+- v5.1.6 (27-April-2019): [#204](https://github.com/bbottema/simple-java-mail/issues/204) A Concurrent exception when an async process starts when the previous connection pool didn't shut down in time
+- v5.1.6 (27-April-2019): [#204](https://github.com/bbottema/simple-java-mail/issues/204) B Exceptions in threads are now caught and logged and don't bubble up anymore. Note that more comprehensive exception handling will be available in 6.0.0 ([#148](https://github.com/bbottema/simple-java-mail/issues/148)).
+- v5.1.5 (24-April-2019): [#202](https://github.com/bbottema/simple-java-mail/issues/202) Fixed ConcurrentModificationException when moving invalid embedded images as regular attachments
+- v5.1.4 (5-April-2019): [#163](https://github.com/bbottema/simple-java-mail/issues/163) Fixed missing mimetype for attachments when parsing Outlook messages where mimeTag was not included
+- v5.1.3 (15-Januari-2019): Updated to newer rfc-validator version, which fixed a regression bug in that library
+- v5.1.2 (9-Januari-2019): [#189](https://github.com/bbottema/simple-java-mail/issues/189) Bugfix for missing timeout config for .testConnection() function
+- v5.1.1 (22-December-2018): [#190](https://github.com/bbottema/simple-java-mail/issues/190) Fix for transitive dependency clash because of emailaddress-rfc2822 library
+
+
+[v5.1.0](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C5.1.0%7Cjar) (21-November-2018)
+
+- [#179](https://github.com/bbottema/simple-java-mail/issues/179) You can now [test the connection](https://www.simplejavamail.org/features.html#section-connection-test) to the SMTP server
+
+
+v5.0.1 - [v5.0.8](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C5.0.8%7Cjar)
+
+- v5.0.8 (27-Oktober-2018): [#178](https://github.com/bbottema/simple-java-mail/issues/178) Fix the annoying vulnerability GitHub report about spring-core
+- v5.0.7 (27-Oktober-2018): [#175](https://github.com/bbottema/simple-java-mail/issues/175) Attachment names are not always parsed properly from MimeMessage
+- v5.0.6 (3-Oktober-2018): [#167](https://github.com/bbottema/simple-java-mail/issues/167) Email addresses validated despite cleared validation criteria
+- v5.0.5 (3-Oktober-2018): [#137](https://github.com/bbottema/simple-java-mail/issues/137) When replying to an email with HTML, the result body is empty
+- v5.0.4 (22-September-2018): [#168](https://github.com/bbottema/simple-java-mail/issues/168) Properties aquired through ConfigLoader should be typed explicitly and converted if necessary
+- v5.0.3 (11-April-2018): [#136](https://github.com/bbottema/simple-java-mail/issues/136) ServerConfig class should be public API
+- v5.0.2 (7-April-2018): [#135](https://github.com/bbottema/simple-java-mail/issues/135) trustingAllHosts should be public on the Builder API
+- v5.0.2 (7-April-2018): [#131](https://github.com/bbottema/simple-java-mail/issues/131) NamedDataSource should implement EncodingAware
+- v5.0.1 (10-March-2018): [#130](https://github.com/bbottema/simple-java-mail/issues/130) java.lang.ClassNotFoundException: net.markenwerk.utils.mail.dkim.DkimMessage. Solves the issue of missing optional class DKIM even when not used
+
+
+[v5.0.0](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C5.0.0%7Cjar) (14-Februari-2018)
+
+Also see the [migration notes](https://www.simplejavamail.org/migration-notes-5.0.0.html#navigation)
+
+#### New features ####
+- [#116](https://github.com/bbottema/simple-java-mail/issues/116) You can now test the connection to the SMTP server
+- [#115](https://github.com/bbottema/simple-java-mail/issues/115) Create mailers with a very robust MailerBuilder API, able to ignore defaults as well
+- [#114](https://github.com/bbottema/simple-java-mail/issues/114) Create emails with a very robust EmailBuilder API, able to ignore defaults as well. Now includes support for InternetAddress. Also copy emails.
+- [#107](https://github.com/bbottema/simple-java-mail/issues/107) You can now easily forward or reply to emails!
+
+#### Security updates ####
+- [#111](https://github.com/bbottema/simple-java-mail/issues/111) Protocol properties for SMTPS are now applied properly
+- [#105](https://github.com/bbottema/simple-java-mail/issues/105) SMTP tries to upgrade to TLS while SMTP_TLS now enforces it and for both SMTP_TLS and SMTPS, [mail.smtp.ssl.checkserveridentity](https://javaee.github.io/javamail/docs/api/com/sun/mail/smtp/package-summary.html) is set to true
+
+#### Maintenance updates ####
+
+Complete [Javadoc](https://www.javadoc.io/doc/org.simplejavamail/simple-java-mail) overhaul. Navigating the Javadoc should be much more consistent now (builder API being the single *public* source of truth).
+
+- [#122](https://github.com/bbottema/simple-java-mail/issues/122) The email-rfc2822-validator library has been made a proper Maven dependency (not packaged along anymore)
+- [#120](https://github.com/bbottema/simple-java-mail/issues/120) The DKIM library has been made an optional proper Maven dependency (not packaged along anymore)
+- [#119](https://github.com/bbottema/simple-java-mail/issues/119) Switched optional Spring dependency version to property and now testing with 4.3.11.RELEASE
+- [#113](https://github.com/bbottema/simple-java-mail/issues/113) Updated the underlying JavaMail to 1.6.0
+
+#### Bugfixes ####
+- [#110](https://github.com/bbottema/simple-java-mail/issues/110) Trusted hosts should be space-delimited
+- [#109](https://github.com/bbottema/simple-java-mail/issues/109) Email headers should be allowed to be empty (now conversion errors can occur as well)
+- [#103](https://github.com/bbottema/simple-java-mail/issues/103) Converting to MimeMessage results in an invalid Content-Disposition for attachments
+
+
+[v4.4.5](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C4.4.5%7Cjar) (2-September-2017)
+
+- [#101](https://github.com/bbottema/simple-java-mail/issues/101) API backwards compatibility update, reinstate old addRecipient API as deprecated (sorry for removing it abruptly)
+
+
+[v4.4.4](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C4.4.4%7Cjar) (23-August-2017)
+
+API usability release. **This relase streamlined the recipient setters, breaking backwards compatibility (but straightforward to fix)**
+
+- [#95](https://github.com/bbottema/simple-java-mail/issues/95) Feature: Add support native API for [setting Return-Receipt-To](https://www.simplejavamail.org/features.html#section-return-receipt) header
+- [#93](https://github.com/bbottema/simple-java-mail/issues/93) Feature: Add support native API for setting [Disposition-Notification-To](https://www.simplejavamail.org/features.html#section-return-receipt) header
+- [#91](https://github.com/bbottema/simple-java-mail/issues/91) **Feature: Add support for parsing [preformatted email addresses](https://www.simplejavamail.org/features.html#section-add-recipients) that include both name and address**
+- [#94](https://github.com/bbottema/simple-java-mail/issues/94) Bugfix: A single EmailBuilder would build emails that all share the same collections for recipients, attachments and embedded images
+- [#98](https://github.com/bbottema/simple-java-mail/issues/98) Bugfix: Subject and body content should be optional
+
+
+[v4.3.0](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C4.3.0%7Cjar) (12-August-2017)
+
+Security and timeout release.
+
+This version safeguards against SMTP injection attack from external values entering the library through *Email* instance. Also, this release introduces default/configurable timeouts for connecting, reading and writing when sending an email.
+
+- [#89](https://github.com/bbottema/simple-java-mail/issues/89) Support multiple delimited recipient addresses sharing the same TO/CC/BCC name
+- [#88](https://github.com/bbottema/simple-java-mail/issues/88) **Safeguard subject property (and others) against SMTP CRLF injection attacks**
+- [#85](https://github.com/bbottema/simple-java-mail/issues/85) **Apply configurable timeouts when sending emails**
+- [#83](https://github.com/bbottema/simple-java-mail/issues/83) Parse INLINE attachments without ID as regular attachments when converting (mostly applicable to Apple emails)
+
+
+[v4.2.3](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C4.2.3%7Cjar) (21-May-2017)
+
+- [#79](https://github.com/bbottema/simple-java-mail/issues/79): Enhancement: define custom message ID on the Email object
+- [#74](https://github.com/bbottema/simple-java-mail/issues/74): v4.2.3-java-6-release: A java6 version with limited capabilities:
+ I've released a customised java6 release with a customised outlook-message-parser 1.1.16-java6-release. **This is the last java6 release** I will do, as it is simply too much manual labor to create a limited second edition.
+
+ For this edition, I've removed the JDK7 Phaser completely which has the following consequences:
+
+ - If authenticated proxy is used, the bridging proxy server will not be shut down automatically (and might not run the second time)
+ - If mails are sent in async mode, the connection pool will not be shut down anymore by itself
+
+ This means your server/application might not stop properly due to lingering processes. To be completely safe, only send emails in sync mode (used by default) and don't use authenticated proxy config.
+
+
+[v4.2.2](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C4.2.2%7Cjar) (10-May-2017)
+
+- [#73](https://github.com/bbottema/simple-java-mail/issues/73): Patch: fix for sending emails in async mode, which makes sure the connection pool is always closed when the last *known* email has been sent. Without this fix, the connection pool keeps any parent process running (main thread or Tomcat for example) until a hard kill.
+
+
+[v4.2.1](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C4.2.1%7Cjar) (12-Feb-2017)
+
+Patch: streamlined convenience methods for adding recipients.
+
+
+[v4.2.0](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C4.2.0%7Cjar) (12-Feb-2017)
+
+**Major feature: Using the EmailConverter you can now [convert between](https://www.simplejavamail.org/features.html#section-converting) Outlook .msg, EML, MimeMessage and Email**!
+
+- [#66](https://github.com/bbottema/simple-java-mail/issues/66): Feature: [convert](https://www.simplejavamail.org/features.html#section-converting) email to EML
+- [#65](https://github.com/bbottema/simple-java-mail/issues/65): Feature: [read outlook messages](https://www.simplejavamail.org/modules.html#outlook-module) from .msg file
+- [#64](https://github.com/bbottema/simple-java-mail/issues/64): **Feature: Added support for [logging-only mode](https://www.simplejavamail.org/debugging.html#section-debug-mode) that skips the actual sending of emails**
+- [#63](https://github.com/bbottema/simple-java-mail/issues/63): Feature: Already including in previous patch update: [Spring support](https://www.simplejavamail.org/modules.html#spring-module) (read properties from Spring context)
+- [#69](https://github.com/bbottema/simple-java-mail/issues/69): Enhancement: Expanded EmailBuilder API to inlude more options for setting (multiple) recipients
+- [#70](https://github.com/bbottema/simple-java-mail/issues/70): Enhancement: Most public API now have defensive null-checks for required fields (Fail Fast support)
+- [#68](https://github.com/bbottema/simple-java-mail/issues/68): Bugfix: Name should be required for embedded images (added safeguards)
+- [#67](https://github.com/bbottema/simple-java-mail/issues/67): Bugfix: Error when name was omitted for attachment
+- minor: added methods on AttachmentResource that reads back the content as (encoded) String
+- other: internal testing is now done using Wiser SMTP test server for testing live sending emails
+
+**Note**: Starting this release, there will always be a Java6 compatible release as well versioned: "x.y.z-java6-release"
+
+
+[v4.1.3](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C4.1.3%7Cjar) (28-Jan-2017)
+
+- [#61](https://github.com/bbottema/simple-java-mail/issues/61): Feature: Add support for [providing your own Properties](https://www.simplejavamail.org/features.html#section-custom-properties) object
+- [#63](https://github.com/bbottema/simple-java-mail/issues/63): **Feature: [Spring support](https://www.simplejavamail.org/modules.html#spring-module) (read properties from Spring context)**
+- [#58](https://github.com/bbottema/simple-java-mail/issues/58): Bugfix: Add support for non-English attachment and embedded image names
+- [#62](https://github.com/bbottema/simple-java-mail/issues/62): Bugfix: Empty properties loaded from config should be considered null
+
+**NOTE**: ConfigLoader moved from `/internal/util` to `/util`
+
+
+[v4.1.2](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C4.1.2%7Cjar) (07-Nov-2016)
+
+- [#52](https://github.com/bbottema/simple-java-mail/issues/52): bug fix for windows / linux disparity when checking socket status
+- [#56](https://github.com/bbottema/simple-java-mail/issues/56): bug fix for IOException when signing dkim with a File reference
+
+
+[v4.1.1](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C4.1.1%7Cjar) (30-Jul-2016)
+
+- [#50](https://github.com/bbottema/simple-java-mail/issues/50): bug fix for manual naming datasources
+
+
+[v4.1.0](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C4.1.0%7Cjar) (22-Jul-2016)
+
+- [#48](https://github.com/bbottema/simple-java-mail/issues/48): Added programmatic support trusting hosts for SSL connections
+- [#47](https://github.com/bbottema/simple-java-mail/issues/47): Honor given names, deduce extension from datasource name, and more robust support for parsing mimemessages
+
+
+[v4.0.0](https://search.maven.org/#artifactdetails%7Corg.simplejavamail%7Csimple-java-mail%7C4.0.0%7Cjar) (05-Jul-2016)
+
+- [#41](https://github.com/bbottema/simple-java-mail/issues/41): added support for fast parallel batch processing
+- [#42](https://github.com/bbottema/simple-java-mail/issues/42): **added support for config files**
+- [#43](https://github.com/bbottema/simple-java-mail/issues/43): removed logging implementation dependencies from distribution and documented various sample configs
+- [#39](https://github.com/bbottema/simple-java-mail/issues/39): simplified and renamed packages to reflect the domain name of the new website: [simplejavamail.org](https://www.simplejavamail.org)
+- [#38](https://github.com/bbottema/simple-java-mail/issues/38): added support for anonymous proxy
+- [#38](https://github.com/bbottema/simple-java-mail/issues/38): **added support for authenticated proxy**
+
+**NOTE**: All packages have been renamed to "org.simplejavamail.(..)"
+**NOTE**: Switched to Java 7
+
+
+[v3.1.1](https://search.maven.org/#artifactdetails%7Corg.codemonkey.simplejavamail%7Csimple-java-mail%7C3.1.1%7Cjar) (11-May-2016)
+
+**Major feature: DKIM support**!
+
+- [#36](https://github.com/bbottema/simple-java-mail/issues/36): Added proper toString and equals methods for the Email classes
+- [#33](https://github.com/bbottema/simple-java-mail/issues/33): Added [support for DKIM](https://www.simplejavamail.org/features.html#section-dkim) domain key signing
+
+*NOTE*: this is the last release still using Java 6. Next release will be using Java 7.
+/edit: starting with 4.2.0 every release will now have a "x.y.z-java6-release" release as well
+
+
+[v3.0.2](https://search.maven.org/#artifactdetails%7Corg.codemonkey.simplejavamail%7Csimple-java-mail%7C3.0.2%7Cjar) (07-May-2016)
+
+- [#35](https://github.com/bbottema/simple-java-mail/issues/35): added proper .equals() and .toString() methods
+- [#34](https://github.com/bbottema/simple-java-mail/issues/34): Fixed bug when disposition is missing (assume it is an attachment)
+- other: added findbugs support internally
+
+
+[v3.0.1](https://search.maven.org/#artifactdetails%7Corg.codemonkey.simplejavamail%7Csimple-java-mail%7C3.0.1%7Cjar) (29-Feb-2016)
+
+ * [#31](https://github.com/bbottema/simple-java-mail/issues/31): Fixed EmailAddressCriteria.DEFAULT and clarified Javadoc
+
+
+[v3.0.0](https://search.maven.org/#artifactdetails%7Corg.codemonkey.simplejavamail%7Csimple-java-mail%7C3.0.0%7Cjar) (26-Feb-2016)
+
+ * [#30](https://github.com/bbottema/simple-java-mail/issues/30): Improved the demonstration class to include attachments and embedded images
+ * [#29](https://github.com/bbottema/simple-java-mail/issues/29): The package has been restructured for future maintenance, breaking backwards compatibility
+ * [#28](https://github.com/bbottema/simple-java-mail/issues/28): Re-added improved email validation facility
+ * [#22](https://github.com/bbottema/simple-java-mail/issues/22): Added conversion to and from MimeMessage. You can now consume and produce MimeMessage objects with simple-java-mail
+
+
+[v2.5.1](https://search.maven.org/#artifactdetails%7Corg.codemonkey.simplejavamail%7Csimple-java-mail%7C2.5.1%7Cjar) (19-Jan-2016)
+
+ * [#25](https://github.com/bbottema/simple-java-mail/issues/25): Added finally clause that will always close socket properly in case of an exception
+
+
+[v2.5](https://search.maven.org/#artifactdetails%7Corg.codemonkey.simplejavamail%7Csimple-java-mail%7C2.5%7Cjar) (19-Jan-2016)
+
+ * [#24](https://github.com/bbottema/simple-java-mail/issues/24): Updated dependencies SLF4J to 1.7.13 and switched to the updated javax mail package com.sun.mail:javax.mail 1.5.5
+
+
+[v2.4](https://search.maven.org/#artifactdetails%7Corg.codemonkey.simplejavamail%7Csimple-java-mail%7C2.4%7Cjar) (12-Aug-2015)
+
+ * [#21](https://github.com/bbottema/simple-java-mail/issues/21): builder API uses CC and BCC recipient types incorrectly
+
+
+[v2.3](https://search.maven.org/#artifactdetails%7Corg.codemonkey.simplejavamail%7Csimple-java-mail%7C2.3%7Cjar) (21-Jul-2015)
+
+ * [#19](https://github.com/bbottema/simple-java-mail/issues/19): supporting custom Session Properties now and emergency access to internal Session object.
+
+
+[v2.2](https://search.maven.org/#artifactdetails%7Corg.codemonkey.simplejavamail%7Csimple-java-mail%7C2.2%7Cjar) (09-May-2015)
+
+ * [#3](https://github.com/bbottema/simple-java-mail/issues/3): turned off email regex validation by default, with the option to turn it back on
+ * [#7](https://github.com/bbottema/simple-java-mail/issues/7): fixed NullPointerException when using your own Session instance
+ * [#10](https://github.com/bbottema/simple-java-mail/issues/10): properly UTF-8 encode recipient addresses
+ * [#14](https://github.com/bbottema/simple-java-mail/issues/14): switched to [SLF4J](https://www.slf4j.org/), so you can easily use your own selected logging framework
+ * [#17](https://github.com/bbottema/simple-java-mail/issues/17): Added [fluent interface](https://en.wikipedia.org/wiki/Builder_pattern) for building emails (see [here](https://www.simplejavamail.org/#section-builder-api) for an example)
+
+
+[v2.1](https://search.maven.org/#artifactdetails%7Corg.codemonkey.simplejavamail%7Csimple-java-mail%7C2.1%7Cjar) (09-Aug-2012)
+
+ * fixed character encoding for reply-to, from, to, body text and headers (to UTF-8)
+ * fixed bug where Recipient was not public resulting in uncompilable code when calling email.getRecipients()
+
+
+[v2.0](https://search.maven.org/#artifactdetails%7Corg.codemonkey.simplejavamail%7Csimple-java-mail%7C2.0%7Cjar) (20-Aug-2011)
+
+ * added support for adding open headers, such as 'X-Priority: 2'
+
+
+[v1.9.1](https://search.maven.org/#artifactdetails%7Corg.codemonkey.simplejavamail%7Csimple-java-mail%7C1.9.1%7Cjar) (08-Aug-2011)
+
+ * updated for Maven support
+
+
+v1.9 (6-Aug-2011)
+
+ * added support for JavaMail's reply-to address
+ * made port optional as to support port defaulting based on protocol
+ * added transport strategy default in the createSession method
+ * tightened up thrown exceptions (MailException instead of RuntimeException)
+ * added and fixed [Javadoc](https://www.javadoc.io/doc/org.simplejavamail/simple-java-mail)
+
+
+v1.8
+
+ * Added support for TLS (tested with gmail)
+
+
+v1.7 (22-Mar-2011)
+
+Added support for SSL! (tested with gmail)
+
+ * improved argument validation when creating a Mailer without preconfigured Session instance
+
+known possible issue: SSL self-signed certificates might not work (yet). Please let me know by e-mail or create a new issue
+
+
+v1.6
+
+Completed migration to Java Simple Mail project.
+
+ * removed all Vesijama references
+ * updated TestMail demonstration class for clarification
+ * updated readme.txt for test run instructions
+ * included log4j.properties
+
+
+v1.4 (15-Jan-2011)
+
+
+vX.X (26-Apr-2009)
+
+ * Initial upload to Google Code.
diff --git a/how to release.txt b/how to release.txt
index b9400e785..875ad5fbe 100644
--- a/how to release.txt
+++ b/how to release.txt
@@ -1,30 +1,66 @@
- 1. update release notes and github readme page (don't commit)
- 2. remove SNAPSHOT version
- 3. mvn -DperformRelease=true clean deploy
+Prerequisite:
+
+You need GPG installed (comes along with GIT installation in the \bin folder) and you need to create a keyring, used for signing artifacts.
+If you have an existing key, simply import it:
+
+gpg --allow-secret-key-import --import .gpg
+
+That, or you can install one of the binaries to import the key, from here: https://www.gnupg.org/download/index.html
+
+To import the keyring in a CI/CD environment (CircleCI, Azure Devops, Bamboo, Jenkins etc.), you need to import the keyring
+externally (or us a private Repo). Alternatively you can import the ASCII export of the key configured as a property secret
+so you can ECHO it to a file during the build. Once exposed as file, you can use it to sign:
+
+To generate the ASCII export of a key so you can store it a secret property in your build environment:
+ - gpg --no-default-keyring --armor --secret-keyring ./secring.gpg --keyring ./pubring.gpg --export-secret-key USER > secring.gpg.asc
+ - sed ':a;N;$!ba;s/\n/\\n/g' secring.gpg.asc, OR
+ - base64 encode the text
+
+To be able to have your CI/CD script also commit the new version, you need to add github.com's official host finger print.
+ - https://serverfault.com/a/701637/157338
+ - https://discuss.circleci.com/t/error-sending-to-agent-inappropriate-ioctl-for-device/17465/2
+ - https://medium.com/@Joachim8675309/generating-gpg-key-files-cc447431415a
+ - http://frankiesardo.github.io/posts/2015-04-19-automate-everything-with-circleci.html
+ - https://github.com/toknapp/arweave4s/blob/master/.circleci/config.yml
+ - https://serverfault.com/questions/447028/non-interactive-git-clone-ssh-fingerprint-prompt
+ - https://superuser.com/questions/232373/how-to-tell-git-which-private-key-to-use
+
+To release through CI/CD pipeline in CircleCI
+
+ 1. update release notes, RELEASE_HISTORY.md and the github readme page according to MAINTAINER_WORKFLOW.md, then push changes
+ 2. go to the CI/CD pipeline https://circleci.com/gh/bbottema/simple-java-mail
+ 3. select the version release needed
+
+To release manually:
+
+ 1. update release notes, RELEASE_HISTORY.md and the github readme page according to MAINTAINER_WORKFLOW.md (don't commit)
+ 2. remove SNAPSHOT version from the property
+ 4. mvn -DperformRelease=true clean deploy
(set password in settings.xml or use local pgp key password, for which the public key must have been sent to a public key server,
eg: gpg --keyserver hkp://keyserver.ubuntu.com --send-keys 05AC6403)
server needed in settings.xml (see below)
- 4. add new SNAPSHOT version and commit everything
-
-maven's settings.xml:
-
-
- ossrh
- sonatype user
- sonatype password
-
-
-To have a global gpg password so that it will use that automatically:
-
-
-
- gpg
-
- gpg
- letmein
-
-
-
-
- gpg
-
\ No newline at end of file
+ 5. Go to https://oss.sonatype.org and release the artifact so it is submitted to Maven Central
+ 6. add new SNAPSHOT version to the property, execute and commit everything
+
+ maven's settings.xml:
+
+
+ ossrh
+ sonatype user
+ sonatype password
+
+
+ To have a global gpg password so that it will use that automatically:
+
+
+
+ gpg
+
+ gpg
+ password
+
+
+
+
+ gpg
+
diff --git a/lib/activation.jar b/lib/activation.jar
deleted file mode 100644
index 29a59a9ee..000000000
Binary files a/lib/activation.jar and /dev/null differ
diff --git a/lib/mailapi-1.4.4.jar b/lib/mailapi-1.4.4.jar
deleted file mode 100644
index fc37e895b..000000000
Binary files a/lib/mailapi-1.4.4.jar and /dev/null differ
diff --git a/lib/smtp-1.4.4.jar b/lib/smtp-1.4.4.jar
deleted file mode 100644
index 90d4794de..000000000
Binary files a/lib/smtp-1.4.4.jar and /dev/null differ
diff --git a/modules/authenticated-socks-module/.gitignore b/modules/authenticated-socks-module/.gitignore
new file mode 100644
index 000000000..dc48b22fc
--- /dev/null
+++ b/modules/authenticated-socks-module/.gitignore
@@ -0,0 +1,2 @@
+*.iml
+target
\ No newline at end of file
diff --git a/LICENSE-2.0.txt b/modules/authenticated-socks-module/LICENSE-2.0.txt
similarity index 94%
rename from LICENSE-2.0.txt
rename to modules/authenticated-socks-module/LICENSE-2.0.txt
index 4ad04c3c0..d639b1e24 100644
--- a/LICENSE-2.0.txt
+++ b/modules/authenticated-socks-module/LICENSE-2.0.txt
@@ -185,18 +185,4 @@
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright 2016 Benny Bottema
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
+ identification within third-party archives.
\ No newline at end of file
diff --git a/modules/authenticated-socks-module/NOTICE.txt b/modules/authenticated-socks-module/NOTICE.txt
new file mode 100644
index 000000000..695f76510
--- /dev/null
+++ b/modules/authenticated-socks-module/NOTICE.txt
@@ -0,0 +1,11 @@
+ =========================================================================
+ == NOTICE file for use with the Apache License, Version 2.0 ==
+ =========================================================================
+
+ Simple Java Mail - Authenticated SOCKS module
+ Copyright (C) 2009 Benny Bottema (benny@bennybottema.com)
+ https://www.simplejavamail.org
+
+ This product uses no commercial products.
+
+ This product uses no external (Open Source) libraries:
diff --git a/modules/authenticated-socks-module/pom.xml b/modules/authenticated-socks-module/pom.xml
new file mode 100644
index 000000000..ed2fe5d9a
--- /dev/null
+++ b/modules/authenticated-socks-module/pom.xml
@@ -0,0 +1,31 @@
+
+
+
+ 4.0.0
+
+
+ org.simplejavamail
+ maven-master-project
+ 9.1.3
+ ../../pom.xml
+
+
+ authenticated-socks-module
+ jar
+ Simple Java Mail - Authenticated SOCKS module
+ Simple API, Complex Emails. Now with SOCKS5 support
+
+
+ org.simplejavamail.authenticatedsocks
+
+
+
+
+
+ org.simplejavamail
+ core-module
+ ${project.version}
+
+
+
diff --git a/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/AuthenticatedSocksHelper.java b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/AuthenticatedSocksHelper.java
new file mode 100644
index 000000000..6717516bd
--- /dev/null
+++ b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/AuthenticatedSocksHelper.java
@@ -0,0 +1,19 @@
+package org.simplejavamail.internal.authenticatedsockssupport;
+
+import org.jetbrains.annotations.NotNull;
+import org.simplejavamail.api.internal.authenticatedsockssupport.socks5server.AnonymousSocks5Server;
+import org.simplejavamail.api.mailer.config.ProxyConfig;
+import org.simplejavamail.internal.authenticatedsockssupport.socks5server.AnonymousSocks5ServerImpl;
+import org.simplejavamail.internal.modules.AuthenticatedSocksModule;
+
+import static org.simplejavamail.internal.util.Preconditions.checkNonEmptyArgument;
+
+@SuppressWarnings("unused")
+public class AuthenticatedSocksHelper implements AuthenticatedSocksModule {
+
+ @Override
+ public AnonymousSocks5Server createAnonymousSocks5Server(@NotNull ProxyConfig socksProxyConfig) {
+ final Integer proxyBridgePort = checkNonEmptyArgument(socksProxyConfig.getProxyBridgePort(), "proxyBridgePort");
+ return new AnonymousSocks5ServerImpl(new AuthenticatingSocks5Bridge(socksProxyConfig), proxyBridgePort);
+ }
+}
\ No newline at end of file
diff --git a/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/AuthenticatingSocks5Bridge.java b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/AuthenticatingSocks5Bridge.java
new file mode 100644
index 000000000..42d0eb47e
--- /dev/null
+++ b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/AuthenticatingSocks5Bridge.java
@@ -0,0 +1,60 @@
+package org.simplejavamail.internal.authenticatedsockssupport;
+
+import org.jetbrains.annotations.NotNull;
+import org.simplejavamail.api.internal.authenticatedsockssupport.common.Socks5Bridge;
+import org.simplejavamail.api.mailer.config.ProxyConfig;
+import org.simplejavamail.internal.authenticatedsockssupport.socks5client.ProxyCredentials;
+import org.simplejavamail.internal.authenticatedsockssupport.socks5client.Socks5;
+import org.simplejavamail.internal.authenticatedsockssupport.socks5client.SocksSocket;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+
+import static org.simplejavamail.internal.util.Preconditions.verifyNonnullOrEmpty;
+
+/**
+ * Please refer to {@link Socks5Bridge}.
+ */
+public class AuthenticatingSocks5Bridge implements Socks5Bridge {
+ private static final Logger LOGGER = LoggerFactory.getLogger("socks5bridge");
+
+ @NotNull private final ProxyConfig proxyConfig;
+ @NotNull private final String remoteProxyHost;
+ @NotNull private final Integer remoteProxyPort;
+
+ AuthenticatingSocks5Bridge(final ProxyConfig proxyConfig) {
+ this.proxyConfig = proxyConfig;
+ this.remoteProxyHost = verifyNonnullOrEmpty(proxyConfig.getRemoteProxyHost());
+ this.remoteProxyPort = verifyNonnullOrEmpty(proxyConfig.getRemoteProxyPort());
+ }
+
+ /**
+ * Refer to {@link Socks5Bridge#connect(String, InetAddress, int)}.
+ */
+ @Override
+ public Socket connect(final String sessionId, final InetAddress remoteServerAddress, final int remoteServerPort)
+ throws IOException {
+ return proxyConfig.requiresAuthentication() ?
+ createSocketAuthenticated(sessionId, remoteServerAddress, remoteServerPort) :
+ createSocketPlainAnonymous(sessionId, remoteServerAddress, remoteServerPort);
+ }
+
+ private Socket createSocketAuthenticated(final String sessionId, final InetAddress remoteServerAddress, final int remoteServerPort)
+ throws IOException {
+ LOGGER.info("SESSION[{}] bridging to remote proxy {}", sessionId, proxyConfig);
+ final Socks5 proxyAuth = new Socks5(new InetSocketAddress(remoteProxyHost, remoteProxyPort));
+ proxyAuth.setCredentials(new ProxyCredentials(proxyConfig.getUsername(), proxyConfig.getPassword()));
+ return new SocksSocket(proxyAuth, proxyAuth.createProxySocket(), new InetSocketAddress(remoteServerAddress, remoteServerPort));
+ }
+
+ private Socket createSocketPlainAnonymous(final String sessionId, final InetAddress remoteServerAddress, final int remoteServerPort)
+ throws IOException {
+ LOGGER.info("SESSION[{}] bridging anonymously to remote proxy {}:{}", sessionId, remoteProxyHost, remoteProxyPort);
+ final Socks5 socksProxyAnonymous = new Socks5(new InetSocketAddress(remoteProxyHost, remoteProxyPort));
+ return new SocksSocket(socksProxyAnonymous, new InetSocketAddress(remoteServerAddress, remoteServerPort));
+ }
+}
diff --git a/src/main/java/org/simplejavamail/mailer/internal/socks/common/SocksException.java b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/common/SocksException.java
similarity index 62%
rename from src/main/java/org/simplejavamail/mailer/internal/socks/common/SocksException.java
rename to modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/common/SocksException.java
index 89102d4dc..63f28611a 100644
--- a/src/main/java/org/simplejavamail/mailer/internal/socks/common/SocksException.java
+++ b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/common/SocksException.java
@@ -1,12 +1,11 @@
+package org.simplejavamail.internal.authenticatedsockssupport.common;
-
-package org.simplejavamail.mailer.internal.socks.common;
-
+@SuppressWarnings("serial")
public class SocksException extends RuntimeException {
-
- private static final String serverReplyMessage[] = { "General SOCKS server failure", "Connection not allowed by ruleset",
+
+ private static final String[] serverReplyMessage = {"General SOCKS server failure", "Connection not allowed by ruleset",
"Network " + "unreachable", "Host unreachable", "Connection refused", "TTL expired", "Command not " + "supported",
- "Address type not supported" };
+ "Address type not supported"};
public SocksException(final String msg) {
super(msg);
@@ -17,13 +16,12 @@ public SocksException(final String msg, final Exception e) {
}
public static SocksException serverReplyException(final byte reply) {
- int code = reply;
- code = code & 0xff;
- if (code < 0 || code > 0x08) {
+ int code = reply & 0xff;
+ if (code > 0x08) {
return new SocksException("Unknown reply");
}
code = code - 1;
return new SocksException(serverReplyMessage[code]);
}
-}
+}
\ No newline at end of file
diff --git a/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5client/KeyStoreInfo.java b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5client/KeyStoreInfo.java
new file mode 100644
index 000000000..ab3cbb44c
--- /dev/null
+++ b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5client/KeyStoreInfo.java
@@ -0,0 +1,42 @@
+package org.simplejavamail.internal.authenticatedsockssupport.socks5client;
+
+import static java.util.Objects.requireNonNull;
+
+@SuppressWarnings("SameParameterValue")
+class KeyStoreInfo {
+
+ private final String keyStorePath;
+ private final String password;
+ private final String type /*= "JKS"*/;
+
+ /**
+ * Delegates to {@link #KeyStoreInfo(String, String, String)} using "JKS" as type.
+ */
+ @SuppressWarnings("unused")
+ public KeyStoreInfo(final String keyStorePath, final String password) {
+ this(keyStorePath, password, "JKS");
+ }
+
+ public KeyStoreInfo(final String keyStorePath, final String password, final String type) {
+ this.keyStorePath = requireNonNull(keyStorePath, "Argument [keyStorePath] may not be null");
+ this.password = requireNonNull(password, "Argument [password] may not be null");
+ this.type = requireNonNull(type, "Argument [type] may not be null");
+ }
+
+ public String getKeyStorePath() {
+ return keyStorePath;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ @Override
+ public String toString() {
+ return "[KEY STORE] PATH:" + keyStorePath + " PASSWORD:xxx" + " TYPE:" + type;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5client/ProxyCredentials.java b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5client/ProxyCredentials.java
similarity index 61%
rename from src/main/java/org/simplejavamail/mailer/internal/socks/socks5client/ProxyCredentials.java
rename to modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5client/ProxyCredentials.java
index 04067037c..e832a8ec3 100644
--- a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5client/ProxyCredentials.java
+++ b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5client/ProxyCredentials.java
@@ -1,8 +1,6 @@
+package org.simplejavamail.internal.authenticatedsockssupport.socks5client;
-
-package org.simplejavamail.mailer.internal.socks.socks5client;
-
-import org.simplejavamail.internal.util.MiscUtil;
+import static java.util.Objects.requireNonNull;
public class ProxyCredentials {
@@ -15,7 +13,7 @@ public ProxyCredentials() {
public ProxyCredentials(final String username, final String password) {
this.username = username;
- this.password = MiscUtil.checkNotNull(password, "Argument [password] may not be null");
+ this.password = requireNonNull(password, "Argument [password] may not be null");
}
public String getUsername() {
diff --git a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5client/SSLConfiguration.java b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5client/SSLConfiguration.java
similarity index 72%
rename from src/main/java/org/simplejavamail/mailer/internal/socks/socks5client/SSLConfiguration.java
rename to modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5client/SSLConfiguration.java
index 2f1d17b2f..fecce60f6 100644
--- a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5client/SSLConfiguration.java
+++ b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5client/SSLConfiguration.java
@@ -1,9 +1,6 @@
+package org.simplejavamail.internal.authenticatedsockssupport.socks5client;
-
-package org.simplejavamail.mailer.internal.socks.socks5client;
-
-import org.simplejavamail.mailer.internal.socks.common.SocksException;
-import org.simplejavamail.internal.util.MiscUtil;
+import org.simplejavamail.internal.authenticatedsockssupport.common.SocksException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -13,9 +10,16 @@
import javax.net.ssl.TrustManagerFactory;
import java.io.FileInputStream;
import java.io.IOException;
+import java.security.KeyManagementException;
import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+
+import static java.util.Objects.requireNonNull;
-public class SSLConfiguration {
+class SSLConfiguration {
private static final Logger LOGGER = LoggerFactory.getLogger(SSLConfiguration.class);
@@ -23,15 +27,15 @@ public class SSLConfiguration {
private final KeyStoreInfo trustKeyStoreInfo;
@SuppressWarnings("SameParameterValue")
- public SSLConfiguration(final KeyStoreInfo keyStoreInfo, final KeyStoreInfo trustKeyStoreInfo) {
+ private SSLConfiguration(final KeyStoreInfo keyStoreInfo, final KeyStoreInfo trustKeyStoreInfo) {
this.keyStoreInfo = keyStoreInfo;
this.trustKeyStoreInfo = trustKeyStoreInfo;
}
public SSLSocketFactory getSSLSocketFactory()
throws SocksException {
- MiscUtil.checkNotNull(trustKeyStoreInfo, "trustKeyStoreInfo may not be null");
- FileInputStream s1 = null;
+ requireNonNull(trustKeyStoreInfo, "trustKeyStoreInfo may not be null");
+ FileInputStream s1 = null;
FileInputStream s2 = null;
try {
final SSLContext context = SSLContext.getInstance("SSL");
@@ -57,9 +61,8 @@ public SSLSocketFactory getSSLSocketFactory()
}
LOGGER.info("SSL: Trust key store:{}", trustKeyStoreInfo.getKeyStorePath());
return context.getSocketFactory();
- } catch (final Exception e) {
- LOGGER.error(e.getMessage(), e);
- throw new SocksException(e.getMessage());
+ } catch (IOException | KeyManagementException | KeyStoreException | NoSuchAlgorithmException | UnrecoverableKeyException | CertificateException e) {
+ throw new SocksException(e.getMessage(), e);
} finally {
tryCloseStream(s1);
tryCloseStream(s2);
diff --git a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5client/SSLSocks5.java b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5client/SSLSocks5.java
similarity index 94%
rename from src/main/java/org/simplejavamail/mailer/internal/socks/socks5client/SSLSocks5.java
rename to modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5client/SSLSocks5.java
index 9c85b8d71..c98aca3b7 100644
--- a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5client/SSLSocks5.java
+++ b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5client/SSLSocks5.java
@@ -1,6 +1,4 @@
-
-
-package org.simplejavamail.mailer.internal.socks.socks5client;
+package org.simplejavamail.internal.authenticatedsockssupport.socks5client;
import java.io.IOException;
import java.net.InetAddress;
diff --git a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5client/Socks5.java b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5client/Socks5.java
similarity index 77%
rename from src/main/java/org/simplejavamail/mailer/internal/socks/socks5client/Socks5.java
rename to modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5client/Socks5.java
index 04672cc9d..0a434769e 100644
--- a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5client/Socks5.java
+++ b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5client/Socks5.java
@@ -1,42 +1,40 @@
+package org.simplejavamail.internal.authenticatedsockssupport.socks5client;
-
-package org.simplejavamail.mailer.internal.socks.socks5client;
+import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.net.*;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+
+import static java.util.Objects.requireNonNull;
public class Socks5 {
private static final int SOCKS_DEFAULT_PORT = 1080;
- public static final byte AUTHENTICATION_SUCCEEDED = 0x00;
+ static final byte AUTHENTICATION_SUCCEEDED = 0x00;
+ @Nullable
private Socks5 chainProxy;
private ProxyCredentials credentials = new ProxyCredentials();
private InetAddress inetAddress;
+ @SuppressWarnings("UnusedAssignment")
private int port = SOCKS_DEFAULT_PORT;
+ @Nullable
private Socket proxySocket;
private SocksAuthenticationHelper socksAuthenticationHelper = new SocksAuthenticationHelper();
private boolean alwaysResolveAddressLocally = false;
- public Socks5(final InetSocketAddress socketAddress, final String username, final String password) {
- this(socketAddress);
- setCredentials(new ProxyCredentials(username, password));
- }
-
- public Socks5(final String host, final int port)
- throws UnknownHostException {
- this(InetAddress.getByName(host), port);
- }
-
Socks5(final InetAddress inetAddress, final int port) {
this(new InetSocketAddress(inetAddress, port));
}
@@ -46,19 +44,12 @@ public Socks5(final InetSocketAddress socketAddress) {
}
@SuppressWarnings("SameParameterValue")
- private Socks5(final Socks5 chainProxy, final InetSocketAddress socketAddress) {
+ private Socks5(@Nullable final Socks5 chainProxy, final InetSocketAddress socketAddress) {
inetAddress = socketAddress.getAddress();
port = socketAddress.getPort();
this.setChainProxy(chainProxy);
}
- public Socks5(final String host, final int port, final ProxyCredentials credentials)
- throws UnknownHostException {
- this.inetAddress = InetAddress.getByName(host);
- this.port = port;
- this.credentials = credentials;
- }
-
public void buildConnection()
throws IOException {
if (inetAddress == null) {
@@ -79,23 +70,23 @@ public void requestConnect(final String host, final int port)
throws IOException {
if (!alwaysResolveAddressLocally) {
// resolve address in SOCKS server
- SocksCommandSender.send(proxySocket, host, port);
+ SocksCommandSender.send(requireNonNull(proxySocket, "proxySocket"), host, port);
} else {
// resolve address in local.
final InetAddress address = InetAddress.getByName(host);
- SocksCommandSender.send(proxySocket, address, port);
+ SocksCommandSender.send(requireNonNull(proxySocket, "proxySocket"), address, port);
}
}
public void requestConnect(final InetAddress address, final int port)
throws IOException {
- SocksCommandSender.send(proxySocket, address, port);
+ SocksCommandSender.send(requireNonNull(proxySocket, "proxySocket"), address, port);
}
public void requestConnect(final SocketAddress address)
throws IOException {
- SocksCommandSender.send(proxySocket, address);
+ SocksCommandSender.send(requireNonNull(proxySocket, "proxySocket"), address);
}
public int getPort() {
@@ -107,22 +98,23 @@ Socks5 setPort(final int port) {
return this;
}
+ @Nullable
public Socket getProxySocket() {
return proxySocket;
}
- public void setProxySocket(final Socket proxySocket) {
+ public void setProxySocket(@Nullable final Socket proxySocket) {
this.proxySocket = proxySocket;
}
public InputStream getInputStream()
throws IOException {
- return proxySocket.getInputStream();
+ return requireNonNull(proxySocket, "proxySocket").getInputStream();
}
public OutputStream getOutputStream()
throws IOException {
- return proxySocket.getOutputStream();
+ return requireNonNull(proxySocket, "proxySocket").getOutputStream();
}
public ProxyCredentials getCredentials() {
@@ -150,11 +142,12 @@ public Socks5 copy() {
return socks5;
}
+ @Nullable
public Socks5 getChainProxy() {
return chainProxy;
}
- Socks5 setChainProxy(final Socks5 chainProxy) {
+ Socks5 setChainProxy(@Nullable final Socks5 chainProxy) {
this.chainProxy = chainProxy;
return this;
}
diff --git a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5client/SocksAuthenticationHelper.java b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5client/SocksAuthenticationHelper.java
similarity index 84%
rename from src/main/java/org/simplejavamail/mailer/internal/socks/socks5client/SocksAuthenticationHelper.java
rename to modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5client/SocksAuthenticationHelper.java
index dcbe99277..0877a299f 100644
--- a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5client/SocksAuthenticationHelper.java
+++ b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5client/SocksAuthenticationHelper.java
@@ -1,8 +1,6 @@
+package org.simplejavamail.internal.authenticatedsockssupport.socks5client;
-
-package org.simplejavamail.mailer.internal.socks.socks5client;
-
-import org.simplejavamail.mailer.internal.socks.common.SocksException;
+import org.simplejavamail.internal.authenticatedsockssupport.common.SocksException;
import org.simplejavamail.internal.util.MiscUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -13,6 +11,7 @@
import java.net.Socket;
import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.util.Objects.requireNonNull;
final class SocksAuthenticationHelper {
private static final Logger LOGGER = LoggerFactory.getLogger(SocksAuthenticationHelper.class);
@@ -40,12 +39,12 @@ public static boolean shouldAuthenticate(final Socket socket)
outputStream.write(bufferSent);
outputStream.flush();
- LOGGER.trace("{}", MiscUtil.buildLogString(bufferSent, false));
+ LOGGER.trace("{}", MiscUtil.buildLogStringForSOCKSCommunication(bufferSent, false));
// Received data.
final InputStream inputStream = socket.getInputStream();
final byte[] receivedData = read2Bytes(inputStream);
- LOGGER.trace("{}", MiscUtil.buildLogString(receivedData, true));
+ LOGGER.trace("{}", MiscUtil.buildLogStringForSOCKSCommunication(receivedData, true));
if (receivedData[0] != (int) SOCKS_VERSION) {
throw new SocksException("Remote server don't support SOCKS5");
}
@@ -58,8 +57,8 @@ public static boolean shouldAuthenticate(final Socket socket)
public static void performUserPasswordAuthentication(final Socks5 socksProxy)
throws IOException {
- MiscUtil.checkNotNull(socksProxy, "Argument [socksProxy] may not be null");
- final ProxyCredentials credentials = socksProxy.getCredentials();
+ requireNonNull(socksProxy, "Argument [socksProxy] may not be null");
+ final ProxyCredentials credentials = socksProxy.getCredentials();
if (credentials == null) {
throw new SocksException("Need Username/Password authentication");
}
@@ -83,12 +82,12 @@ public static void performUserPasswordAuthentication(final Socks5 socksProxy)
outputStream.write(bufferSent);
outputStream.flush();
// logger send bytes
- LOGGER.trace("{}", MiscUtil.buildLogString(bufferSent, false));
+ LOGGER.trace("{}", MiscUtil.buildLogStringForSOCKSCommunication(bufferSent, false));
final byte[] authenticationResult = new byte[2];
checkEnd(inputStream.read(authenticationResult));
// logger
- LOGGER.trace("{}", MiscUtil.buildLogString(authenticationResult, true));
+ LOGGER.trace("{}", MiscUtil.buildLogStringForSOCKSCommunication(authenticationResult, true));
if (authenticationResult[1] != Socks5.AUTHENTICATION_SUCCEEDED) {
// Close connection if authentication is failed.
diff --git a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5client/SocksCommandSender.java b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5client/SocksCommandSender.java
similarity index 87%
rename from src/main/java/org/simplejavamail/mailer/internal/socks/socks5client/SocksCommandSender.java
rename to modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5client/SocksCommandSender.java
index 186631004..f0e376771 100644
--- a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5client/SocksCommandSender.java
+++ b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5client/SocksCommandSender.java
@@ -1,9 +1,8 @@
+package org.simplejavamail.internal.authenticatedsockssupport.socks5client;
-
-package org.simplejavamail.mailer.internal.socks.socks5client;
-
+import org.jetbrains.annotations.NotNull;
+import org.simplejavamail.internal.authenticatedsockssupport.common.SocksException;
import org.simplejavamail.internal.util.MiscUtil;
-import org.simplejavamail.mailer.internal.socks.common.SocksException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -39,12 +38,12 @@ final class SocksCommandSender {
private static final byte ATYPE_IPV6 = 0x04;
private static final int REP_SUCCEEDED = 0x00;
- public static void send(final Socket socket, final InetAddress address, final int port)
+ public static void send(@NotNull final Socket socket, final InetAddress address, final int port)
throws IOException {
send(socket, new InetSocketAddress(address, port));
}
- public static void send(final Socket socket, final SocketAddress socketAddress)
+ public static void send(@NotNull final Socket socket, final SocketAddress socketAddress)
throws IOException {
if (!(socketAddress instanceof InetSocketAddress)) {
throw new IllegalArgumentException("Unsupported address type");
@@ -79,13 +78,13 @@ public static void send(final Socket socket, final SocketAddress socketAddress)
outputStream.write(bufferSent);
outputStream.flush();
- LOGGER.trace("{}", MiscUtil.buildLogString(bufferSent, false));
+ LOGGER.trace("{}", MiscUtil.buildLogStringForSOCKSCommunication(bufferSent, false));
checkServerReply(inputStream);
}
- public static void send(final Socket socket, final String host, final int port)
- throws IOException {
+ public static void send(@NotNull final Socket socket, final String host, final int port)
+ throws IOException, SocksException {
final InputStream inputStream = socket.getInputStream();
final OutputStream outputStream = socket.getOutputStream();
final int lengthOfHost = host.getBytes(UTF_8).length;
@@ -103,13 +102,13 @@ public static void send(final Socket socket, final String host, final int port)
outputStream.write(bufferSent);
outputStream.flush();
- LOGGER.trace("{}", MiscUtil.buildLogString(bufferSent, false));
+ LOGGER.trace("{}", MiscUtil.buildLogStringForSOCKSCommunication(bufferSent, false));
checkServerReply(inputStream);
}
private static void checkServerReply(final InputStream inputStream)
- throws IOException {
+ throws IOException, SocksException {
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
int temp = 0;
for (int i = 0; i < 4; i++) {
@@ -140,7 +139,7 @@ private static void checkServerReply(final InputStream inputStream)
throw new SocksException("Address type not support, type value: " + addressType);
}
final byte[] receivedData = byteArrayOutputStream.toByteArray();
- LOGGER.trace("{}", MiscUtil.buildLogString(receivedData, true));
+ LOGGER.trace("{}", MiscUtil.buildLogStringForSOCKSCommunication(receivedData, true));
final byte[] addressBytes;
final byte[] portBytes = new byte[2];
diff --git a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5client/SocksSocket.java b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5client/SocksSocket.java
similarity index 69%
rename from src/main/java/org/simplejavamail/mailer/internal/socks/socks5client/SocksSocket.java
rename to modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5client/SocksSocket.java
index 3495efd9a..0c6122eb2 100644
--- a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5client/SocksSocket.java
+++ b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5client/SocksSocket.java
@@ -1,20 +1,25 @@
+package org.simplejavamail.internal.authenticatedsockssupport.socks5client;
-
-package org.simplejavamail.mailer.internal.socks.socks5client;
-
-import org.simplejavamail.mailer.internal.socks.common.SocksException;
-import org.simplejavamail.internal.util.MiscUtil;
+import org.jetbrains.annotations.NotNull;
+import org.simplejavamail.internal.authenticatedsockssupport.common.SocksException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.net.*;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.net.UnknownHostException;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.List;
+import static java.util.Objects.requireNonNull;
+
public class SocksSocket extends Socket {
private static final Logger LOGGER = LoggerFactory.getLogger(SocksSocket.class);
@@ -29,9 +34,9 @@ public class SocksSocket extends Socket {
private SocksSocket(final Socks5 proxy, final String remoteServerHost, final int remoteServerPort)
throws IOException {
- this.proxy = MiscUtil.checkNotNull(proxy, "Argument [proxy] may not be null").copy();
+ this.proxy = requireNonNull(proxy, "Argument [proxy] may not be null").copy();
this.proxy.setProxySocket(proxySocket);
- this.remoteServerHost = MiscUtil.checkNotNull(remoteServerHost, "Argument [remoteServerHost] may not be null");
+ this.remoteServerHost = requireNonNull(remoteServerHost, "Argument [remoteServerHost] may not be null");
this.remoteServerPort = remoteServerPort;
this.proxy.buildConnection();
proxySocket = this.proxy.getProxySocket();
@@ -46,9 +51,9 @@ private SocksSocket(final Socks5 proxy, final InetAddress address, final int por
public SocksSocket(final Socks5 proxy, final InetSocketAddress socketAddress)
throws IOException {
- MiscUtil.checkNotNull(proxy, "Argument [proxy] may not be null");
- MiscUtil.checkNotNull(socketAddress, "Argument [socketAddress] may not be null");
- this.proxy = proxy.copy();
+ requireNonNull(proxy, "Argument [proxy] may not be null");
+ requireNonNull(socketAddress, "Argument [socketAddress] may not be null");
+ this.proxy = proxy.copy();
this.remoteServerHost = socketAddress.getHostString();
this.remoteServerPort = socketAddress.getPort();
this.proxy.buildConnection();
@@ -71,9 +76,9 @@ public SocksSocket(final Socks5 proxy, final Socket proxySocket, final InetSocke
@SuppressWarnings("WeakerAccess")
public SocksSocket(final Socks5 proxy, final Socket proxySocket) {
- MiscUtil.checkNotNull(proxy, "Argument [proxy] may not be null");
- MiscUtil.checkNotNull(proxySocket, "Argument [proxySocket] may not be null");
- if (proxySocket.isConnected()) {
+ requireNonNull(proxy, "Argument [proxy] may not be null");
+ requireNonNull(proxySocket, "Argument [proxySocket] may not be null");
+ if (proxySocket.isConnected()) {
throw new IllegalArgumentException("Proxy socket should be unconnected");
}
this.proxySocket = proxySocket;
@@ -95,7 +100,7 @@ private void initProxyChain()
Socks5 pre = proxy;
for (final Socks5 chain : proxyChain) {
pre.requestConnect(chain.getInetAddress(), chain.getPort());
- proxy.getChainProxy().buildConnection();
+ requireNonNull(proxy.getChainProxy(), "chainProxy").buildConnection();
pre = chain;
}
}
@@ -119,7 +124,7 @@ public void connect(final SocketAddress endpoint, final int timeout)
remoteServerHost = ((InetSocketAddress) endpoint).getHostName();
remoteServerPort = ((InetSocketAddress) endpoint).getPort();
- proxy.getProxySocket().setSoTimeout(timeout);
+ getProxySocket().setSoTimeout(timeout);
proxy.buildConnection();
initProxyChain();
proxy.requestConnect(endpoint);
@@ -129,19 +134,19 @@ public void connect(final SocketAddress endpoint, final int timeout)
@Override
public InputStream getInputStream()
throws IOException {
- return proxy.getProxySocket().getInputStream();
+ return getProxySocket().getInputStream();
}
@Override
public OutputStream getOutputStream()
throws IOException {
- return proxy.getProxySocket().getOutputStream();
+ return getProxySocket().getOutputStream();
}
@Override
public void bind(final SocketAddress bindpoint)
throws IOException {
- proxy.getProxySocket().bind(bindpoint);
+ getProxySocket().bind(bindpoint);
}
@Override
@@ -155,7 +160,7 @@ public InetAddress getInetAddress() {
@Override
public InetAddress getLocalAddress() {
- return proxy.getProxySocket().getLocalAddress();
+ return getProxySocket().getLocalAddress();
}
@SuppressWarnings("SuspiciousGetterSetter")
@@ -166,136 +171,136 @@ public int getPort() {
@Override
public int getLocalPort() {
- return proxy.getProxySocket().getLocalPort();
+ return getProxySocket().getLocalPort();
}
@Override
public SocketAddress getRemoteSocketAddress() {
- return proxy.getProxySocket().getRemoteSocketAddress();
+ return getProxySocket().getRemoteSocketAddress();
}
@Override
public SocketAddress getLocalSocketAddress() {
- return proxy.getProxySocket().getLocalSocketAddress();
+ return getProxySocket().getLocalSocketAddress();
}
@Override
public SocketChannel getChannel() {
- return proxy.getProxySocket().getChannel();
+ return getProxySocket().getChannel();
}
@Override
public boolean getTcpNoDelay()
throws SocketException {
- return proxy.getProxySocket().getTcpNoDelay();
+ return getProxySocket().getTcpNoDelay();
}
@Override
public void setTcpNoDelay(final boolean on)
throws SocketException {
- proxy.getProxySocket().setTcpNoDelay(on);
+ getProxySocket().setTcpNoDelay(on);
}
@Override
public void setSoLinger(final boolean on, final int linger)
throws SocketException {
- proxy.getProxySocket().setSoLinger(on, linger);
+ getProxySocket().setSoLinger(on, linger);
}
@Override
public int getSoLinger()
throws SocketException {
- return proxy.getProxySocket().getSoLinger();
+ return getProxySocket().getSoLinger();
}
@Override
public void sendUrgentData(final int data)
throws IOException {
- proxy.getProxySocket().sendUrgentData(data);
+ getProxySocket().sendUrgentData(data);
}
@Override
public boolean getOOBInline()
throws SocketException {
- return proxy.getProxySocket().getOOBInline();
+ return getProxySocket().getOOBInline();
}
@Override
public void setOOBInline(final boolean on)
throws SocketException {
- proxy.getProxySocket().setOOBInline(on);
+ getProxySocket().setOOBInline(on);
}
@Override
public synchronized int getSoTimeout()
throws SocketException {
- return proxy.getProxySocket().getSoTimeout();
+ return getProxySocket().getSoTimeout();
}
@Override
public synchronized void setSoTimeout(final int timeout)
throws SocketException {
- proxy.getProxySocket().setSoTimeout(timeout);
+ getProxySocket().setSoTimeout(timeout);
}
@Override
public synchronized int getSendBufferSize()
throws SocketException {
- return proxy.getProxySocket().getSendBufferSize();
+ return getProxySocket().getSendBufferSize();
}
@Override
public synchronized void setSendBufferSize(final int size)
throws SocketException {
- proxy.getProxySocket().setSendBufferSize(size);
+ getProxySocket().setSendBufferSize(size);
}
@Override
public synchronized int getReceiveBufferSize()
throws SocketException {
- return proxy.getProxySocket().getReceiveBufferSize();
+ return getProxySocket().getReceiveBufferSize();
}
@Override
public synchronized void setReceiveBufferSize(final int size)
throws SocketException {
- proxy.getProxySocket().setReceiveBufferSize(size);
+ getProxySocket().setReceiveBufferSize(size);
}
@Override
public boolean getKeepAlive()
throws SocketException {
- return proxy.getProxySocket().getKeepAlive();
+ return getProxySocket().getKeepAlive();
}
@Override
public void setKeepAlive(final boolean on)
throws SocketException {
- proxy.getProxySocket().setKeepAlive(on);
+ getProxySocket().setKeepAlive(on);
}
@Override
public int getTrafficClass()
throws SocketException {
- return proxy.getProxySocket().getTrafficClass();
+ return getProxySocket().getTrafficClass();
}
@Override
public void setTrafficClass(final int tc)
throws SocketException {
- proxy.getProxySocket().setTrafficClass(tc);
+ getProxySocket().setTrafficClass(tc);
}
@Override
public boolean getReuseAddress()
throws SocketException {
- return proxy.getProxySocket().getReuseAddress();
+ return getProxySocket().getReuseAddress();
}
@Override
public void setReuseAddress(final boolean on)
throws SocketException {
- proxy.getProxySocket().setReuseAddress(on);
+ getProxySocket().setReuseAddress(on);
}
@Override
@@ -310,43 +315,47 @@ public synchronized void close()
@Override
public void shutdownInput()
throws IOException {
- proxy.getProxySocket().shutdownInput();
+ getProxySocket().shutdownInput();
}
@Override
public void shutdownOutput()
throws IOException {
- proxy.getProxySocket().shutdownOutput();
+ getProxySocket().shutdownOutput();
}
@Override
public boolean isConnected() {
- return proxy.getProxySocket().isConnected();
+ return getProxySocket().isConnected();
}
@Override
public boolean isBound() {
- return proxy.getProxySocket().isBound();
+ return getProxySocket().isBound();
}
@Override
public boolean isClosed() {
- return proxy.getProxySocket().isClosed();
+ return getProxySocket().isClosed();
}
@Override
public boolean isInputShutdown() {
- return proxy.getProxySocket().isInputShutdown();
+ return getProxySocket().isInputShutdown();
}
@Override
public boolean isOutputShutdown() {
- return proxy.getProxySocket().isOutputShutdown();
+ return getProxySocket().isOutputShutdown();
}
@Override
public void setPerformancePreferences(final int connectionTime, final int latency, final int bandwidth) {
- proxy.getProxySocket().setPerformancePreferences(connectionTime, latency, bandwidth);
+ getProxySocket().setPerformancePreferences(connectionTime, latency, bandwidth);
}
-}
+ @NotNull
+ private Socket getProxySocket() {
+ return requireNonNull(proxy.getProxySocket(), "proxySocket");
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5server/AnonymousSocks5Server.java b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5server/AnonymousSocks5ServerImpl.java
similarity index 70%
rename from src/main/java/org/simplejavamail/mailer/internal/socks/socks5server/AnonymousSocks5Server.java
rename to modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5server/AnonymousSocks5ServerImpl.java
index fc2bccae1..233082124 100644
--- a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5server/AnonymousSocks5Server.java
+++ b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5server/AnonymousSocks5ServerImpl.java
@@ -1,9 +1,4 @@
-package org.simplejavamail.mailer.internal.socks.socks5server;
-
-import org.simplejavamail.mailer.internal.socks.common.Socks5Bridge;
-import org.simplejavamail.mailer.internal.socks.common.SocksException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+package org.simplejavamail.internal.authenticatedsockssupport.socks5server;
import java.io.IOException;
import java.net.InetSocketAddress;
@@ -12,32 +7,36 @@
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import org.simplejavamail.api.internal.authenticatedsockssupport.common.Socks5Bridge;
+import org.simplejavamail.api.internal.authenticatedsockssupport.socks5server.AnonymousSocks5Server;
+import org.simplejavamail.internal.authenticatedsockssupport.common.SocksException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
/**
- * SOCKS server that accepts anonymous connections from JavaMail.
- *
- * Java Mail only support anonymous SOCKS proxies; in order to support authenticated proxies, we need to create a man-in-the-middle: which is the
- * {@link AnonymousSocks5Server}.
+ * @see AnonymousSocks5Server
*/
-public class AnonymousSocks5Server implements Runnable {
-
+public class AnonymousSocks5ServerImpl implements AnonymousSocks5Server {
+
private static final Logger LOGGER = LoggerFactory.getLogger(AnonymousSocks5Server.class);
-
+
private final Socks5Bridge socks5Bridge;
private final int proxyBridgePort;
-
+
private ExecutorService threadPool;
private ServerSocket serverSocket;
private boolean stopping = false;
private boolean running = false;
-
- public AnonymousSocks5Server(final Socks5Bridge socks5Bridge, final int proxyBridgePort) {
+
+ public AnonymousSocks5ServerImpl(final Socks5Bridge socks5Bridge, final int proxyBridgePort) {
this.socks5Bridge = socks5Bridge;
this.proxyBridgePort = proxyBridgePort;
}
-
+
/**
- * Binds the port and starts a thread to listen to incoming proxy connections from JavaMail.
+ * @see AnonymousSocks5Server#start()
*/
+ @Override
public void start() {
if (running) {
throw new IllegalStateException("server already running!");
@@ -53,7 +52,8 @@ public void start() {
}
new Thread(this).start();
}
-
+
+ @Override
public void stop() {
stopping = true;
try {
@@ -62,13 +62,14 @@ public void stop() {
throw new SocksException(e.getMessage(), e);
}
}
-
+
@Override
public void run() {
LOGGER.info("Starting proxy server at port {}", serverSocket.getLocalPort());
while (!stopping) {
try {
LOGGER.info("waiting for new connection...");
+ @SuppressWarnings("SocketOpenedButNotSafelyClosed") // socket is closed elsewhere
final Socket socket = serverSocket.accept();
socket.setSoTimeout(10000);
threadPool.execute(new Socks5Handler(new SocksSession(socket), socks5Bridge));
@@ -81,9 +82,9 @@ public void run() {
running = false;
stopping = false;
}
-
+
private void checkIoException(final Exception e) {
- if (e.getMessage().equals("socket closed")) {
+ if (e.getMessage().equalsIgnoreCase("socket closed")) {
LOGGER.debug("socket closed");
} else {
running = false;
@@ -91,12 +92,22 @@ private void checkIoException(final Exception e) {
throw new SocksException("server crashed...", e);
}
}
-
+
+ @Override
public boolean isStopping() {
return stopping;
}
-
+
+ @Override
public boolean isRunning() {
return running;
}
+
+ @Override
+ public int getLocalPort() {
+ if (serverSocket == null) {
+ return -1;
+ }
+ return serverSocket.getLocalPort();
+ }
}
\ No newline at end of file
diff --git a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5server/Socks5Handler.java b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5server/Socks5Handler.java
similarity index 85%
rename from src/main/java/org/simplejavamail/mailer/internal/socks/socks5server/Socks5Handler.java
rename to modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5server/Socks5Handler.java
index 2d7bb4ca1..6669f33db 100644
--- a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5server/Socks5Handler.java
+++ b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5server/Socks5Handler.java
@@ -1,12 +1,12 @@
-package org.simplejavamail.mailer.internal.socks.socks5server;
-
-import org.simplejavamail.mailer.internal.socks.common.Socks5Bridge;
-import org.simplejavamail.mailer.internal.socks.common.SocksException;
-import org.simplejavamail.mailer.internal.socks.socks5server.io.SocketPipe;
-import org.simplejavamail.mailer.internal.socks.socks5server.msg.CommandMessage;
-import org.simplejavamail.mailer.internal.socks.socks5server.msg.CommandResponseMessage;
-import org.simplejavamail.mailer.internal.socks.socks5server.msg.MethodSelectionMessage;
-import org.simplejavamail.mailer.internal.socks.socks5server.msg.ServerReply;
+package org.simplejavamail.internal.authenticatedsockssupport.socks5server;
+
+import org.simplejavamail.api.internal.authenticatedsockssupport.common.Socks5Bridge;
+import org.simplejavamail.internal.authenticatedsockssupport.common.SocksException;
+import org.simplejavamail.internal.authenticatedsockssupport.socks5server.io.SocketPipe;
+import org.simplejavamail.internal.authenticatedsockssupport.socks5server.msg.CommandMessage;
+import org.simplejavamail.internal.authenticatedsockssupport.socks5server.msg.CommandResponseMessage;
+import org.simplejavamail.internal.authenticatedsockssupport.socks5server.msg.MethodSelectionMessage;
+import org.simplejavamail.internal.authenticatedsockssupport.socks5server.msg.ServerReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -87,6 +87,7 @@ private void doConnect(final SocksSession session, final CommandMessage commandM
bindPort = socket.getLocalPort();
reply = ServerReply.SUCCEEDED;
} catch (final IOException e) {
+ //noinspection IfCanBeSwitch
if (e.getMessage().equals("Connection refused")) {
reply = ServerReply.CONNECTION_REFUSED;
} else if (e.getMessage().equals("Operation timed out")) {
diff --git a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5server/SocksSession.java b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5server/SocksSession.java
similarity index 96%
rename from src/main/java/org/simplejavamail/mailer/internal/socks/socks5server/SocksSession.java
rename to modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5server/SocksSession.java
index 4cb045546..c9eee1a23 100644
--- a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5server/SocksSession.java
+++ b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5server/SocksSession.java
@@ -1,4 +1,4 @@
-package org.simplejavamail.mailer.internal.socks.socks5server;
+package org.simplejavamail.internal.authenticatedsockssupport.socks5server;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5server/io/SocketPipe.java b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5server/io/SocketPipe.java
similarity index 93%
rename from src/main/java/org/simplejavamail/mailer/internal/socks/socks5server/io/SocketPipe.java
rename to modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5server/io/SocketPipe.java
index ae8e8f486..16111f1d2 100644
--- a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5server/io/SocketPipe.java
+++ b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5server/io/SocketPipe.java
@@ -1,4 +1,4 @@
-package org.simplejavamail.mailer.internal.socks.socks5server.io;
+package org.simplejavamail.internal.authenticatedsockssupport.socks5server.io;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -8,7 +8,7 @@
/**
* The class SocketPipe represents pipe that can transfer data from one socket to another socket. The tow socket should be
- * connected sockets. If any of the them occurred error the pipe will close all of them.
+ * connected sockets. If any error occurred, the pipe will close all of them.
*/
public class SocketPipe {
diff --git a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5server/io/StreamPipe.java b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5server/io/StreamPipe.java
similarity index 94%
rename from src/main/java/org/simplejavamail/mailer/internal/socks/socks5server/io/StreamPipe.java
rename to modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5server/io/StreamPipe.java
index edbfe9066..d09dcea0b 100644
--- a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5server/io/StreamPipe.java
+++ b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5server/io/StreamPipe.java
@@ -1,4 +1,4 @@
-package org.simplejavamail.mailer.internal.socks.socks5server.io;
+package org.simplejavamail.internal.authenticatedsockssupport.socks5server.io;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -10,7 +10,7 @@
import java.util.List;
/**
- * The class StreamPipe represents a pipe the can transfer data source a input stream destination a output stream.
+ * The class StreamPipe represents a pipe the can transfer data source an input stream destination an output stream.
*/
class StreamPipe implements Runnable {
diff --git a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5server/msg/AddressType.java b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5server/msg/AddressType.java
similarity index 75%
rename from src/main/java/org/simplejavamail/mailer/internal/socks/socks5server/msg/AddressType.java
rename to modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5server/msg/AddressType.java
index d586d6335..8b6a62ffb 100644
--- a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5server/msg/AddressType.java
+++ b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5server/msg/AddressType.java
@@ -1,4 +1,4 @@
-package org.simplejavamail.mailer.internal.socks.socks5server.msg;
+package org.simplejavamail.internal.authenticatedsockssupport.socks5server.msg;
final class AddressType {
diff --git a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5server/msg/CommandMessage.java b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5server/msg/CommandMessage.java
similarity index 82%
rename from src/main/java/org/simplejavamail/mailer/internal/socks/socks5server/msg/CommandMessage.java
rename to modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5server/msg/CommandMessage.java
index 44e3b51fc..a34f5ccc8 100644
--- a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5server/msg/CommandMessage.java
+++ b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5server/msg/CommandMessage.java
@@ -1,6 +1,6 @@
-package org.simplejavamail.mailer.internal.socks.socks5server.msg;
+package org.simplejavamail.internal.authenticatedsockssupport.socks5server.msg;
-import org.simplejavamail.mailer.internal.socks.common.SocksException;
+import org.simplejavamail.internal.authenticatedsockssupport.common.SocksException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -10,7 +10,6 @@
import java.net.UnknownHostException;
import static java.nio.charset.StandardCharsets.UTF_8;
-import static org.simplejavamail.mailer.internal.socks.socks5server.msg.StreamUtil.checkEnd;
public class CommandMessage {
@@ -28,11 +27,11 @@ public void read(final InputStream inputStream)
throws IOException {
LOGGER.trace("CommandMessage.read");
- checkEnd(inputStream.read()); // version, unused
- command = checkEnd(inputStream.read());
+ StreamUtil.checkEnd(inputStream.read()); // version, unused
+ command = StreamUtil.checkEnd(inputStream.read());
- checkEnd(inputStream.read());
- final int addressType = checkEnd(inputStream.read());
+ StreamUtil.checkEnd(inputStream.read());
+ final int addressType = StreamUtil.checkEnd(inputStream.read());
if (!AddressType.isSupport(addressType) && socksServerReplyException == null) {
socksServerReplyException = new SocksServerReplyException(ServerReply.ADDRESS_TYPE_NOT_SUPPORTED);
@@ -46,7 +45,7 @@ public void read(final InputStream inputStream)
break;
case AddressType.DOMAIN_NAME:
- final int domainLength = checkEnd(inputStream.read());
+ final int domainLength = StreamUtil.checkEnd(inputStream.read());
if (domainLength < 1) {
throw new SocksException("Length of domain must great than 0");
}
@@ -79,7 +78,7 @@ private static byte[] read(final InputStream inputStream, final int length)
throws IOException {
final byte[] bytes = new byte[length];
for (int i = 0; i < length; i++) {
- bytes[i] = (byte) checkEnd(inputStream.read());
+ bytes[i] = (byte) StreamUtil.checkEnd(inputStream.read());
}
return bytes;
}
diff --git a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5server/msg/CommandResponseMessage.java b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5server/msg/CommandResponseMessage.java
similarity index 88%
rename from src/main/java/org/simplejavamail/mailer/internal/socks/socks5server/msg/CommandResponseMessage.java
rename to modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5server/msg/CommandResponseMessage.java
index 26b531c06..baaaede8f 100644
--- a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5server/msg/CommandResponseMessage.java
+++ b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5server/msg/CommandResponseMessage.java
@@ -1,6 +1,6 @@
-package org.simplejavamail.mailer.internal.socks.socks5server.msg;
+package org.simplejavamail.internal.authenticatedsockssupport.socks5server.msg;
-import org.simplejavamail.mailer.internal.socks.socks5server.Socks5Handler;
+import org.simplejavamail.internal.authenticatedsockssupport.socks5server.Socks5Handler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5server/msg/MethodSelectionMessage.java b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5server/msg/MethodSelectionMessage.java
similarity index 58%
rename from src/main/java/org/simplejavamail/mailer/internal/socks/socks5server/msg/MethodSelectionMessage.java
rename to modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5server/msg/MethodSelectionMessage.java
index 34ef0667f..d35fb7d4d 100644
--- a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5server/msg/MethodSelectionMessage.java
+++ b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5server/msg/MethodSelectionMessage.java
@@ -1,4 +1,4 @@
-package org.simplejavamail.mailer.internal.socks.socks5server.msg;
+package org.simplejavamail.internal.authenticatedsockssupport.socks5server.msg;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -6,8 +6,6 @@
import java.io.IOException;
import java.io.InputStream;
-import static org.simplejavamail.mailer.internal.socks.socks5server.msg.StreamUtil.checkEnd;
-
public final class MethodSelectionMessage {
private static final Logger LOGGER = LoggerFactory.getLogger(MethodSelectionMessage.class);
@@ -15,10 +13,10 @@ public final class MethodSelectionMessage {
public static int readVersion(final InputStream inputStream)
throws IOException {
LOGGER.trace("MethodSelectionMessage.read");
- final int version = checkEnd(inputStream.read());
- final int methodNum = checkEnd(inputStream.read());
+ final int version = StreamUtil.checkEnd(inputStream.read());
+ final int methodNum = StreamUtil.checkEnd(inputStream.read());
for (int i = 0; i < methodNum; i++) {
- checkEnd(inputStream.read()); // read method byte
+ StreamUtil.checkEnd(inputStream.read()); // read method byte
}
return version;
}
diff --git a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5server/msg/ServerReply.java b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5server/msg/ServerReply.java
similarity index 70%
rename from src/main/java/org/simplejavamail/mailer/internal/socks/socks5server/msg/ServerReply.java
rename to modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5server/msg/ServerReply.java
index 4884e4e02..a516092cc 100644
--- a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5server/msg/ServerReply.java
+++ b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5server/msg/ServerReply.java
@@ -1,7 +1,9 @@
-package org.simplejavamail.mailer.internal.socks.socks5server.msg;
+package org.simplejavamail.internal.authenticatedsockssupport.socks5server.msg;
+
+import org.jetbrains.annotations.Nullable;
/**
- * The enumeration ServerReply represents reply of servers will SOCKS client send a command request to the SOCKS server.
+ * The enumeration ServerReply represents reply of servers when a SOCKS client sends a command request to the SOCKS server.
*/
public enum ServerReply {
@@ -21,9 +23,10 @@ public enum ServerReply {
private final byte value;
+ @Nullable
private final String errorMessage;
- ServerReply(final int value, final String errorMessage) {
+ ServerReply(final int value, @Nullable final String errorMessage) {
this.value = (byte) value;
this.errorMessage = errorMessage;
}
@@ -32,7 +35,8 @@ public byte getValue() {
return value;
}
+ @Nullable
public String getErrorMessage() {
return errorMessage;
}
-}
+}
\ No newline at end of file
diff --git a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5server/msg/SocksServerReplyException.java b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5server/msg/SocksServerReplyException.java
similarity index 62%
rename from src/main/java/org/simplejavamail/mailer/internal/socks/socks5server/msg/SocksServerReplyException.java
rename to modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5server/msg/SocksServerReplyException.java
index 173a8109e..2c312420e 100644
--- a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5server/msg/SocksServerReplyException.java
+++ b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5server/msg/SocksServerReplyException.java
@@ -1,7 +1,8 @@
-package org.simplejavamail.mailer.internal.socks.socks5server.msg;
+package org.simplejavamail.internal.authenticatedsockssupport.socks5server.msg;
-import org.simplejavamail.mailer.internal.socks.common.SocksException;
+import org.simplejavamail.internal.authenticatedsockssupport.common.SocksException;
+@SuppressWarnings("serial")
public class SocksServerReplyException extends SocksException {
private final ServerReply serverReply;
diff --git a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5server/msg/StreamUtil.java b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5server/msg/StreamUtil.java
similarity index 71%
rename from src/main/java/org/simplejavamail/mailer/internal/socks/socks5server/msg/StreamUtil.java
rename to modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5server/msg/StreamUtil.java
index cf8267e1b..bbc82d501 100644
--- a/src/main/java/org/simplejavamail/mailer/internal/socks/socks5server/msg/StreamUtil.java
+++ b/modules/authenticated-socks-module/src/main/java/org/simplejavamail/internal/authenticatedsockssupport/socks5server/msg/StreamUtil.java
@@ -1,4 +1,4 @@
-package org.simplejavamail.mailer.internal.socks.socks5server.msg;
+package org.simplejavamail.internal.authenticatedsockssupport.socks5server.msg;
import java.io.IOException;
diff --git a/modules/authenticated-socks-module/src/main/javadoc/index.html b/modules/authenticated-socks-module/src/main/javadoc/index.html
new file mode 100644
index 000000000..94a172530
--- /dev/null
+++ b/modules/authenticated-socks-module/src/main/javadoc/index.html
@@ -0,0 +1,17 @@
+
+
+
+
+ About this module
+
+
+
+ If present on the classpath, this module is used internally by the main Simple Java Mail library.
+ By itself this module has no public API.
+
+
+
\ No newline at end of file
diff --git a/modules/batch-module/.gitignore b/modules/batch-module/.gitignore
new file mode 100644
index 000000000..dc48b22fc
--- /dev/null
+++ b/modules/batch-module/.gitignore
@@ -0,0 +1,2 @@
+*.iml
+target
\ No newline at end of file
diff --git a/modules/batch-module/LICENSE-2.0.txt b/modules/batch-module/LICENSE-2.0.txt
new file mode 100644
index 000000000..d639b1e24
--- /dev/null
+++ b/modules/batch-module/LICENSE-2.0.txt
@@ -0,0 +1,188 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
\ No newline at end of file
diff --git a/modules/batch-module/NOTICE.txt b/modules/batch-module/NOTICE.txt
new file mode 100644
index 000000000..d48127094
--- /dev/null
+++ b/modules/batch-module/NOTICE.txt
@@ -0,0 +1,13 @@
+ =========================================================================
+ == NOTICE file for use with the Apache License, Version 2.0 ==
+ =========================================================================
+
+ Simple Java Mail - Batch module
+ Copyright (C) 2009 Benny Bottema (benny@bennybottema.com)
+ https://www.simplejavamail.org
+
+ This product uses no commercial products.
+
+ This product uses the following external (Open Source) libraries:
+
+ - smtp-connection-pool https://github.com/simple-java-mail/smtp-connection-pool
\ No newline at end of file
diff --git a/modules/batch-module/pom.xml b/modules/batch-module/pom.xml
new file mode 100644
index 000000000..8eef69455
--- /dev/null
+++ b/modules/batch-module/pom.xml
@@ -0,0 +1,39 @@
+
+
+
+ 4.0.0
+
+
+ org.simplejavamail
+ maven-master-project
+ 9.1.3
+ ../../pom.xml
+
+
+ batch-module
+ jar
+ Simple Java Mail - Batch module
+ Simple API, Complex Emails. High performance.
+
+
+ org.simplejavamail.batch
+
+
+
+
+
+
+ org.simplejavamail
+ core-module
+ ${project.version}
+
+
+
+
+ org.simplejavamail
+ smtp-connection-pool
+ 3.0.1
+
+
+
diff --git a/modules/batch-module/src/main/java/org/simplejavamail/internal/batchsupport/BatchException.java b/modules/batch-module/src/main/java/org/simplejavamail/internal/batchsupport/BatchException.java
new file mode 100644
index 000000000..bcbf5fc5d
--- /dev/null
+++ b/modules/batch-module/src/main/java/org/simplejavamail/internal/batchsupport/BatchException.java
@@ -0,0 +1,14 @@
+package org.simplejavamail.internal.batchsupport;
+
+class BatchException extends RuntimeException {
+
+ static final String ERROR_ACQUIRING_KEYED_POOLABLE = "Was unable to obtain a poolable object for key:\t%n%s";
+
+ BatchException(final String msg, final Throwable cause) {
+ super(msg, cause);
+ }
+
+ BatchException(final String msg) {
+ super(msg);
+ }
+}
\ No newline at end of file
diff --git a/modules/batch-module/src/main/java/org/simplejavamail/internal/batchsupport/BatchSupport.java b/modules/batch-module/src/main/java/org/simplejavamail/internal/batchsupport/BatchSupport.java
new file mode 100644
index 000000000..4942c86c4
--- /dev/null
+++ b/modules/batch-module/src/main/java/org/simplejavamail/internal/batchsupport/BatchSupport.java
@@ -0,0 +1,150 @@
+package org.simplejavamail.internal.batchsupport;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import jakarta.mail.Session;
+import lombok.val;
+import org.bbottema.clusteredobjectpool.core.api.ResourceKey.ResourceClusterAndPoolKey;
+import org.bbottema.genericobjectpool.PoolableObject;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.simplejavamail.api.internal.batchsupport.LifecycleDelegatingTransport;
+import org.simplejavamail.api.mailer.config.OperationalConfig;
+import org.simplejavamail.api.mailer.config.TransportStrategy;
+import org.simplejavamail.internal.batchsupport.concurrent.NonJvmBlockingThreadPoolExecutor;
+import org.simplejavamail.internal.modules.BatchModule;
+import org.simplejavamail.internal.util.concurrent.AsyncOperationHelper;
+import org.simplejavamail.smtpconnectionpool.SessionTransport;
+import org.simplejavamail.smtpconnectionpool.SmtpConnectionPool;
+import org.simplejavamail.smtpconnectionpool.SmtpConnectionPoolClustered;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+
+import static java.lang.String.format;
+import static java.util.Objects.requireNonNull;
+import static java.util.Optional.ofNullable;
+import static java.util.concurrent.CompletableFuture.completedFuture;
+import static org.simplejavamail.internal.batchsupport.BatchException.ERROR_ACQUIRING_KEYED_POOLABLE;
+import static org.simplejavamail.internal.batchsupport.ClusterHelper.compareClusterConfig;
+import static org.simplejavamail.internal.batchsupport.ClusterHelper.configureSmtpClusterConfig;
+
+/**
+ * This class only serves to hide the Batch implementation behind an easy-to-load-with-reflection class.
+ */
+@SuppressWarnings("unused") // it is used through reflection
+public class BatchSupport implements BatchModule {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(BatchSupport.class);
+
+ // no need to make this static, because this module itself is already static in the ModuleLoader
+ @Nullable private SmtpConnectionPoolClustered smtpConnectionPool;
+
+ /**
+ * @see BatchModule#executeAsync(String, Runnable)
+ */
+ @Override
+ public CompletableFuture executeAsync(@NotNull final String processName, @NotNull final Runnable operation) {
+ return AsyncOperationHelper.executeAsync(processName, operation);
+ }
+
+ /**
+ * @see BatchModule#executeAsync(ExecutorService, String, Runnable)
+ */
+ @NotNull
+ @Override
+ public CompletableFuture executeAsync(@NotNull final ExecutorService executorService, @NotNull final String processName, @NotNull final Runnable operation) {
+ return AsyncOperationHelper.executeAsync(executorService, processName, operation);
+ }
+
+ /**
+ * @see BatchModule#createDefaultExecutorService(int, int)
+ */
+ @NotNull
+ @Override
+ public ExecutorService createDefaultExecutorService(final int threadPoolSize, final int keepAliveTime) {
+ return new NonJvmBlockingThreadPoolExecutor(threadPoolSize, keepAliveTime);
+ }
+
+ /**
+ * @see BatchModule#registerToCluster(OperationalConfig, UUID, Session)
+ */
+ @Override
+ public synchronized void registerToCluster(@NotNull final OperationalConfig operationalConfig, @NotNull final UUID clusterKey, @NotNull final Session session) {
+ ensureClusterInitialized(operationalConfig);
+ ensureClusterRegistered(operationalConfig, clusterKey);
+ final ResourceClusterAndPoolKey poolKey = new ResourceClusterAndPoolKey<>(clusterKey, session);
+ if (!requireNonNull(smtpConnectionPool).isPoolRegistered(poolKey)) {
+ smtpConnectionPool.registerResourcePool(poolKey);
+ }
+ }
+
+ private void ensureClusterInitialized(@NotNull OperationalConfig operationalConfig) {
+ if (smtpConnectionPool == null) {
+ LOGGER.warn("Starting SMTP connection pool cluster: JVM won't shutdown until the pool is manually closed with mailer.shutdownConnectionPool() (for each mailer in the cluster)");
+ smtpConnectionPool = new SmtpConnectionPoolClustered<>(configureSmtpClusterConfig(operationalConfig));
+ }
+ }
+
+ private void ensureClusterRegistered(@NotNull OperationalConfig operationalConfig, @NotNull UUID clusterKey) {
+ val smtpConnectionPool = requireNonNull(this.smtpConnectionPool);
+ if (!smtpConnectionPool.isClusterRegistered(clusterKey)) {
+ smtpConnectionPool.registerResourceCluster(clusterKey, configureSmtpClusterConfig(operationalConfig, clusterKey).getConfigBuilder().build());
+ } else if (compareClusterConfig(operationalConfig, clusterKey, smtpConnectionPool.getClusterConfig(clusterKey))) {
+ LOGGER.warn("SMTP Connection pool cluster {} is already configured with pool defaults from the first Mailer instance in that cluster, ignoring relevant properties from {}",
+ clusterKey, operationalConfig);
+ }
+ }
+
+ /**
+ * @see BatchModule#acquireTransport(UUID, Session, boolean)
+ */
+ @NotNull
+ @Override
+ @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH", justification = "This is bullshit, Spotbugs. There's a requireNonNull() right in front of you, you numbnuts")
+ public LifecycleDelegatingTransport acquireTransport(@NotNull final UUID clusterKey, @NotNull final Session session, boolean stickySession) {
+ val smtpConnectionPool = requireNonNull(this.smtpConnectionPool, "Connection pool used before it was initialized. This shouldn't be possible.");
+ checkConfigureOAuth2Token(session);
+
+ return ofNullable(getSessionTransportPoolableObject(smtpConnectionPool, clusterKey, session, stickySession))
+ .map(LifecycleDelegatingTransportImpl::new)
+ .orElseThrow(() -> new BatchException(format(ERROR_ACQUIRING_KEYED_POOLABLE, session)));
+ }
+
+ @Nullable
+ private PoolableObject getSessionTransportPoolableObject(SmtpConnectionPoolClustered smtpConnectionPool, UUID clusterKey, Session session, boolean stickySession) {
+ try {
+ return stickySession
+ ? smtpConnectionPool.claimResourceFromPool(new ResourceClusterAndPoolKey<>(clusterKey, session))
+ : smtpConnectionPool.claimResourceFromCluster(clusterKey);
+ } catch (InterruptedException e) {
+ throw new BatchException(format(ERROR_ACQUIRING_KEYED_POOLABLE, session), e);
+ }
+ }
+
+ // since the SMTP connection pool doesn't know about Simple Java Mail,
+ // it won't know where to look for the OAUTH2 token unless we copy the property
+ private void checkConfigureOAuth2Token(Session session) {
+ val props = session.getProperties();
+ if (props.containsKey(TransportStrategy.OAUTH2_TOKEN_PROPERTY)) {
+ props.setProperty(SmtpConnectionPool.OAUTH2_TOKEN_PROPERTY,
+ props.getProperty(TransportStrategy.OAUTH2_TOKEN_PROPERTY));
+ }
+ }
+
+ /**
+ * @see BatchModule#shutdownConnectionPools(Session)
+ */
+ @NotNull
+ @Override
+ public Future shutdownConnectionPools(@NotNull Session session) {
+ if (smtpConnectionPool == null) {
+ LOGGER.warn("user requested connection pool shutdown, but there is no connection pool to shut down (yet)");
+ return completedFuture(null);
+ }
+ return smtpConnectionPool.shutdownPool(session);
+ }
+}
diff --git a/modules/batch-module/src/main/java/org/simplejavamail/internal/batchsupport/ClusterHelper.java b/modules/batch-module/src/main/java/org/simplejavamail/internal/batchsupport/ClusterHelper.java
new file mode 100644
index 000000000..516110a6e
--- /dev/null
+++ b/modules/batch-module/src/main/java/org/simplejavamail/internal/batchsupport/ClusterHelper.java
@@ -0,0 +1,104 @@
+package org.simplejavamail.internal.batchsupport;
+
+import jakarta.mail.Session;
+import org.bbottema.clusteredobjectpool.core.ClusterConfig;
+import org.bbottema.clusteredobjectpool.core.api.LoadBalancingStrategy;
+import org.bbottema.clusteredobjectpool.cyclingstrategies.RandomAccessLoadBalancing;
+import org.bbottema.clusteredobjectpool.cyclingstrategies.RoundRobinLoadBalancing;
+import org.bbottema.genericobjectpool.expirypolicies.TimeoutSinceLastAllocationExpirationPolicy;
+import org.bbottema.genericobjectpool.util.Timeout;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.simplejavamail.api.mailer.config.ConnectionPoolClusterConfig;
+import org.simplejavamail.api.mailer.config.OperationalConfig;
+import org.simplejavamail.smtpconnectionpool.SessionTransport;
+import org.simplejavamail.smtpconnectionpool.SmtpClusterConfig;
+
+import java.util.UUID;
+
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static org.simplejavamail.api.mailer.config.LoadBalancingStrategy.ROUND_ROBIN;
+
+final class ClusterHelper {
+ private ClusterHelper() {
+ // utility class
+ }
+
+ @NotNull
+ static SmtpClusterConfig configureSmtpClusterConfig(@NotNull final OperationalConfig operationalConfig) {
+ return configureSmtpClusterConfig(operationalConfig, null);
+ }
+
+ @NotNull
+ static SmtpClusterConfig configureSmtpClusterConfig(@NotNull final OperationalConfig operationalConfig, @Nullable final UUID clusterKey) {
+ final ConnectionPoolClusterConfig clusterConfig = determineClusterConfig(operationalConfig, clusterKey);
+ SmtpClusterConfig smtpClusterConfig = new SmtpClusterConfig<>();
+ smtpClusterConfig.getConfigBuilder()
+ .defaultCorePoolSize(determineCoreSize(operationalConfig, clusterConfig))
+ .defaultMaxPoolSize(determineMaxSize(operationalConfig, clusterConfig))
+ .claimTimeout(new Timeout(determineClaimTimeoutMillis(operationalConfig, clusterConfig), MILLISECONDS))
+ .loadBalancingStrategy(createPoolLoadBalancingStrategy(determineConfiguredLoadBalancingStrategy(operationalConfig, clusterConfig)))
+ .defaultExpirationPolicy(new TimeoutSinceLastAllocationExpirationPolicy<>(determineExpireAfterMillis(operationalConfig, clusterConfig), MILLISECONDS));
+ return smtpClusterConfig;
+ }
+
+ static boolean compareClusterConfig(@NotNull final OperationalConfig operationalConfig, final ClusterConfig config) {
+ return compareClusterConfig(operationalConfig, null, config);
+ }
+
+ static boolean compareClusterConfig(@NotNull final OperationalConfig operationalConfig, @Nullable final UUID clusterKey, final ClusterConfig config) {
+ final ConnectionPoolClusterConfig clusterConfig = determineClusterConfig(operationalConfig, clusterKey);
+ return config.getDefaultCorePoolSize() != determineCoreSize(operationalConfig, clusterConfig) ||
+ config.getDefaultMaxPoolSize() != determineMaxSize(operationalConfig, clusterConfig) ||
+ !config.getClaimTimeout().equals(new Timeout(determineClaimTimeoutMillis(operationalConfig, clusterConfig), MILLISECONDS)) ||
+ config.getLoadBalancingStrategy().getClass() != createPoolLoadBalancingStrategy(determineConfiguredLoadBalancingStrategy(operationalConfig, clusterConfig)).getClass() ||
+ !config.getDefaultExpirationPolicy().equals(new TimeoutSinceLastAllocationExpirationPolicy(determineExpireAfterMillis(operationalConfig, clusterConfig), MILLISECONDS));
+ }
+
+ @Nullable
+ private static ConnectionPoolClusterConfig determineClusterConfig(@NotNull final OperationalConfig operationalConfig, @Nullable final UUID clusterKey) {
+ return clusterKey != null
+ ? operationalConfig.getConnectionPoolClusterConfigs().get(clusterKey)
+ : null;
+ }
+
+ private static int determineCoreSize(@NotNull final OperationalConfig operationalConfig, @Nullable final ConnectionPoolClusterConfig clusterConfig) {
+ return clusterConfig != null && clusterConfig.getCoreSize() != null
+ ? clusterConfig.getCoreSize()
+ : operationalConfig.getConnectionPoolCoreSize();
+ }
+
+ private static int determineMaxSize(@NotNull final OperationalConfig operationalConfig, @Nullable final ConnectionPoolClusterConfig clusterConfig) {
+ return clusterConfig != null && clusterConfig.getMaxSize() != null
+ ? clusterConfig.getMaxSize()
+ : operationalConfig.getConnectionPoolMaxSize();
+ }
+
+ private static int determineClaimTimeoutMillis(@NotNull final OperationalConfig operationalConfig, @Nullable final ConnectionPoolClusterConfig clusterConfig) {
+ return clusterConfig != null && clusterConfig.getClaimTimeoutMillis() != null
+ ? clusterConfig.getClaimTimeoutMillis()
+ : operationalConfig.getConnectionPoolClaimTimeoutMillis();
+ }
+
+ private static int determineExpireAfterMillis(@NotNull final OperationalConfig operationalConfig, @Nullable final ConnectionPoolClusterConfig clusterConfig) {
+ return clusterConfig != null && clusterConfig.getExpireAfterMillis() != null
+ ? clusterConfig.getExpireAfterMillis()
+ : operationalConfig.getConnectionPoolExpireAfterMillis();
+ }
+
+ @NotNull
+ private static org.simplejavamail.api.mailer.config.LoadBalancingStrategy determineConfiguredLoadBalancingStrategy(@NotNull final OperationalConfig operationalConfig,
+ @Nullable final ConnectionPoolClusterConfig clusterConfig) {
+ return clusterConfig != null && clusterConfig.getLoadBalancingStrategy() != null
+ ? clusterConfig.getLoadBalancingStrategy()
+ : operationalConfig.getConnectionPoolLoadBalancingStrategy();
+ }
+
+ @SuppressWarnings("rawtypes")
+ @NotNull
+ private static LoadBalancingStrategy createPoolLoadBalancingStrategy(@NotNull final org.simplejavamail.api.mailer.config.LoadBalancingStrategy loadBalancingStrategy) {
+ return loadBalancingStrategy == ROUND_ROBIN
+ ? new RoundRobinLoadBalancing<>()
+ : new RandomAccessLoadBalancing<>();
+ }
+}
diff --git a/modules/batch-module/src/main/java/org/simplejavamail/internal/batchsupport/LifecycleDelegatingTransportImpl.java b/modules/batch-module/src/main/java/org/simplejavamail/internal/batchsupport/LifecycleDelegatingTransportImpl.java
new file mode 100644
index 000000000..7193324c5
--- /dev/null
+++ b/modules/batch-module/src/main/java/org/simplejavamail/internal/batchsupport/LifecycleDelegatingTransportImpl.java
@@ -0,0 +1,42 @@
+package org.simplejavamail.internal.batchsupport;
+
+import jakarta.mail.Session;
+import jakarta.mail.Transport;
+import org.bbottema.genericobjectpool.PoolableObject;
+import org.jetbrains.annotations.NotNull;
+import org.simplejavamail.api.internal.batchsupport.LifecycleDelegatingTransport;
+import org.simplejavamail.smtpconnectionpool.SessionTransport;
+
+/**
+ * Wraps {@link PoolableObject} to implement {@link LifecycleDelegatingTransport}, so transport resources
+ * can be used outside the batchmodule and released to be reused in connection pool.
+ */
+class LifecycleDelegatingTransportImpl implements LifecycleDelegatingTransport {
+ private final PoolableObject pooledTransport;
+
+ LifecycleDelegatingTransportImpl(final PoolableObject pooledTransport) {
+ this.pooledTransport = pooledTransport;
+ }
+
+ @NotNull
+ @Override
+ public Session getSessionUsedToObtainTransport() {
+ return pooledTransport.getAllocatedObject().getSession();
+ }
+
+ @NotNull
+ @Override
+ public Transport getTransport() {
+ return pooledTransport.getAllocatedObject().getTransport();
+ }
+
+ @Override
+ public void signalTransportUsed() {
+ pooledTransport.release();
+ }
+
+ @Override
+ public void signalTransportFailed() {
+ pooledTransport.invalidate();
+ }
+}
\ No newline at end of file
diff --git a/modules/batch-module/src/main/java/org/simplejavamail/internal/batchsupport/concurrent/NamedThreadFactory.java b/modules/batch-module/src/main/java/org/simplejavamail/internal/batchsupport/concurrent/NamedThreadFactory.java
new file mode 100644
index 000000000..e09582fdc
--- /dev/null
+++ b/modules/batch-module/src/main/java/org/simplejavamail/internal/batchsupport/concurrent/NamedThreadFactory.java
@@ -0,0 +1,31 @@
+package org.simplejavamail.internal.batchsupport.concurrent;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static java.lang.String.format;
+import static java.lang.Thread.currentThread;
+
+class NamedThreadFactory implements ThreadFactory {
+ private final AtomicInteger threadNumber = new AtomicInteger(1);
+ private final ThreadGroup group;
+ private final String threadName;
+
+ NamedThreadFactory(@NotNull final String threadName) {
+ SecurityManager s = System.getSecurityManager();
+ group = (s != null) ? s.getThreadGroup() : currentThread().getThreadGroup();
+ this.threadName = threadName;
+ }
+
+ @NotNull
+ public Thread newThread(@NotNull Runnable r) {
+ Thread t = new Thread(group, r, format("%s %d", threadName, threadNumber.getAndIncrement()));
+ if (t.isDaemon())
+ t.setDaemon(false);
+ if (t.getPriority() != Thread.NORM_PRIORITY)
+ t.setPriority(Thread.NORM_PRIORITY);
+ return t;
+ }
+}
\ No newline at end of file
diff --git a/modules/batch-module/src/main/java/org/simplejavamail/internal/batchsupport/concurrent/NonJvmBlockingThreadPoolExecutor.java b/modules/batch-module/src/main/java/org/simplejavamail/internal/batchsupport/concurrent/NonJvmBlockingThreadPoolExecutor.java
new file mode 100644
index 000000000..2036fdf11
--- /dev/null
+++ b/modules/batch-module/src/main/java/org/simplejavamail/internal/batchsupport/concurrent/NonJvmBlockingThreadPoolExecutor.java
@@ -0,0 +1,37 @@
+package org.simplejavamail.internal.batchsupport.concurrent;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import static java.lang.String.format;
+
+/**
+ * Unbounded ThreadPoolExecutor that won't block the JVM from shutting down,
+ * unless the keepAliveTime is explicitly set to zero by user config.
+ *
+ * @see ThreadPoolExecutor
+ * @see LinkedBlockingQueue
+ * @see NamedThreadFactory
+ */
+public class NonJvmBlockingThreadPoolExecutor extends ThreadPoolExecutor {
+
+ private static int counter = 1;
+
+ @SuppressFBWarnings("ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD")
+ public NonJvmBlockingThreadPoolExecutor(int threadPoolSize, int threadPoolKeepAliveTime) {
+ super(threadPoolSize,
+ threadPoolSize,
+ threadPoolKeepAliveTime,
+ TimeUnit.MILLISECONDS,
+ new LinkedBlockingQueue<>(),
+ new NamedThreadFactory(format("Simple Java Mail async mail sender, executor %s / thread", counter++)));
+ // if a timeout is configured, the user wants threads to die off automatically,
+ // so they won't block the JVM from shutting down
+ if (threadPoolKeepAliveTime > 0) {
+ allowCoreThreadTimeOut(true);
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/batch-module/src/main/javadoc/index.html b/modules/batch-module/src/main/javadoc/index.html
new file mode 100644
index 000000000..78c3b0ecf
--- /dev/null
+++ b/modules/batch-module/src/main/javadoc/index.html
@@ -0,0 +1,17 @@
+
+
+
+
+ About this module
+
+
+
+ If present on the classpath, this module is used internally by the main Simple Java Mail library.
+ By itself this module has no public API.
+
+
+
\ No newline at end of file
diff --git a/modules/batch-module/src/test/java/org/simplejavamail/internal/batchsupport/BatchSupportTest.java b/modules/batch-module/src/test/java/org/simplejavamail/internal/batchsupport/BatchSupportTest.java
new file mode 100644
index 000000000..1c9ea378b
--- /dev/null
+++ b/modules/batch-module/src/test/java/org/simplejavamail/internal/batchsupport/BatchSupportTest.java
@@ -0,0 +1,131 @@
+package org.simplejavamail.internal.batchsupport;
+
+import jakarta.mail.Session;
+import org.bbottema.clusteredobjectpool.core.ClusterConfig;
+import org.junit.jupiter.api.Test;
+import org.simplejavamail.api.mailer.config.ConnectionPoolClusterConfig;
+import org.simplejavamail.api.mailer.config.LoadBalancingStrategy;
+import org.simplejavamail.api.mailer.config.OperationalConfig;
+import org.simplejavamail.smtpconnectionpool.SessionTransport;
+import org.simplejavamail.smtpconnectionpool.SmtpConnectionPoolClustered;
+
+import java.lang.reflect.Field;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.UUID;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+class BatchSupportTest {
+
+ @Test
+ void registerToClusterUsesSeparatePoolConfigPerClusterKey() throws Exception {
+ BatchSupport batchSupport = new BatchSupport();
+ UUID clusterA = UUID.randomUUID();
+ UUID clusterB = UUID.randomUUID();
+ Session sessionA = session();
+ Session sessionB = session();
+
+ try {
+ batchSupport.registerToCluster(operationalConfig(0, 2, 100, 5000, LoadBalancingStrategy.ROUND_ROBIN), clusterA, sessionA);
+ batchSupport.registerToCluster(operationalConfig(0, 7, 200, 6000, LoadBalancingStrategy.RANDOM_ACCESS), clusterB, sessionB);
+
+ SmtpConnectionPoolClustered smtpConnectionPool = smtpConnectionPool(batchSupport);
+ assertPoolConfig(smtpConnectionPool.getClusterConfig(clusterA), 0, 2, 100, "RoundRobinLoadBalancing");
+ assertPoolConfig(smtpConnectionPool.getClusterConfig(clusterB), 0, 7, 200, "RandomAccessLoadBalancing");
+ } finally {
+ batchSupport.shutdownConnectionPools(sessionA).get();
+ batchSupport.shutdownConnectionPools(sessionB).get();
+ }
+ }
+
+ @Test
+ void registerToClusterKeepsFirstPoolConfigForSameClusterKey() throws Exception {
+ BatchSupport batchSupport = new BatchSupport();
+ UUID cluster = UUID.randomUUID();
+ Session sessionA = session();
+ Session sessionB = session();
+
+ try {
+ batchSupport.registerToCluster(operationalConfig(0, 2, 100, 5000, LoadBalancingStrategy.ROUND_ROBIN), cluster, sessionA);
+ batchSupport.registerToCluster(operationalConfig(0, 7, 200, 6000, LoadBalancingStrategy.RANDOM_ACCESS), cluster, sessionB);
+
+ SmtpConnectionPoolClustered smtpConnectionPool = smtpConnectionPool(batchSupport);
+ assertPoolConfig(smtpConnectionPool.getClusterConfig(cluster), 0, 2, 100, "RoundRobinLoadBalancing");
+ } finally {
+ batchSupport.shutdownConnectionPools(sessionA).get();
+ batchSupport.shutdownConnectionPools(sessionB).get();
+ }
+ }
+
+ @Test
+ void registerToClusterUsesPropertyConfiguredOverridesForMatchingClusterKey() throws Exception {
+ BatchSupport batchSupport = new BatchSupport();
+ UUID configuredCluster = UUID.randomUUID();
+ UUID fallbackCluster = UUID.randomUUID();
+ Session configuredSession = session();
+ Session fallbackSession = session();
+ Map configuredClusters = new HashMap<>();
+ configuredClusters.put(configuredCluster, ConnectionPoolClusterConfig.builder()
+ .coreSize(0)
+ .maxSize(9)
+ .claimTimeoutMillis(300)
+ .expireAfterMillis(7000)
+ .loadBalancingStrategy(LoadBalancingStrategy.RANDOM_ACCESS)
+ .build());
+
+ try {
+ OperationalConfig operationalConfig = operationalConfig(1, 2, 100, 5000, LoadBalancingStrategy.ROUND_ROBIN, configuredClusters);
+ batchSupport.registerToCluster(operationalConfig, configuredCluster, configuredSession);
+ batchSupport.registerToCluster(operationalConfig, fallbackCluster, fallbackSession);
+
+ SmtpConnectionPoolClustered smtpConnectionPool = smtpConnectionPool(batchSupport);
+ assertPoolConfig(smtpConnectionPool.getClusterConfig(configuredCluster), 0, 9, 300, "RandomAccessLoadBalancing");
+ assertPoolConfig(smtpConnectionPool.getClusterConfig(fallbackCluster), 1, 2, 100, "RoundRobinLoadBalancing");
+ } finally {
+ batchSupport.shutdownConnectionPools(configuredSession).get();
+ batchSupport.shutdownConnectionPools(fallbackSession).get();
+ }
+ }
+
+ private static OperationalConfig operationalConfig(int corePoolSize, int maxPoolSize, int claimTimeoutMillis, int expireAfterMillis,
+ LoadBalancingStrategy loadBalancingStrategy) {
+ return operationalConfig(corePoolSize, maxPoolSize, claimTimeoutMillis, expireAfterMillis, loadBalancingStrategy, Collections.emptyMap());
+ }
+
+ private static OperationalConfig operationalConfig(int corePoolSize, int maxPoolSize, int claimTimeoutMillis, int expireAfterMillis,
+ LoadBalancingStrategy loadBalancingStrategy,
+ Map connectionPoolClusterConfigs) {
+ OperationalConfig operationalConfig = mock(OperationalConfig.class);
+ when(operationalConfig.getConnectionPoolCoreSize()).thenReturn(corePoolSize);
+ when(operationalConfig.getConnectionPoolMaxSize()).thenReturn(maxPoolSize);
+ when(operationalConfig.getConnectionPoolClaimTimeoutMillis()).thenReturn(claimTimeoutMillis);
+ when(operationalConfig.getConnectionPoolExpireAfterMillis()).thenReturn(expireAfterMillis);
+ when(operationalConfig.getConnectionPoolLoadBalancingStrategy()).thenReturn(loadBalancingStrategy);
+ when(operationalConfig.getConnectionPoolClusterConfigs()).thenReturn(connectionPoolClusterConfigs);
+ return operationalConfig;
+ }
+
+ private static Session session() {
+ return Session.getInstance(new Properties());
+ }
+
+ private static void assertPoolConfig(ClusterConfig clusterConfig, int corePoolSize, int maxPoolSize,
+ long claimTimeoutMillis, String loadBalancingStrategyClassName) {
+ assertThat(clusterConfig.getDefaultCorePoolSize()).isEqualTo(corePoolSize);
+ assertThat(clusterConfig.getDefaultMaxPoolSize()).isEqualTo(maxPoolSize);
+ assertThat(clusterConfig.getClaimTimeout().getDurationMs()).isEqualTo(claimTimeoutMillis);
+ assertThat(clusterConfig.getLoadBalancingStrategy().getClass().getSimpleName()).isEqualTo(loadBalancingStrategyClassName);
+ }
+
+ @SuppressWarnings("unchecked")
+ private static SmtpConnectionPoolClustered smtpConnectionPool(BatchSupport batchSupport) throws Exception {
+ Field field = BatchSupport.class.getDeclaredField("smtpConnectionPool");
+ field.setAccessible(true);
+ return (SmtpConnectionPoolClustered) field.get(batchSupport);
+ }
+}
diff --git a/modules/cli-module/.gitignore b/modules/cli-module/.gitignore
new file mode 100644
index 000000000..dc48b22fc
--- /dev/null
+++ b/modules/cli-module/.gitignore
@@ -0,0 +1,2 @@
+*.iml
+target
\ No newline at end of file
diff --git a/modules/cli-module/LICENSE-2.0.txt b/modules/cli-module/LICENSE-2.0.txt
new file mode 100644
index 000000000..d639b1e24
--- /dev/null
+++ b/modules/cli-module/LICENSE-2.0.txt
@@ -0,0 +1,188 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
\ No newline at end of file
diff --git a/modules/cli-module/NOTICE.txt b/modules/cli-module/NOTICE.txt
new file mode 100644
index 000000000..b00843877
--- /dev/null
+++ b/modules/cli-module/NOTICE.txt
@@ -0,0 +1,14 @@
+ =========================================================================
+ == NOTICE file for use with the Apache License, Version 2.0 ==
+ =========================================================================
+
+ Simple Java Mail - CLI module
+ Copyright (C) 2009 Benny Bottema (benny@bennybottema.com)
+ https://www.simplejavamail.org
+
+ This product uses no commercial products.
+
+ This product uses the following external (Open Source) libraries:
+
+ - therapi-runtime-javadoc (https://github.com/dnault/therapi-runtime-javadoc)
+ - Picocli (https://github.com/remkop/picocli)
diff --git a/modules/cli-module/pom.xml b/modules/cli-module/pom.xml
new file mode 100644
index 000000000..c6d03a30f
--- /dev/null
+++ b/modules/cli-module/pom.xml
@@ -0,0 +1,200 @@
+
+
+
+ 4.0.0
+
+
+ org.simplejavamail
+ maven-master-project
+ 9.1.3
+ ../../pom.xml
+
+
+ cli-module
+ jar
+ Simple Java Mail - CLI module
+ Simple API, Complex Emails. Now with CLI support
+
+
+ org.simplejavamail.cli
+
+
+
+
+
+
+ org.simplejavamail
+ simple-java-mail
+ ${project.version}
+ compile
+
+
+ com.github.bbottema
+ java-reflection
+ 4.1.1
+
+
+
+
+ info.picocli
+ picocli
+ 3.9.6
+
+
+
+
+ com.github.therapi
+ therapi-runtime-javadoc
+ 0.15.0
+
+
+
+
+ org.simplejavamail
+ authenticated-socks-module
+ ${project.version}
+ runtime
+ true
+
+
+ org.simplejavamail
+ dkim-module
+ ${project.version}
+ runtime
+ true
+
+
+ org.simplejavamail
+ smime-module
+ ${project.version}
+ runtime
+ true
+
+
+ org.simplejavamail
+ batch-module
+ ${project.version}
+ runtime
+ true
+
+
+ org.simplejavamail
+ outlook-module
+ ${project.version}
+ runtime
+ true
+
+
+
+
+ com.esotericsoftware
+ kryo
+ 5.6.2
+ compile
+
+
+
+
+ org.apache.logging.log4j
+ log4j-slf4j2-impl
+ runtime
+
+
+ org.apache.logging.log4j
+ log4j-api
+ runtime
+
+
+ org.apache.logging.log4j
+ log4j-core
+ runtime
+
+
+
+
+ org.simplejavamail
+ core-test-module
+ ${project.version}
+ test
+
+
+
+
+
+ publish-cli
+
+
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ 3.6.3
+
+
+ generateCliData
+ package
+
+ java
+
+
+
+
+ demo.CliListAllSupportedOptionsDemoApp
+ test
+
+
+
+ org.codehaus.mojo
+ appassembler-maven-plugin
+ 2.1.0
+
+ src/main/resources
+ true
+ flat
+ lib
+ true
+
+ unix
+ windows
+
+
+
+ org.simplejavamail.cli.SimpleJavaMail
+ sjm
+
+
+
+
+
+ package
+
+ assemble
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+ 3.8.0
+
+
+ src/assembly/standalone-cli-descriptor.xml
+
+
+
+
+ assemble-all
+ package
+
+ single
+
+
+
+
+
+
+
+
+
diff --git a/modules/cli-module/src/assembly/standalone-cli-descriptor.xml b/modules/cli-module/src/assembly/standalone-cli-descriptor.xml
new file mode 100644
index 000000000..333e89696
--- /dev/null
+++ b/modules/cli-module/src/assembly/standalone-cli-descriptor.xml
@@ -0,0 +1,35 @@
+
+ standalone-cli
+
+ tar
+ zip
+
+ false
+
+
+ ${project.build.directory}/appassembler
+ ./
+
+ **/**
+
+
+
+ ${project.basedir}
+ ./
+
+ NOTICE.txt
+
+
+
+ ${maven.multiModuleProjectDirectory}
+ ./
+
+ LICENSE-2.0.txt
+ RELEASE.txt
+
+
+
+
\ No newline at end of file
diff --git a/modules/cli-module/src/main/java/org/simplejavamail/cli/SimpleJavaMail.java b/modules/cli-module/src/main/java/org/simplejavamail/cli/SimpleJavaMail.java
new file mode 100644
index 000000000..eaf20ba45
--- /dev/null
+++ b/modules/cli-module/src/main/java/org/simplejavamail/cli/SimpleJavaMail.java
@@ -0,0 +1,18 @@
+package org.simplejavamail.cli;
+
+import static org.simplejavamail.internal.clisupport.CliSupport.runCLI;
+
+/**
+ * Entry class when using the command line interface. Wires all the args into the CLI support.
+ *
+ * For CLI usage help, simply add the {@code --help} flag or add it to any available option, like so:
+ * {@code sjm send --mailer:async--help}.
+ *
+ * @see More about the CLI module
+ * @see How to use simple Java Mail CLI
+ */
+public class SimpleJavaMail {
+ public static void main(String[] args) {
+ runCLI(args);
+ }
+}
\ No newline at end of file
diff --git a/modules/cli-module/src/main/java/org/simplejavamail/cli/package-info.java b/modules/cli-module/src/main/java/org/simplejavamail/cli/package-info.java
new file mode 100644
index 000000000..e3d51e800
--- /dev/null
+++ b/modules/cli-module/src/main/java/org/simplejavamail/cli/package-info.java
@@ -0,0 +1,10 @@
+/**
+ * Contains the exposed API of this module which is the entry class to invoke from the command line.
+ *