public Result execute()

in plugins/misc/mail/src/main/java/org/apache/hop/mail/workflow/actions/mail/ActionMail.java [209:763]


  public Result execute(Result result, int nr) {
    File masterZipfile = null;

    session = null;
    String protocol = "smtp";

    if (!StringUtils.isEmpty(connectionName)) {
      try {
        connection =
            getMetadataProvider().getSerializer(MailServerConnection.class).load(connectionName);
        session = connection.getSession(getVariables() /*, getLogChannel()*/);
      } catch (HopException e) {
        throw new RuntimeException(
            "Mail server connection '" + connectionName + "' could not be found", e);
      }
    } else {
      // Send an e-mail...
      // create some properties and get the default Session
      Properties props = new Properties();
      if (Utils.isEmpty(server)) {
        logError(BaseMessages.getString(PKG, "ActionMail.Error.HostNotSpecified"));

        result.setNrErrors(1L);
        result.setResult(false);
        return result;
      }

      if (usingSecureAuthentication) {
        if (usexoauth2) {
          props.put("mail.smtp.auth.mechanisms", "XOAUTH2");
        }
        if (secureConnectionType.equals("TLS")) {
          // Allow TLS authentication
          props.put("mail.smtp.starttls.enable", "true");
        } else if (secureConnectionType.equals("TLS 1.2")) {
          // Allow TLS 1.2 authentication
          props.put("mail.smtp.starttls.enable", "true");
          props.put("mail.smtp.ssl.protocols", "TLSv1.2");
        } else {

          protocol = "smtps";
          // required to get rid of a SSL exception :
          // nested exception is:
          // javax.net.ssl.SSLException: Unsupported record version Unknown
          props.put("mail.smtps.quitwait", "false");
        }
        props.put("mail.smtp.ssl.checkServerIdentity", isCheckServerIdentity());
        if (!Utils.isEmpty(trustedHosts)) {
          props.put("mail.smtp.ssl.trust", resolve(trustedHosts));
        }
      }

      props.put(CONST_MAIL + protocol + ".host", resolve(server));
      if (!Utils.isEmpty(port)) {
        props.put(CONST_MAIL + protocol + ".port", resolve(port));
      }

      if (isDebug()) {
        props.put("mail.debug", "true");
      }

      if (usingAuthentication) {
        props.put(CONST_MAIL + protocol + ".auth", "true");
      }

      session = Session.getInstance(props);
    }

    session.setDebug(isDebug());

    try {
      // create a message
      Message msg = new MimeMessage(session);

      // set message priority
      if (usePriority) {
        String priorityInt = "1";
        if (priority.equals("low")) {
          priorityInt = "3";
        }
        if (priority.equals("normal")) {
          priorityInt = "2";
        }

        msg.setHeader("X-Priority", priorityInt); // (String)int between 1= high and 3 = low.
        msg.setHeader("Importance", importance);
        // seems to be needed for MS Outlook.
        // where it returns a string of high /normal /low.
        msg.setHeader("Sensitivity", sensitivity);
        // Possible values are normal, personal, private, company-confidential

      }

      // Set Mail sender (From)
      String senderAddress = resolve(replyAddress);
      if (!Utils.isEmpty(senderAddress)) {
        String senderName = resolve(replyName);
        if (!Utils.isEmpty(senderName)) {
          senderAddress = senderName + '<' + senderAddress + '>';
        }
        msg.setFrom(new InternetAddress(senderAddress));
      } else {
        throw new MessagingException(
            BaseMessages.getString(PKG, "ActionMail.Error.ReplyEmailNotFilled"));
      }

      // set Reply to addresses
      String replyToAddress = resolve(replyToAddresses);
      if (!Utils.isEmpty(replyToAddress)) {
        // Split the mail-address: variables separated
        String[] replyAddressList = resolve(replyToAddress).split(" ");
        InternetAddress[] address = new InternetAddress[replyAddressList.length];
        for (int i = 0; i < replyAddressList.length; i++) {
          address[i] = new InternetAddress(replyAddressList[i]);
        }
        msg.setReplyTo(address);
      }

      // Split the mail-address: variables separated
      String[] destinations = resolve(destination).split(" ");
      InternetAddress[] address = new InternetAddress[destinations.length];
      for (int i = 0; i < destinations.length; i++) {
        address[i] = new InternetAddress(destinations[i]);
      }
      msg.setRecipients(Message.RecipientType.TO, address);

      String realCC = resolve(getDestinationCc());
      if (!Utils.isEmpty(realCC)) {
        // Split the mail-address Cc: variables separated
        String[] destinationsCc = realCC.split(" ");
        InternetAddress[] addressCc = new InternetAddress[destinationsCc.length];
        for (int i = 0; i < destinationsCc.length; i++) {
          addressCc[i] = new InternetAddress(destinationsCc[i]);
        }

        msg.setRecipients(Message.RecipientType.CC, addressCc);
      }

      String realBCc = resolve(getDestinationBCc());
      if (!Utils.isEmpty(realBCc)) {
        // Split the mail-address BCc: variables separated
        String[] destinationsBCc = realBCc.split(" ");
        InternetAddress[] addressBCc = new InternetAddress[destinationsBCc.length];
        for (int i = 0; i < destinationsBCc.length; i++) {
          addressBCc[i] = new InternetAddress(destinationsBCc[i]);
        }

        msg.setRecipients(Message.RecipientType.BCC, addressBCc);
      }
      String realSubject = resolve(subject);
      if (!Utils.isEmpty(realSubject)) {
        msg.setSubject(realSubject);
      }

      msg.setSentDate(new Date());
      StringBuilder messageText = new StringBuilder();
      String endRow = isUseHTML() ? "<br>" : Const.CR;
      String realComment = resolve(comment);
      if (!Utils.isEmpty(realComment)) {
        messageText.append(realComment).append(Const.CR).append(Const.CR);
      }
      if (!onlySendComment) {

        messageText
            .append(BaseMessages.getString(PKG, "ActionMail.Log.Comment.Workflow"))
            .append(endRow);
        messageText.append("-----").append(endRow);
        messageText
            .append(BaseMessages.getString(PKG, "ActionMail.Log.Comment.JobName") + "    : ")
            .append(parentWorkflow.getWorkflowMeta().getName())
            .append(endRow);
        messageText
            .append(BaseMessages.getString(PKG, "ActionMail.Log.Comment.Action") + "   : ")
            .append(getName())
            .append(endRow);
        messageText.append(Const.CR);
      }

      if (includeDate) {
        messageText
            .append(endRow)
            .append(BaseMessages.getString(PKG, "ActionMail.Log.Comment.MsgDate") + ": ")
            .append(XmlHandler.date2string(new Date()))
            .append(endRow)
            .append(endRow);
      }
      if (!onlySendComment && result != null) {
        messageText
            .append(BaseMessages.getString(PKG, "ActionMail.Log.Comment.PreviousResult") + ":")
            .append(endRow);
        messageText.append("-----------------").append(endRow);
        messageText
            .append(BaseMessages.getString(PKG, "ActionMail.Log.Comment.ActionNr") + "         : ")
            .append(result.getEntryNr())
            .append(endRow);
        messageText
            .append(
                BaseMessages.getString(PKG, "ActionMail.Log.Comment.Errors") + "               : ")
            .append(result.getNrErrors())
            .append(endRow);
        messageText
            .append(
                BaseMessages.getString(PKG, "ActionMail.Log.Comment.LinesRead") + "           : ")
            .append(result.getNrLinesRead())
            .append(endRow);
        messageText
            .append(
                BaseMessages.getString(PKG, "ActionMail.Log.Comment.LinesWritten") + "        : ")
            .append(result.getNrLinesWritten())
            .append(endRow);
        messageText
            .append(
                BaseMessages.getString(PKG, "ActionMail.Log.Comment.LinesInput") + "          : ")
            .append(result.getNrLinesInput())
            .append(endRow);
        messageText
            .append(
                BaseMessages.getString(PKG, "ActionMail.Log.Comment.LinesOutput") + "         : ")
            .append(result.getNrLinesOutput())
            .append(endRow);
        messageText
            .append(
                BaseMessages.getString(PKG, "ActionMail.Log.Comment.LinesUpdated") + "        : ")
            .append(result.getNrLinesUpdated())
            .append(endRow);
        messageText
            .append(
                BaseMessages.getString(PKG, "ActionMail.Log.Comment.LinesRejected") + "       : ")
            .append(result.getNrLinesRejected())
            .append(endRow);
        messageText
            .append(BaseMessages.getString(PKG, "ActionMail.Log.Comment.Status") + "  : ")
            .append(result.getExitStatus())
            .append(endRow);
        messageText
            .append(
                BaseMessages.getString(PKG, "ActionMail.Log.Comment.Result") + "               : ")
            .append(result.getResult())
            .append(endRow);
        messageText.append(endRow);
      }

      if (!onlySendComment
          && (!Utils.isEmpty(resolve(contactPerson)) || !Utils.isEmpty(resolve(contactPhone)))) {
        messageText
            .append(BaseMessages.getString(PKG, "ActionMail.Log.Comment.ContactInfo") + " :")
            .append(endRow);
        messageText.append("---------------------").append(endRow);
        messageText
            .append(BaseMessages.getString(PKG, "ActionMail.Log.Comment.PersonToContact") + " : ")
            .append(resolve(contactPerson))
            .append(endRow);
        messageText
            .append(BaseMessages.getString(PKG, "ActionMail.Log.Comment.Tel") + "  : ")
            .append(resolve(contactPhone))
            .append(endRow);
        messageText.append(endRow);
      }

      // Include the path to this action...
      if (!onlySendComment) {
        WorkflowTracker workflowTracker = parentWorkflow.getWorkflowTracker();
        if (workflowTracker != null) {
          messageText
              .append(BaseMessages.getString(PKG, "ActionMail.Log.Comment.PathToJobentry") + ":")
              .append(endRow);
          messageText.append("------------------------").append(endRow);

          addBacktracking(workflowTracker, messageText);
          if (isUseHTML()) {
            messageText.replace(
                0, messageText.length(), messageText.toString().replace(Const.CR, endRow));
          }
        }
      }

      MimeMultipart parts = new MimeMultipart();
      MimeBodyPart part1 = new MimeBodyPart(); // put the text in the
      // Attached files counter
      int nrattachedFiles = 0;

      // 1st part

      if (useHTML) {
        if (!Utils.isEmpty(getEncoding())) {
          part1.setContent(messageText.toString(), "text/html; " + "charset=" + getEncoding());
        } else {
          part1.setContent(messageText.toString(), "text/html; " + "charset=ISO-8859-1");
        }
      } else {
        part1.setText(messageText.toString());
      }

      parts.addBodyPart(part1);

      if (includingFiles && result != null) {
        List<ResultFile> resultFiles = result.getResultFilesList();
        if (resultFiles != null && !resultFiles.isEmpty()) {
          if (!zipFiles) {
            // Add all files to the message...
            //
            for (ResultFile resultFile : resultFiles) {
              FileObject file = resultFile.getFile();
              if (file != null && file.exists()) {
                boolean found = false;
                for (ActionMailFileTypeField fileTypeField : fileTypes) {
                  if (fileTypeField.getFileType().equals(resultFile.getTypeDesc())) {
                    found = true;
                  }
                }
                if (found) {
                  // create a data source
                  MimeBodyPart files = new MimeBodyPart();
                  URLDataSource fds = new URLDataSource(file.getURL());

                  // get a data IHandler to manipulate this file type
                  files.setDataHandler(new DataHandler(fds));
                  // include the file in the data source
                  files.setFileName(file.getName().getBaseName());

                  // insist on base64 to preserve line endings
                  files.addHeader("Content-Transfer-Encoding", "base64");

                  // add the part with the file in the BodyPart()
                  parts.addBodyPart(files);
                  nrattachedFiles++;
                  logBasic("Added file '" + fds.getName() + "' to the mail message.");
                }
              }
            }
          } else {
            // create a single ZIP archive of all files
            masterZipfile =
                new File(
                    System.getProperty("java.io.tmpdir")
                        + Const.FILE_SEPARATOR
                        + resolve(zipFilename));
            ZipOutputStream zipOutputStream = null;
            try {
              zipOutputStream = new ZipOutputStream(new FileOutputStream(masterZipfile));

              for (ResultFile resultFile : resultFiles) {
                boolean found = false;
                for (int i = 0; i < fileTypes.size(); i++) {
                  if (fileTypes.get(i).getFileType().equals(resultFile.getTypeDesc())) {
                    found = true;
                  }
                }
                if (found) {
                  FileObject file = resultFile.getFile();
                  ZipEntry zipEntry = new ZipEntry(file.getName().getBaseName());
                  zipOutputStream.putNextEntry(zipEntry);

                  // Now put the content of this file into this archive...
                  BufferedInputStream inputStream =
                      new BufferedInputStream(HopVfs.getInputStream(file));
                  try {
                    int c;
                    while ((c = inputStream.read()) >= 0) {
                      zipOutputStream.write(c);
                    }
                  } finally {
                    inputStream.close();
                  }
                  zipOutputStream.closeEntry();
                  nrattachedFiles++;
                  logBasic(
                      "Added file '"
                          + file.getName().getURI()
                          + "' to the mail message in a zip archive.");
                }
              }
            } catch (Exception e) {
              logError(
                  "Error zipping attachement files into file ["
                      + masterZipfile.getPath()
                      + "] : "
                      + e.toString());
              logError(Const.getStackTracker(e));
              result.setNrErrors(1);
            } finally {
              if (zipOutputStream != null) {
                try {
                  zipOutputStream.finish();
                  zipOutputStream.close();
                } catch (IOException e) {
                  logError("Unable to close attachement zip file archive : " + e.toString());
                  logError(Const.getStackTracker(e));
                  result.setNrErrors(1);
                }
              }
            }

            // Now attach the master zip file to the message.
            if (result.getNrErrors() == 0) {
              // create a data source
              MimeBodyPart files = new MimeBodyPart();
              FileDataSource fds = new FileDataSource(masterZipfile);
              // get a data IHandler to manipulate this file type
              files.setDataHandler(new DataHandler(fds));
              // include the file in the data source
              files.setFileName(fds.getName());
              // add the part with the file in the BodyPart()
              parts.addBodyPart(files);
            }
          }
        }
      }

      int nrEmbeddedImages = 0;
      if (embeddedimages != null && embeddedimages.size() > 0) {
        FileObject imageFile = null;
        for (int i = 0; i < embeddedimages.size(); i++) {
          String realImageFile = resolve(embeddedimages.get(i).getEmbeddedimage());
          String realcontenID = resolve(embeddedimages.get(i).getContentId());
          if (messageText.indexOf("cid:" + realcontenID) < 0) {
            if (isDebug()) {
              logDebug("Image [" + realImageFile + "] is not used in message body!");
            }
          } else {
            try {
              boolean found = false;
              imageFile = HopVfs.getFileObject(realImageFile);
              if (imageFile.exists() && imageFile.getType() == FileType.FILE) {
                found = true;
              } else {
                logError("We can not find [" + realImageFile + "] or it is not a file");
              }
              if (found) {
                // Create part for the image
                MimeBodyPart messageBodyPart = new MimeBodyPart();
                // Load the image
                URLDataSource fds = new URLDataSource(imageFile.getURL());
                messageBodyPart.setDataHandler(new DataHandler(fds));
                // Setting the header
                messageBodyPart.setHeader("Content-ID", "<" + realcontenID + ">");
                // Add part to multi-part
                parts.addBodyPart(messageBodyPart);
                nrEmbeddedImages++;
                logBasic("Image '" + fds.getName() + "' was embedded in message.");
              }
            } catch (Exception e) {
              logError(
                  "Error embedding image [" + realImageFile + "] in message : " + e.toString());
              logError(Const.getStackTracker(e));
              result.setNrErrors(1);
            } finally {
              if (imageFile != null) {
                try {
                  imageFile.close();
                } catch (Exception e) {
                  /* Ignore */
                }
              }
            }
          }
        }
      }

      if (nrEmbeddedImages > 0 && nrattachedFiles == 0) {
        // If we need to embedd images...
        // We need to create a "multipart/related" message.
        // otherwise image will appear as attached file
        parts.setSubType("related");
      }
      // put all parts together
      msg.setContent(parts);

      Transport transport = null;
      try {
        if (!StringUtils.isEmpty(connectionName)) {
          transport = connection.getTransport();
        } else {
          transport = session.getTransport(protocol);
          String authPass = getPassword(authenticationPassword);

          if (usingAuthentication) {
            if (!Utils.isEmpty(port)) {
              transport.connect(
                  resolve(Const.NVL(server, "")),
                  Integer.parseInt(resolve(Const.NVL(port, ""))),
                  resolve(Const.NVL(authenticationUser, "")),
                  authPass);
            } else {
              transport.connect(
                  resolve(Const.NVL(server, "")),
                  resolve(Const.NVL(authenticationUser, "")),
                  authPass);
            }
          } else {
            transport.connect();
          }
        }
        transport.sendMessage(msg, msg.getAllRecipients());
      } finally {
        if (transport != null) {
          transport.close();
        }
      }
    } catch (IOException e) {
      logError("Problem while sending message: " + e.toString());
      result.setNrErrors(1);
    } catch (MessagingException mex) {
      logError("Problem while sending message: " + mex.toString());
      result.setNrErrors(1);

      Exception ex = mex;
      do {
        if (ex instanceof SendFailedException sfex) {
          Address[] invalid = sfex.getInvalidAddresses();
          if (invalid != null) {
            logError("    ** Invalid Addresses");
            for (int i = 0; i < invalid.length; i++) {
              logError(CONST_SPACES_LONG + invalid[i]);
              result.setNrErrors(1);
            }
          }

          Address[] validUnsent = sfex.getValidUnsentAddresses();
          if (validUnsent != null) {
            logError("    ** ValidUnsent Addresses");
            for (int i = 0; i < validUnsent.length; i++) {
              logError(CONST_SPACES_LONG + validUnsent[i]);
              result.setNrErrors(1);
            }
          }

          Address[] validSent = sfex.getValidSentAddresses();
          if (validSent != null) {
            for (int i = 0; i < validSent.length; i++) {
              logError(CONST_SPACES_LONG + validSent[i]);
              result.setNrErrors(1);
            }
          }
        }
        if (ex instanceof MessagingException messagingException) {
          ex = messagingException.getNextException();
        } else {
          ex = null;
        }
      } while (ex != null);
    } finally {
      if (masterZipfile != null && masterZipfile.exists()) {
        masterZipfile.delete();
      }
    }

    if (result.getNrErrors() > 0) {
      result.setResult(false);
    } else {
      result.setResult(true);
    }

    return result;
  }