use of javax.mail.event.ConnectionListener in project ph-web by phax.
the class MailTransport method send.
/**
* Actually send the given array of MimeMessages via JavaMail.
*
* @param aAllMessages
* Email data objects to send. May be <code>null</code>.
* @return A non-<code>null</code> map of the failed messages
*/
@Nonnull
public ICommonsOrderedMap<IMutableEmailData, MailTransportError> send(@Nullable final Collection<IMutableEmailData> aAllMessages) {
final ICommonsOrderedMap<IMutableEmailData, MailTransportError> aFailedMessages = new CommonsLinkedHashMap<>();
if (aAllMessages != null) {
final ICommonsList<IMutableEmailData> aRemainingMessages = new CommonsArrayList<>(aAllMessages);
MailSendException aExceptionToBeRemembered = null;
try (final Transport aTransport = m_aSession.getTransport(m_bSMTPS ? SMTPS_PROTOCOL : SMTP_PROTOCOL)) {
// Add global listeners (if present)
for (final ConnectionListener aConnectionListener : EmailGlobalSettings.getAllConnectionListeners()) aTransport.addConnectionListener(aConnectionListener);
// Check if a detailed listener is present
final ICommonsList<IEmailDataTransportListener> aEmailDataTransportListeners = EmailGlobalSettings.getAllEmailDataTransportListeners();
// Connect
aTransport.connect(m_aSMTPSettings.getHostName(), m_aSMTPSettings.getPort(), m_aSMTPSettings.getUserName(), m_aSMTPSettings.getPassword());
// For all messages
for (final IMutableEmailData aEmailData : aAllMessages) {
final MimeMessage aMimeMessage = new MimeMessage(m_aSession);
try {
// convert from IEmailData to MimeMessage
MailConverter.fillMimeMessage(aMimeMessage, aEmailData, m_aSMTPSettings.getCharsetObj());
// Ensure a sent date is present
if (aMimeMessage.getSentDate() == null)
aMimeMessage.setSentDate(new Date());
// Get an explicitly specified message ID
final String sMessageID = aMimeMessage.getMessageID();
// This creates a new message ID (besides other things)
aMimeMessage.saveChanges();
if (sMessageID != null) {
// Preserve explicitly specified message id...
aMimeMessage.setHeader(HEADER_MESSAGE_ID, sMessageID);
}
aMimeMessage.setHeader(HEADER_X_MAILER, X_MAILER);
if (LOGGER.isInfoEnabled())
LOGGER.info("Delivering mail from " + Arrays.toString(aMimeMessage.getFrom()) + " to " + Arrays.toString(aMimeMessage.getAllRecipients()) + " with subject '" + aMimeMessage.getSubject() + "' and message ID '" + aMimeMessage.getMessageID() + "'");
// Main transmit - always throws an exception
aTransport.sendMessage(aMimeMessage, aMimeMessage.getAllRecipients());
throw new IllegalStateException("Never expected to come beyong sendMessage!");
} catch (final SendFailedException ex) {
if (EmailGlobalSettings.isDebugSMTP())
LOGGER.error("Error send mail - SendFailedException", ex);
/*
* Extract all addresses: the valid addresses to which the message
* was sent, the valid address to which the message was not sent and
* the invalid addresses
*/
final ICommonsSet<String> aValidSent = new CommonsHashSet<>(ex.getValidSentAddresses(), Address::toString);
final ICommonsSet<String> aValidUnsent = new CommonsHashSet<>(ex.getValidUnsentAddresses(), Address::toString);
final ICommonsSet<String> aInvalid = new CommonsHashSet<>(ex.getInvalidAddresses(), Address::toString);
final ICommonsList<MailSendDetails> aDetails = new CommonsArrayList<>();
Exception ex2;
MessagingException bex = ex;
while ((ex2 = bex.getNextException()) != null && ex2 instanceof MessagingException) {
if (ex2 instanceof SMTPAddressFailedException) {
final SMTPAddressFailedException ssfe = (SMTPAddressFailedException) ex2;
aDetails.add(new MailSendDetails(false, ssfe.getAddress().toString(), ssfe.getCommand(), ssfe.getMessage().trim(), ESMTPErrorCode.getFromIDOrDefault(ssfe.getReturnCode(), ESMTPErrorCode.FALLBACK)));
} else if (ex2 instanceof SMTPAddressSucceededException) {
final SMTPAddressSucceededException ssfe = (SMTPAddressSucceededException) ex2;
aDetails.add(new MailSendDetails(true, ssfe.getAddress().toString(), ssfe.getCommand(), ssfe.getMessage().trim(), ESMTPErrorCode.getFromIDOrDefault(ssfe.getReturnCode(), ESMTPErrorCode.FALLBACK)));
}
bex = (MessagingException) ex2;
}
// Map addresses to details
final ICommonsOrderedSet<MailSendDetails> aValidSentExt = new CommonsLinkedHashSet<>();
final ICommonsOrderedSet<MailSendDetails> aValidUnsentExt = new CommonsLinkedHashSet<>();
final ICommonsOrderedSet<MailSendDetails> aInvalidExt = new CommonsLinkedHashSet<>();
for (final MailSendDetails aFailure : aDetails) {
final String sAddress = aFailure.getAddress();
if (aValidSent.contains(sAddress))
aValidSentExt.add(aFailure);
else if (aValidUnsent.contains(sAddress))
aValidUnsentExt.add(aFailure);
else
aInvalidExt.add(aFailure);
}
final EmailDataTransportEvent aEvent = new EmailDataTransportEvent(m_aSMTPSettings, aEmailData, aMimeMessage, aValidSentExt, aValidUnsentExt, aInvalidExt);
if (aValidUnsent.isEmpty() && aInvalid.isEmpty() && aValidSent.isNotEmpty()) {
// Message delivered
for (final IEmailDataTransportListener aEmailDataTransportListener : aEmailDataTransportListeners) aEmailDataTransportListener.messageDelivered(aEvent);
// Remove message from list of remaining
STATS_SEND_SUCCESS.increment();
} else {
// Message not delivered
for (final IEmailDataTransportListener aEmailDataTransportListener : aEmailDataTransportListeners) aEmailDataTransportListener.messageNotDelivered(aEvent);
// Sending exactly this message failed
aFailedMessages.put(aEmailData, new MailTransportError(ex, aDetails));
STATS_SEND_FAILURE.increment();
}
// Remove message from list of remaining as we put it in the
// failed message list manually in case of error
aRemainingMessages.remove(aEmailData);
} catch (final MessagingException ex) {
if (EmailGlobalSettings.isDebugSMTP())
LOGGER.error("Error send mail - MessagingException", ex);
final ICommonsOrderedSet<MailSendDetails> aInvalid = new CommonsLinkedHashSet<>();
final Consumer<IEmailAddress> aConsumer = a -> aInvalid.add(new MailSendDetails(false, a.getAddress(), "<generic error>", ex.getMessage(), ESMTPErrorCode.FALLBACK));
aEmailData.to().forEach(aConsumer);
aEmailData.cc().forEach(aConsumer);
aEmailData.bcc().forEach(aConsumer);
final EmailDataTransportEvent aEvent = new EmailDataTransportEvent(m_aSMTPSettings, aEmailData, aMimeMessage, new CommonsArrayList<>(), new CommonsArrayList<>(), aInvalid);
// Message not delivered
for (final IEmailDataTransportListener aEmailDataTransportListener : aEmailDataTransportListeners) aEmailDataTransportListener.messageNotDelivered(aEvent);
// Sending exactly this message failed
aFailedMessages.put(aEmailData, new MailTransportError(ex));
// Remove message from list of remaining as we put it in the
// failed message list manually
aRemainingMessages.remove(aEmailData);
STATS_SEND_FAILURE.increment();
}
}
// for all messages
} catch (final AuthenticationFailedException ex) {
// problem with the credentials
aExceptionToBeRemembered = new MailSendException("Mail server authentication failed", ex);
} catch (final MessagingException ex) {
if (WebExceptionHelper.isServerNotReachableConnection(ex.getCause()))
aExceptionToBeRemembered = new MailSendException("Failed to connect to mail server: " + ex.getCause().getMessage());
else
aExceptionToBeRemembered = new MailSendException("Mail server connection failed", ex);
} catch (final Exception ex) {
// E.g. IllegalState from SMTPTransport ("Not connected")
aExceptionToBeRemembered = new MailSendException("Internal error sending mail", ex);
} finally {
// Was any message not sent
if (aRemainingMessages.isNotEmpty()) {
if (aExceptionToBeRemembered == null)
aExceptionToBeRemembered = new MailSendException("Internal error - messages are remaining but no Exception occurred!");
for (final IMutableEmailData aRemainingMessage : aRemainingMessages) aFailedMessages.put(aRemainingMessage, new MailTransportError(aExceptionToBeRemembered));
}
}
}
return aFailedMessages;
}
Aggregations