NMS-20102: Migrate all mail sending/reading from JavaMail 1.4.7 to Jakarta Mail 2.1 (Part of rework JavaMailNotificationStrategy) - #8701
Conversation
Adds dependencyManagement for jakarta.mail-api 2.1.5, angus-mail 2.0.5, angus-activation 2.0.3, and bumps jakarta.activation-api to 2.1.4 (the jakarta-namespace line needed by angus; javax-namespace activation classes continue to come from com.sun.activation:jakarta.activation 1.2.1, which opennms-webapp-rest now references directly). EclipseLink MOXy 2.5.1 hard-references javax.mail.internet.MimeMultipart from XMLBinaryDataHelper's initializer, so a javax.mail-namespace API must stay on the classpath after the jakarta migration. jaxb-dependencies switches from javax.mail:mail 1.4.7 to com.sun.mail:mailapi 1.6.7: API classes only, no transport providers, and a distinct Maven GA so it cannot collide with jakarta.mail-api 2.1.x under dependencyConvergence. The Karaf javax.mail feature repoints to the jakarta.mail-api 1.6.7 bundle, matching the copy CXF's cxf-specs feature already installs.
alt.dev.jmta:jmta:1.0 (2004) subclasses javax.mail.Transport and cannot load under Jakarta Mail 2.x. The use-jmta attribute and the useJMTA property remain accepted so existing configuration files keep loading; JavaMailer now logs a one-time WARN and sends via the configured transport instead. On the JavaSendMailer path use-jmta was already inert: the transport always came from sendmail-protocol@transport, which the schema restricts to smtp|smtps, so the removed "mta" branch there was unreachable. Shipped defaults change to use-jmta="false". Behavior change for installs that relied on the local MTA transport: mail now goes over SMTP to the configured sendmail host (default 127.0.0.1:25) instead of through the in-process JMTA class.
Renames javax.mail.* to jakarta.mail.* and javax.activation.* to jakarta.activation.* across the mail senders/readers (opennms-javamail, ackd, poller MailTransportMonitor, reportd, web-api) and their tests. opennms-javamail-api now depends on jakarta.mail-api with angus-mail and angus-activation as runtime providers, flowing transitively to all consumers; direct importers declare jakarta.mail-api explicitly. Spring 4.2.9's MimeMessageHelper is compiled against javax.mail, so JavaSendMailer.buildMimeMessage() and reportd's JavaMailDeliveryService build their MIME messages directly (same structure: single-part message for sendmail, mixed multipart with a plain/HTML alternative and the report attachment for reportd). This also drops opennms-javamail-api's mandatory org.springframework.mail.javamail OSGi import. Container: new jakarta.mail Karaf feature (API + Angus bundles at the system start level); the opennms-javamail feature uses it; the javax.mail feature remains for the MOXy shim consumers. custom.properties exports the jakarta.mail/jakarta.activation packages from the flat classpath. The wsman bundle marks jakarta.mail optional: it accidentally embeds poller-monitors-core's whole org.opennms.netmgt.poller.monitors package (split package with WsManMonitor), and the unused embedded MailTransportMonitor copy is where its mail import comes from.
Inverts the enforcer rule that required javax.mail:mail: the banned list now covers javax.mail:mail, com.sun.mail:javax.mail/jakarta.mail, the merged org.eclipse.angus:jakarta.mail artifact (would duplicate the API + angus-mail classes), and geronimo-javamail_1.4_spec, which reached $OPENNMS_HOME/lib undeclared through abdera-parser/axiom and is now excluded at its source in cxf-dependencies. com.sun.mail:mailapi remains allowed as the MOXy shim. Also fixes the newts-repository-converter activation-jar glob, which matched nothing (lib/jdk9plus ships the servicemix activation-api jar, not javax.activation-*.jar).
createProps() assembled <javamail-property> entries and the computed
mail.smtp.* keys, then returned the JVM-default session's properties
instead ("//get rid of this"), so none of it ever reached the Session;
configureProperties() additionally merged everything into a local
variable that went nowhere. The Session now receives the merged set:
javamail-configuration.properties (only when useJmProps=true, matching
the constructor contract), overlaid by <javamail-property> entries,
with computed keys filled in only where absent so user values win.
Session-property-driven features - mail.smtp.auth.mechanisms=XOAUTH2
in particular - become usable on the XML config path.
Applied property names are logged at INFO on session creation since
previously-inert <javamail-property> entries in existing configuration
files take effect on upgrade.
Also assigns the parent JavaMailer2 session, which reportd reads via
getSession() and previously received as null.
Adds TokenScope, a mate Scope over the token-auth TokenProvider under
the "token" context, registered in the token-auth application context.
JavaMailerConfig now interpolates credentials against a FallbackScope
of the SCV scope and the token scope, each independently optional, so
${token:<name>} works wherever ${scv:...} already did: the
authenticateUser/authenticatePassword properties and the XML
user-auth fields (both resolved at connect time, so tokens are always
fresh via the token cache).
With Angus providing the XOAUTH2 SASL mechanism natively, OAuth2 SMTP
(Microsoft 365 client-credentials, Gmail) needs only configuration:
a token-auth definition for the provider's token endpoint, plus
authenticate=true, mail.smtp.auth.mechanisms=XOAUTH2, and
${token:<name>} as the password. No mail-code OAuth client required.
The token scope resolves per interpolation (no caching in the scope) -
covered by tests asserting fetch-per-call semantics.
The mail code had no non-manual wire coverage: every send/receive test was @ignore'd against real servers. JavaMailerWireTest runs the actual Angus SMTP/IMAP providers against an embedded GreenMail 2.x on dynamic ports: plain send, authenticated send, JavaSendMailer end-to-end from a SendmailConfig (locks in the createProps fix), and JavaReadMailer over IMAP. XOAUTH2 is asserted byte-level against a minimal in-test SMTP server, since GreenMail doesn't implement that SASL mechanism: the client must emit AUTH XOAUTH2 with base64("user=<u>\x01auth=Bearer <token>\x01\x01"), which is the exact string Microsoft 365 and Gmail validate. greenmail excludes org.eclipse.angus:jakarta.mail (the banned merged API+impl jar); the split artifacts provide the same classes. The tests set mail.smtp timeouts so protocol mismatches fail in seconds instead of hanging the build.
Adds a worked Microsoft 365 client-credentials example to the token authentication page (token-auth block plus both the properties-file and javamail-configuration.xml recipes), references the token context from the notifd config-file table and the metadata DSL page, and comments the XOAUTH2 pattern in the shipped javamail-configuration.properties. Release notes cover the Jakarta Mail migration and its three upgrade notes: checkserveridentity now defaults to true on SSL/TLS connections, use-jmta is accepted but inert, and <javamail-property> entries take effect on the sendmail path.
Code fixes:
- angus-mail on the flat classpath is replaced by angus-mail-shaded,
which strips META-INF/mailcap and META-INF/javamail(.default).providers.
Those javax-era resource names list jakarta-namespace classes, and the
javax.activation command map reads them from every jar: with
com.sun.activation as the javax impl, a text/plain DataHandler lookup
fails outright (reproduced), taking down unrelated javax consumers.
The jakarta runtime keeps working via META-INF/jakarta.mailcap and
ServiceLoader, both retained; Karaf features keep vanilla angus-mail
(bundle isolation makes the resources harmless there).
- reportd attachments carry their real MIME type again (PDF/CSV/XLS
registered on the data source); a bare FileDataSource labeled every
report application/octet-stream.
- JavaSendMailer only advertises mail.smtp(s).auth=true when a user-auth
is actually configured; use-authentication="true" without credentials
kept sending unauthenticated before the session properties became
real, and now warns instead of failing the connect.
- transport 'mta' (still possible via the unvalidated properties file)
maps to smtp with a warning instead of NoSuchProviderException; the
removed-JMTA warning is per-mailer instead of once per JVM.
- TokenScope resolves to empty (WARN) on token-provider failures so a
transient token-endpoint outage cannot abort mailer construction.
- JavaMailerConfig.getProperties is no longer synchronized: credential
interpolation may fetch an OAuth token over HTTP, and the class
monitor serialized every mail path in the JVM on that request.
- custom.properties additionally exports jakarta.activation.spi, so
angus-activation wires both packages to the same provider.
Tests: XOAUTH2 wire test now drives the full documented composition
(${token:name} in javamail-configuration.properties resolved through
the token scope to the Bearer token on the wire); new authenticated
JavaSendMailer wire test; fake SMTP thread is a daemon; JavaSendMailer
wire tests set mail timeouts via <javamail-property>; test scope/system
property state is restored after each class.
Docs: metadata page no longer suggests readmail-config credentials
interpolate (they do not); XOAUTH2 mechanism line documented as
required rather than advisory; M365 prerequisites include the mailbox
permission grant; release notes cover the provider-less javax.mail API
(third-party plugins) and MailTransportMonitor sendmail-test behavior;
MailTransportMonitor reference page marks use-jmta deprecated; shipped
and example properties files carry the XOAUTH2 recipe with a
duplicate-key note.
Conflict resolution: dependencies/javamail stays deleted (jmta removal vs the branch-wide 36.0.3-SNAPSHOT version bump); both new release-note sections kept in whatsnew.adoc. The new angus-mail-shaded module's parent version is bumped to 36.0.3-SNAPSHOT, which the merge could not do since upstream never saw the file.
There was a problem hiding this comment.
Pull request overview
Migrates OpenNMS mail sending/reading from legacy JavaMail (javax.*) to Jakarta Mail 2.1 with the Eclipse Angus implementation, while preserving existing configuration formats and adding OAuth2/XOAUTH2 support via ${token:<name>} interpolation.
Changes:
- Replaces
javax.mailusage across services/daemons/tests withjakarta.mail, adds Angus runtime/provider dependencies, and introduces a shaded Angus artifact for flat-classpath compatibility. - Adds
${token:...}metadata context support for mail credential interpolation via a newTokenScopeSpring bean and associated tests. - Updates assembly/config/docs to reflect JMTA removal, new TLS hostname verification defaults, XOAUTH2 configuration, and related operational guidance.
Reviewed changes
Copilot reviewed 47 out of 48 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| pom.xml | Introduces Jakarta Mail/Angus + GreenMail versions/deps and excludes conflicting mail artifacts. |
| opennms-webapp-rest/pom.xml | Aligns activation dependency with the chosen runtime/flat-classpath activation jar. |
| opennms-web-dependencies/pom.xml | Removes legacy javamail-dependencies BOM usage. |
| opennms-web-api/src/main/java/org/opennms/web/svclayer/support/DefaultSchedulerService.java | Switches mail address imports from javax.mail to jakarta.mail. |
| opennms-web-api/pom.xml | Adds jakarta.mail-api dependency for compilation. |
| opennms-services/pom.xml | Replaces javax.mail:mail with jakarta.mail-api and removes javamail-dependencies test BOM. |
| opennms-javamail/opennms-javamail-api/src/test/java/org/opennms/javamail/JavaSendMailerTest.java | Updates tests to jakarta.mail types. |
| opennms-javamail/opennms-javamail-api/src/test/java/org/opennms/javamail/JavaReadMailerTest.java | Updates tests to jakarta.mail types. |
| opennms-javamail/opennms-javamail-api/src/test/java/org/opennms/javamail/JavaMailerWireTest.java | Adds GreenMail-backed wire-level SMTP/IMAP + XOAUTH2 transcript tests. |
| opennms-javamail/opennms-javamail-api/src/test/java/org/opennms/javamail/JavaMailerTest.java | Updates tests to jakarta.mail types. |
| opennms-javamail/opennms-javamail-api/src/test/java/org/opennms/javamail/JavaMailerConfigTokenTest.java | Adds unit tests ensuring ${token:...} interpolation resolves and refreshes each call. |
| opennms-javamail/opennms-javamail-api/src/main/java/org/opennms/javamail/JavaSendMailer.java | Ports to jakarta.mail, fixes session handling, merges/filters session properties, deprecates JMTA transport, and adds auth behavior adjustments. |
| opennms-javamail/opennms-javamail-api/src/main/java/org/opennms/javamail/JavaReadMailer.java | Ports to jakarta.mail and updates javadocs. |
| opennms-javamail/opennms-javamail-api/src/main/java/org/opennms/javamail/JavaMailerConfig.java | Adds token-scope interpolation support and removes synchronization from properties loading to avoid token-fetch serialization. |
| opennms-javamail/opennms-javamail-api/src/main/java/org/opennms/javamail/JavaMailer2.java | Ports activation/mail types to jakarta.* and updates javadocs. |
| opennms-javamail/opennms-javamail-api/src/main/java/org/opennms/javamail/JavaMailer.java | Ports to jakarta.*, defaults away from JMTA, and warns/falls back when mta transport is configured. |
| opennms-javamail/opennms-javamail-api/pom.xml | Switches to Jakarta Mail API + activation API and adds runtime Angus/activation + GreenMail for tests. |
| opennms-enterprise-reporting/opennms-reportd/src/main/java/org/opennms/netmgt/reporting/service/JavaMailDeliveryService.java | Removes Spring MimeMessageHelper usage and builds multipart + attachments directly with jakarta.mail. |
| opennms-enterprise-reporting/opennms-reportd/pom.xml | Adds jakarta.mail-api and jakarta.activation-api dependencies. |
| opennms-config/src/test/java/org/opennms/netmgt/config/tokenauth/TokenScopeTest.java | Adds tests for new token scope behavior (context filtering, failure behavior, no key enumeration). |
| opennms-config/src/main/resources/META-INF/opennms/applicationContext-token-auth.xml | Registers tokenScope bean for ${token:...} interpolation. |
| opennms-config/src/main/java/org/opennms/netmgt/config/tokenauth/TokenScope.java | Implements a Mate Scope backed by TokenProvider for on-demand token resolution. |
| opennms-base-assembly/src/main/filtered/etc/javamail-configuration.xml | Updates sample configs to default use-jmta="false". |
| opennms-base-assembly/src/main/filtered/etc/javamail-configuration.properties | Documents JMTA removal and adds XOAUTH2/token examples. |
| opennms-base-assembly/src/main/filtered/etc/examples/javamail-configuration.properties | Adds a worked XOAUTH2 example (M365) for notification properties config. |
| opennms-base-assembly/src/main/filtered/bin/newts-repository-converter | Loosens activation jar discovery pattern to match new activation naming. |
| opennms-base-assembly/pom.xml | Removes runtime dependency on legacy javamail-dependencies. |
| opennms-ackd/src/test/java/org/opennms/netmgt/ackd/readers/JavaMailAckReaderIT.java | Ports test usage from javax.mail to jakarta.mail. |
| opennms-ackd/src/main/java/org/opennms/netmgt/ackd/readers/MailAckProcessor.java | Ports imports/javadocs from javax.mail to jakarta.mail. |
| opennms-ackd/pom.xml | Replaces javax.mail:mail with jakarta.mail-api. |
| features/wsman/pom.xml | Marks jakarta.mail* imports optional to avoid accidental resolution due to embedded split package. |
| features/poller/monitors/core/src/main/java/org/opennms/netmgt/poller/monitors/MailTransportMonitor.java | Ports monitor code from javax.mail to jakarta.mail. |
| features/poller/monitors/core/pom.xml | Adds jakarta.mail-api dependency for the monitor. |
| docs/modules/releasenotes/pages/whatsnew.adoc | Adds breaking-change notes for Jakarta Mail migration, JMTA removal behavior, TLS hostname checks, XOAUTH2, and <javamail-property> behavior. |
| docs/modules/reference/pages/service-assurance/monitors/MailTransportMonitor.adoc | Documents use-jmta as deprecated/removed transport behavior. |
| docs/modules/reference/pages/daemons/daemon-config-files/notifd.adoc | Documents ${token:<name>} usage for XOAUTH2 mail auth. |
| docs/modules/operation/pages/deep-dive/meta-data.adoc | Documents token metadata context for outbound mail credential interpolation. |
| docs/modules/operation/pages/deep-dive/admin/configuration/token-authentication.adoc | Adds a worked Microsoft 365 XOAUTH2 SMTP authentication example. |
| dependencies/pom.xml | Removes legacy javamail module and adds angus-mail-shaded module. |
| dependencies/jaxb/pom.xml | Switches MOXy shim dependency to com.sun.mail:mailapi and documents rationale. |
| dependencies/javamail/src/license/THIRD-PARTY.properties | Removes JMTA-related third-party notice with deleted module. |
| dependencies/javamail/pom.xml | Deletes the legacy javamail-dependencies module (JMTA dependency). |
| dependencies/cxf/pom.xml | Excludes geronimo javamail spec to avoid conflicting mail artifacts. |
| dependencies/angus-mail-shaded/pom.xml | Adds shaded Angus build that strips legacy javax-era resource names for flat-classpath safety. |
| container/karaf/src/main/filtered-resources/etc/custom.properties | Exports jakarta.mail/jakarta.activation packages via system bundle with versions aligned to shipped jars. |
| container/features/src/main/resources/features.xml | Updates opennms-javamail feature to pull jakarta.mail and required dependencies. |
| container/features/src/main/resources/features-core.xml | Defines new jakarta.mail feature (API + Angus) and keeps a javax.mail API-only shim feature for MOXy. |
| container/features/pom.xml | Ensures jakarta.mail feature is included in feature sets that previously only pulled javax.mail. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…2-jakarta-mail The XMPP removal (NMS-20099) edited the same metadata-DSL list entry this branch annotates with the token context; kept upstream's entry (xmpp-configuration.xml gone) plus this branch's token paragraph.
JavaSendMailer.buildMimeMessage() parses the to address with InternetAddress.parse(to, false), matching JavaMailer, so comma-separated recipient lists in sendmail-message work; the previous single-address constructor matched the old MimeMessageHelper behavior but diverged from the rest of the module. Wire test now sends to two recipients. Also drops the duplicated mail.smtp.quitwait defaulting block (pre-existing) and restores the opennms.home system property after each JavaMailerWireTest.
dino2gnt
left a comment
There was a problem hiding this comment.
This touches a surprisingly large number of things.
If it goes green, ship it. When this is all moved into a UI + REST, we can revisit the configuration parsing and some of those 20+-year-old TODOs and FIXMEs and rip it all out.
Yep. I was genuinely shocked at how rooted this is in there... it's not ideal but my thought process is that if I'm touching this at all, this is the way to do it for now. I think once this is in, it opens up the door for a lot of future work. |
Absolutely. And besides, even if this is completely broken, it's only ~10% more broken than things are today. 😆 |
JavaMailer.buildMessage() has two attachment branches: the file branch builds a multipart with the message text followed by the attachment, while the stream branch (added in 1dfc6c9, 2010) added only the attachment part. Callers that set an input stream therefore lost the message text entirely -- DefaultReportWrapperService sets both, so every emailed database report arrived as a bare PDF or CSV with no body. The stream branch now adds the text part first, matching the file branch. Covered by a GreenMail wire test asserting both parts and their order; the test fails on the previous behavior with one part instead of two. Pre-existing on release-36.x and unrelated to the Jakarta migration, folded in here since this is the mail rework.
Angus enforces certificate trust and host-name verification independently, and mail.smtp.ssl.trust suppresses only the first -- including when set to "*", the conventional workaround for self-signed certificates. Installations carrying it therefore still fail host-name verification after the upgrade, which the release note did not convey. Adds a Mail server TLS section to the notification configuration page covering both properties, the two distinct failure messages, and which property applies to each; the release note is trimmed to the behavior change and points there. Verified against a STARTTLS server presenting a certificate for a different name.
|
@indigo423 - I can confirm this should work for everything in OpenNMS that touches mail today but if you find something that doesn't work, let me know. I tested locally with mailpit, the following:
I can also confirm that token auth works with gmail. I haven't been able to directly test O365 but I don't think we should avoid shipping this. |
…-20102-jakarta-mail The NMS-20098 microblog removal edited the same metadata-DSL list entry this branch annotates with the token context, the same collision the NMS-20099 XMPP removal caused earlier. Kept upstream's entry (microblog-configuration.xml gone) plus this branch's token paragraph.
This was part of the rework on the JavaMailNotificationStrategy work to support modernizing notifications. In thoery, this keeps all existing config and shouldn't break anything.
Migrates all mail sending/reading from JavaMail 1.4.7 to Jakarta Mail 2.1 (Eclipse Angus) and adds OAuth2/XOAUTH2 SMTP authentication, which Microsoft 365 and Gmail now require.
External References