org.simplejavamail.mailer.internal.util.TransportRunner Maven / Gradle / Ivy
Show all versions of simple-java-mail Show documentation
/*
* Copyright © 2009 Benny Bottema ([email protected])
*
* 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.
*/
package org.simplejavamail.mailer.internal.util;
import jakarta.mail.MessagingException;
import jakarta.mail.Session;
import jakarta.mail.Transport;
import jakarta.mail.internet.InternetAddress;
import lombok.val;
import org.jetbrains.annotations.NotNull;
import org.simplejavamail.api.email.Email;
import org.simplejavamail.api.internal.batchsupport.LifecycleDelegatingTransport;
import org.simplejavamail.internal.moduleloader.ModuleLoader;
import org.simplejavamail.internal.modules.BatchModule;
import org.simplejavamail.internal.util.MiscUtil;
import org.simplejavamail.mailer.internal.SessionBasedEmailToMimeMessageConverter;
import org.slf4j.Logger;
import java.util.UUID;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.slf4j.LoggerFactory.getLogger;
/**
* If available, runs activities on Transport connections using SMTP connection pool from the batch-module.
*
* Otherwise, always creates a new connection to run the activity on.
*
* Note that
* multiple threads can safely use a Session, but are synchronized in the Transport connection.
*/
public class TransportRunner {
private static final Logger LOGGER = getLogger(TransportRunner.class);
/**
* NOTE: only in case batch-module is *not* in use, the {@link Session} passed in here is guaranteed to be used to send this message.
*
* @param clusterKey The cluster key to use for the connection pool, which was randomly generated in the Mailer builder if not provided.
*/
public static void sendMessage(@NotNull final UUID clusterKey, final Session session, @NotNull Email email)
throws MessagingException {
runOnSessionTransport(clusterKey, session, false, (transport, actualSessionUsed) -> {
val message = SessionBasedEmailToMimeMessageConverter.convertAndLogMimeMessage(actualSessionUsed, email);
val actualRecipients = email.getOverrideReceivers().isEmpty()
? message.getAllRecipients()
: MiscUtil.asInternetAddresses(email.getOverrideReceivers(), UTF_8).toArray(new InternetAddress[0]);
transport.sendMessage(message, actualRecipients);
LOGGER.trace("...email sent");
});
}
public static void connect(@NotNull UUID clusterKey, final Session session)
throws MessagingException {
runOnSessionTransport(clusterKey, session, true, (transport, actualSessionUsed) -> {
// the fact that we reached here means a connection was made successfully
LOGGER.debug("...connection successful");
});
}
private static void runOnSessionTransport(@NotNull UUID clusterKey, Session session, final boolean stickySession, TransportRunnable runnable)
throws MessagingException {
if (ModuleLoader.batchModuleAvailable()) {
sendUsingConnectionPool(ModuleLoader.loadBatchModule(), clusterKey, session, stickySession, runnable);
} else {
try (Transport transport = session.getTransport()) {
TransportConnectionHelper.connectTransport(transport, session);
runnable.run(transport, session);
} finally {
LOGGER.trace("closing transport");
}
}
}
private static void sendUsingConnectionPool(@NotNull BatchModule batchModule, @NotNull UUID clusterKey, Session session, boolean stickySession, TransportRunnable runnable)
throws MessagingException {
LifecycleDelegatingTransport delegatingTransport = batchModule.acquireTransport(clusterKey, session, stickySession);
try {
runnable.run(delegatingTransport.getTransport(), delegatingTransport.getSessionUsedToObtainTransport());
} catch (final Throwable t) {
// always make sure claimed resources are released
delegatingTransport.signalTransportFailed();
throw t;
}
delegatingTransport.signalTransportUsed();
}
private interface TransportRunnable {
void run(Transport transport, Session actualSessionUsed)
throws MessagingException;
}
}