Search in sources :

Example 1 with IEmailDataTransportListener

use of com.helger.smtp.listener.IEmailDataTransportListener 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;
}
Also used : ICommonsList(com.helger.commons.collection.impl.ICommonsList) AuthenticationFailedException(javax.mail.AuthenticationFailedException) EmailDataTransportEvent(com.helger.smtp.listener.EmailDataTransportEvent) IMutableEmailData(com.helger.smtp.data.IMutableEmailData) ICommonsOrderedSet(com.helger.commons.collection.impl.ICommonsOrderedSet) ConnectionListener(javax.mail.event.ConnectionListener) Consumer(java.util.function.Consumer) MimeMessage(javax.mail.internet.MimeMessage) IEmailDataTransportListener(com.helger.smtp.listener.IEmailDataTransportListener) CommonsLinkedHashMap(com.helger.commons.collection.impl.CommonsLinkedHashMap) SendFailedException(javax.mail.SendFailedException) MessagingException(javax.mail.MessagingException) SMTPAddressFailedException(com.sun.mail.smtp.SMTPAddressFailedException) SMTPAddressSucceededException(com.sun.mail.smtp.SMTPAddressSucceededException) Date(java.util.Date) MessagingException(javax.mail.MessagingException) AuthenticationFailedException(javax.mail.AuthenticationFailedException) SendFailedException(javax.mail.SendFailedException) SMTPAddressFailedException(com.sun.mail.smtp.SMTPAddressFailedException) SMTPAddressSucceededException(com.sun.mail.smtp.SMTPAddressSucceededException) ICommonsSet(com.helger.commons.collection.impl.ICommonsSet) Transport(javax.mail.Transport) CommonsArrayList(com.helger.commons.collection.impl.CommonsArrayList) Nonnull(javax.annotation.Nonnull)

Aggregations

CommonsArrayList (com.helger.commons.collection.impl.CommonsArrayList)1 CommonsLinkedHashMap (com.helger.commons.collection.impl.CommonsLinkedHashMap)1 ICommonsList (com.helger.commons.collection.impl.ICommonsList)1 ICommonsOrderedSet (com.helger.commons.collection.impl.ICommonsOrderedSet)1 ICommonsSet (com.helger.commons.collection.impl.ICommonsSet)1 IMutableEmailData (com.helger.smtp.data.IMutableEmailData)1 EmailDataTransportEvent (com.helger.smtp.listener.EmailDataTransportEvent)1 IEmailDataTransportListener (com.helger.smtp.listener.IEmailDataTransportListener)1 SMTPAddressFailedException (com.sun.mail.smtp.SMTPAddressFailedException)1 SMTPAddressSucceededException (com.sun.mail.smtp.SMTPAddressSucceededException)1 Date (java.util.Date)1 Consumer (java.util.function.Consumer)1 Nonnull (javax.annotation.Nonnull)1 AuthenticationFailedException (javax.mail.AuthenticationFailedException)1 MessagingException (javax.mail.MessagingException)1 SendFailedException (javax.mail.SendFailedException)1 Transport (javax.mail.Transport)1 ConnectionListener (javax.mail.event.ConnectionListener)1 MimeMessage (javax.mail.internet.MimeMessage)1