private boolean executePresendScript(
      AbstractBuild<?, ?> build,
      BuildListener listener,
      MimeMessage msg,
      EmailTrigger trigger,
      Map<String, EmailTrigger> triggered)
      throws RuntimeException {
    boolean cancel = false;
    presendScript = new ContentBuilder().transformText(presendScript, this, build, listener);
    if (StringUtils.isNotBlank(presendScript)) {
      listener.getLogger().println("Executing pre-send script");
      ClassLoader cl = Jenkins.getInstance().getPluginManager().uberClassLoader;
      ScriptSandbox sandbox = null;
      CompilerConfiguration cc = new CompilerConfiguration();
      cc.addCompilationCustomizers(
          new ImportCustomizer()
              .addStarImports("jenkins", "jenkins.model", "hudson", "hudson.model"));

      if (ExtendedEmailPublisher.DESCRIPTOR.isSecurityEnabled()) {
        debug(listener.getLogger(), "Setting up sandbox for pre-send script");
        cc.addCompilationCustomizers(new SandboxTransformer());
        sandbox = new ScriptSandbox();
      }

      Binding binding = new Binding();
      binding.setVariable("build", build);
      binding.setVariable("msg", msg);
      binding.setVariable("logger", listener.getLogger());
      binding.setVariable("cancel", cancel);
      binding.setVariable("trigger", trigger);
      binding.setVariable("triggered", Collections.unmodifiableMap(triggered));

      GroovyShell shell = new GroovyShell(cl, binding, cc);
      StringWriter out = new StringWriter();
      PrintWriter pw = new PrintWriter(out);

      if (sandbox != null) {
        sandbox.register();
      }

      try {
        Object output = shell.evaluate(presendScript);
        if (output != null) {
          pw.println("Result: " + output);
          cancel = ((Boolean) shell.getVariable("cancel")).booleanValue();
          debug(listener.getLogger(), "Pre-send script set cancel to %b", cancel);
        }
      } catch (SecurityException e) {
        listener
            .getLogger()
            .println("Pre-send script tried to access secured objects: " + e.getMessage());
      } catch (Throwable t) {
        t.printStackTrace(pw);
        listener.getLogger().println(out.toString());
        // should we cancel the sending of the email???
      }
      debug(listener.getLogger(), out.toString());
    }
    return !cancel;
  }
 @Override
 public boolean prebuild(AbstractBuild<?, ?> build, BuildListener listener) {
   debug(listener.getLogger(), "Checking for pre-build");
   if (!(build instanceof MatrixRun) || isExecuteOnMatrixNodes()) {
     debug(listener.getLogger(), "Executing pre-build step");
     return _perform(build, listener, true);
   }
   return true;
 }
 @Override
 public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener)
     throws InterruptedException, IOException {
   debug(listener.getLogger(), "Checking for post-build");
   if (!(build instanceof MatrixRun) || isExecuteOnMatrixNodes()) {
     debug(listener.getLogger(), "Performing post-build step");
     return _perform(build, listener, false);
   }
   return true;
 }
  private MimeBodyPart getContent(
      final EmailType type,
      final AbstractBuild<?, ?> build,
      BuildListener listener,
      String charset,
      EmailTrigger trigger)
      throws MessagingException {
    final String text = new ContentBuilder().transformText(type.getBody(), this, build, listener);

    String messageContentType = contentType;
    // contentType is null if the project was not reconfigured after upgrading.
    if (messageContentType == null || "default".equals(messageContentType)) {
      messageContentType = DESCRIPTOR.getDefaultContentType();
      // The defaultContentType is null if the main Jenkins configuration
      // was not reconfigured after upgrading.
      if (messageContentType == null) {
        messageContentType = "text/plain";
      }
    }
    messageContentType += "; charset=" + charset;

    try {
      if (saveOutput) {
        Random random = new Random();
        String extension = ".html";
        if (messageContentType.startsWith("text/plain")) {
          extension = ".txt";
        }

        FilePath savedOutput =
            new FilePath(
                build.getWorkspace(),
                String.format(
                    "%s-%s%d%s",
                    trigger.getDescriptor().getDisplayName(),
                    build.getId(),
                    random.nextInt(),
                    extension));
        savedOutput.write(text, charset);
      }
    } catch (IOException e) {
      listener.getLogger().println("Error trying to save email output to file. " + e.getMessage());
    } catch (InterruptedException e) {
      listener.getLogger().println("Error trying to save email output to file. " + e.getMessage());
    }

    // set the email message text
    // (plain text or HTML depending on the content type)
    MimeBodyPart msgPart = new MimeBodyPart();
    debug(listener.getLogger(), "messageContentType = %s", messageContentType);
    if (messageContentType.startsWith("text/html")) {
      String inlinedCssHtml = new CssInliner().process(text);
      msgPart.setContent(inlinedCssHtml, messageContentType);
    } else {
      msgPart.setContent(text, messageContentType);
    }
    return msgPart;
  }
  private boolean _perform(AbstractBuild<?, ?> build, BuildListener listener, boolean forPreBuild) {
    boolean emailTriggered = false;
    debug(listener.getLogger(), "Checking if email needs to be generated");
    Map<String, EmailTrigger> triggered = new HashMap<String, EmailTrigger>();

    for (EmailTrigger trigger : configuredTriggers) {
      if (trigger.isPreBuild() == forPreBuild && trigger.trigger(build, listener)) {
        String tName = trigger.getDescriptor().getDisplayName();
        triggered.put(tName, trigger);
        listener.getLogger().println("Email was triggered for: " + tName);
        emailTriggered = true;
      }
    }

    // Go through and remove triggers that are replaced by others
    List<String> replacedTriggers = new ArrayList<String>();

    for (String triggerName : triggered.keySet()) {
      replacedTriggers.addAll(triggered.get(triggerName).getDescriptor().getTriggerReplaceList());
    }
    for (String triggerName : replacedTriggers) {
      triggered.remove(triggerName);
      listener
          .getLogger()
          .println(
              "Trigger "
                  + triggerName
                  + " was overridden by another trigger and will not send an email.");
    }

    if (emailTriggered && triggered.isEmpty()) {
      listener
          .getLogger()
          .println(
              "There is a circular trigger replacement with the email triggers.  No email is sent.");
      return false;
    } else if (triggered.isEmpty()) {
      listener.getLogger().println("No emails were triggered.");
      return true;
    }

    for (String triggerName : triggered.keySet()) {
      listener.getLogger().println("Sending email for trigger: " + triggerName);
      sendMail(
          triggered.get(triggerName).getEmail(),
          build,
          listener,
          triggered.get(triggerName),
          triggered);
    }

    return true;
  }
  private MimeMessage createMail(
      EmailType type, AbstractBuild<?, ?> build, BuildListener listener, EmailTrigger trigger)
      throws MessagingException, IOException, InterruptedException {
    boolean overrideGlobalSettings = ExtendedEmailPublisher.DESCRIPTOR.getOverrideGlobalSettings();

    MimeMessage msg;

    // If not overriding global settings, use the Mailer class to create a session and set the from
    // address
    // Else we'll do it ourselves
    if (!overrideGlobalSettings) {
      debug(
          listener.getLogger(),
          "NOT overriding default server settings, using Mailer to create session");
      msg = new MimeMessage(Mailer.descriptor().createSession());
      msg.setFrom(new InternetAddress(Mailer.descriptor().getAdminAddress()));
    } else {
      debug(listener.getLogger(), "Overriding default server settings, creating our own session");
      msg = new MimeMessage(ExtendedEmailPublisher.DESCRIPTOR.createSession());
      msg.setFrom(new InternetAddress(ExtendedEmailPublisher.DESCRIPTOR.getAdminAddress()));
    }

    String charset = Mailer.descriptor().getCharset();
    if (overrideGlobalSettings) {
      String overrideCharset = ExtendedEmailPublisher.DESCRIPTOR.getCharset();
      if (StringUtils.isNotBlank(overrideCharset)) {
        debug(listener.getLogger(), "Overriding charset %s", overrideCharset);
        charset = overrideCharset;
      }
    }

    // Set the contents of the email
    msg.addHeader("X-Jenkins-Job", build.getProject().getDisplayName());
    if (build.getResult() != null) {
      msg.addHeader("X-Jenkins-Result", build.getResult().toString());
    }
    msg.setSentDate(new Date());
    setSubject(type, build, msg, listener, charset);

    Multipart multipart = new MimeMultipart();
    multipart.addBodyPart(getContent(type, build, listener, charset, trigger));

    AttachmentUtils attachments = new AttachmentUtils(attachmentsPattern);
    attachments.attach(multipart, this, build, listener);

    // add attachments from the email type if they are setup
    if (StringUtils.isNotBlank(type.getAttachmentsPattern())) {
      AttachmentUtils typeAttachments = new AttachmentUtils(type.getAttachmentsPattern());
      typeAttachments.attach(multipart, this, build, listener);
    }

    if (attachBuildLog || type.getAttachBuildLog()) {
      debug(listener.getLogger(), "Request made to attach build log");
      AttachmentUtils.attachBuildLog(
          multipart, build, listener, compressBuildLog || type.getCompressBuildLog());
    }

    msg.setContent(multipart);

    EnvVars env = null;
    try {
      env = build.getEnvironment(listener);
    } catch (Exception e) {
      listener.getLogger().println("Error retrieving environment vars: " + e.getMessage());
      // create an empty set of env vars
      env = new EnvVars();
    }

    // Get the recipients from the global list of addresses
    Set<InternetAddress> recipientAddresses = new LinkedHashSet<InternetAddress>();
    Set<InternetAddress> ccAddresses = new LinkedHashSet<InternetAddress>();
    if (type.getSendToRecipientList()) {
      debug(listener.getLogger(), "Adding recipients from recipient list");
      addAddressesFromRecipientList(
          recipientAddresses,
          ccAddresses,
          getRecipientList(type, build, recipientList, listener, charset),
          env,
          listener);
    }
    // Get the list of developers who made changes between this build and the last
    // if this mail type is configured that way
    if (type.getSendToDevelopers()) {
      debug(listener.getLogger(), "Adding developers");
      Set<User> users;
      if (type.getIncludeCulprits()) {
        users = build.getCulprits();
      } else {
        users = new HashSet<User>();
        for (Entry change : build.getChangeSet()) {
          users.add(change.getAuthor());
        }
      }

      for (User user : users) {
        if (!isExcludedCommitter(user.getFullName())) {
          String userAddress = EmailRecipientUtils.getUserConfiguredEmail(user);
          if (userAddress != null) {
            addAddressesFromRecipientList(
                recipientAddresses, ccAddresses, userAddress, env, listener);
          } else {
            listener
                .getLogger()
                .println(
                    "Failed to send e-mail to "
                        + user.getFullName()
                        + " because no e-mail address is known, and no default e-mail domain is configured");
          }
        }
      }
    }

    if (type.isSendToRequester()) {
      debug(listener.getLogger(), "Sending to requester");
      // looking for Upstream build.
      AbstractBuild<?, ?> cur = build;
      Cause.UpstreamCause upc = build.getCause(Cause.UpstreamCause.class);
      while (upc != null) {
        // UpstreamCause.getUpStreamProject() returns the full name, so use getItemByFullName
        AbstractProject<?, ?> p =
            (AbstractProject<?, ?>)
                Hudson.getInstance().getItemByFullName(upc.getUpstreamProject());
        cur = p.getBuildByNumber(upc.getUpstreamBuild());
        upc = cur.getCause(Cause.UpstreamCause.class);
      }
      addUserTriggeringTheBuild(cur, recipientAddresses, ccAddresses, env, listener);
    }

    // Get the list of recipients that are uniquely specified for this type of email
    if (StringUtils.isNotBlank(type.getRecipientList())) {
      addAddressesFromRecipientList(
          recipientAddresses,
          ccAddresses,
          getRecipientList(type, build, type.getRecipientList(), listener, charset),
          env,
          listener);
    }

    String emergencyReroute = ExtendedEmailPublisher.DESCRIPTOR.getEmergencyReroute();
    boolean isEmergencyReroute = StringUtils.isNotBlank(emergencyReroute);

    if (isEmergencyReroute) {
      debug(listener.getLogger(), "Emergency reroute turned on");
      recipientAddresses.clear();
      addAddressesFromRecipientList(
          recipientAddresses, ccAddresses, emergencyReroute, env, listener);
      listener.getLogger().println("Emergency reroute is set to: " + emergencyReroute);
    }

    msg.setRecipients(
        Message.RecipientType.TO,
        recipientAddresses.toArray(new InternetAddress[recipientAddresses.size()]));
    if (ccAddresses.size() > 0) {
      msg.setRecipients(
          Message.RecipientType.CC, ccAddresses.toArray(new InternetAddress[ccAddresses.size()]));
    }

    Set<InternetAddress> replyToAddresses = new LinkedHashSet<InternetAddress>();
    if (StringUtils.isNotBlank(replyTo)) {
      addAddressesFromRecipientList(
          replyToAddresses,
          null,
          getRecipientList(type, build, replyTo, listener, charset),
          env,
          listener);
    }

    if (StringUtils.isNotBlank(type.getReplyTo())) {
      addAddressesFromRecipientList(
          replyToAddresses,
          null,
          getRecipientList(type, build, type.getReplyTo(), listener, charset),
          env,
          listener);
    }

    if (replyToAddresses.size() > 0) {
      msg.setReplyTo(replyToAddresses.toArray(new InternetAddress[replyToAddresses.size()]));
    }

    AbstractBuild<?, ?> pb = build.getPreviousBuild();
    if (pb != null) {
      // Send mails as replies until next successful build
      MailMessageIdAction b = pb.getAction(MailMessageIdAction.class);
      if (b != null && pb.getResult() != Result.SUCCESS) {
        debug(listener.getLogger(), "Setting In-Reply-To since last build was not successful");
        msg.setHeader("In-Reply-To", b.messageId);
        msg.setHeader("References", b.messageId);
      }
    }

    if (CONTENT_TRANSFER_ENCODING != null) {
      msg.setHeader("Content-Transfer-Encoding", CONTENT_TRANSFER_ENCODING);
    }

    String listId = ExtendedEmailPublisher.DESCRIPTOR.getListId();
    if (listId != null) {
      msg.setHeader("List-ID", listId);
    }

    if (ExtendedEmailPublisher.DESCRIPTOR.getPrecedenceBulk()) {
      msg.setHeader("Precedence", "bulk");
    }

    return msg;
  }
  private boolean sendMail(
      EmailType mailType,
      AbstractBuild<?, ?> build,
      BuildListener listener,
      EmailTrigger trigger,
      Map<String, EmailTrigger> triggered) {
    try {
      MimeMessage msg = createMail(mailType, build, listener, trigger);
      debug(listener.getLogger(), "Successfully created MimeMessage");
      Address[] allRecipients = msg.getAllRecipients();
      int retries = 0;
      if (allRecipients != null) {
        StringBuilder buf = new StringBuilder("Sending email to:");
        for (Address a : allRecipients) {
          buf.append(' ').append(a);
        }
        listener.getLogger().println(buf);
        if (executePresendScript(build, listener, msg, trigger, triggered)) {
          while (true) {
            try {
              Transport.send(msg);
              break;
            } catch (SendFailedException e) {
              if (e.getNextException() != null
                  && ((e.getNextException() instanceof SocketException)
                      || (e.getNextException() instanceof ConnectException))) {
                listener
                    .getLogger()
                    .println("Socket error sending email, retrying once more in 10 seconds...");
                Thread.sleep(10000);
              } else {
                Address[] addresses = e.getValidSentAddresses();
                if (addresses != null && addresses.length > 0) {
                  buf = new StringBuilder("Successfully sent to the following addresses:");
                  for (Address a : addresses) {
                    buf.append(' ').append(a);
                  }
                  listener.getLogger().println(buf);
                }
                addresses = e.getValidUnsentAddresses();
                if (addresses != null && addresses.length > 0) {
                  buf = new StringBuilder("Error sending to the following VALID addresses:");
                  for (Address a : addresses) {
                    buf.append(' ').append(a);
                  }
                  listener.getLogger().println(buf);
                }
                addresses = e.getInvalidAddresses();
                if (addresses != null && addresses.length > 0) {
                  buf = new StringBuilder("Error sending to the following INVALID addresses:");
                  for (Address a : addresses) {
                    buf.append(' ').append(a);
                  }
                  listener.getLogger().println(buf);
                }

                debug(listener.getLogger(), "SendFailedException message: " + e.getMessage());
                break;
              }
            }
            retries++;
            if (retries > 1) {
              listener.getLogger().println("Failed after second try sending email");
              break;
            }
          }
          if (build.getAction(MailMessageIdAction.class) == null) {
            build.addAction(new MailMessageIdAction(msg.getMessageID()));
          }
        } else {
          listener.getLogger().println("Email sending was cancelled" + " by user script.");
        }
        return true;
      } else {
        listener
            .getLogger()
            .println("An attempt to send an e-mail" + " to empty list of recipients, ignored.");
      }
    } catch (Exception e) {
      LOGGER.log(Level.WARNING, "Could not send email.", e);
      e.printStackTrace(
          listener.error("Could not send email as a part of the post-build publishers."));
    }

    debug(
        listener.getLogger(),
        "Some error occured trying to send the email...check the Jenkins log");
    return false;
  }