private MultiPartEmail constructMessage(
      Content contentNode,
      List<String> recipients,
      javax.jcr.Session session,
      org.sakaiproject.nakamura.api.lite.Session sparseSession)
      throws EmailDeliveryException, StorageClientException, AccessDeniedException,
          PathNotFoundException, RepositoryException {
    MultiPartEmail email = new MultiPartEmail();
    // TODO: the SAKAI_TO may make no sense in an email context
    // and there does not appear to be any distinction between Bcc and To in java mail.

    Set<String> toRecipients = new HashSet<String>();
    Set<String> bccRecipients = new HashSet<String>();
    for (String r : recipients) {
      bccRecipients.add(convertToEmail(r.trim(), sparseSession));
    }

    if (contentNode.hasProperty(MessageConstants.PROP_SAKAI_TO)) {
      String[] tor =
          StringUtils.split((String) contentNode.getProperty(MessageConstants.PROP_SAKAI_TO), ',');
      for (String r : tor) {
        r = convertToEmail(r.trim(), sparseSession);
        if (bccRecipients.contains(r)) {
          toRecipients.add(r);
          bccRecipients.remove(r);
        }
      }
    }
    for (String r : toRecipients) {
      try {
        email.addTo(convertToEmail(r, sparseSession));
      } catch (EmailException e) {
        throw new EmailDeliveryException(
            "Invalid To Address [" + r + "], message is being dropped :" + e.getMessage(), e);
      }
    }
    for (String r : bccRecipients) {
      try {
        email.addBcc(convertToEmail(r, sparseSession));
      } catch (EmailException e) {
        throw new EmailDeliveryException(
            "Invalid Bcc Address [" + r + "], message is being dropped :" + e.getMessage(), e);
      }
    }

    if (contentNode.hasProperty(MessageConstants.PROP_SAKAI_FROM)) {
      String from = (String) contentNode.getProperty(MessageConstants.PROP_SAKAI_FROM);
      try {
        email.setFrom(convertToEmail(from, sparseSession));
      } catch (EmailException e) {
        throw new EmailDeliveryException(
            "Invalid From Address [" + from + "], message is being dropped :" + e.getMessage(), e);
      }
    } else {
      throw new EmailDeliveryException("Must provide a 'from' address.");
    }

    if (contentNode.hasProperty(MessageConstants.PROP_SAKAI_BODY)) {
      String messageBody = (String) contentNode.getProperty(MessageConstants.PROP_SAKAI_BODY);
      // if this message has a template, use it
      LOGGER.debug(
          "Checking for sakai:templatePath and sakai:templateParams properties on the outgoing message's node.");
      if (contentNode.hasProperty(MessageConstants.PROP_TEMPLATE_PATH)
          && contentNode.hasProperty(MessageConstants.PROP_TEMPLATE_PARAMS)) {
        Map<String, String> parameters =
            getTemplateProperties(
                (String) contentNode.getProperty(MessageConstants.PROP_TEMPLATE_PARAMS));
        String templatePath = (String) contentNode.getProperty(MessageConstants.PROP_TEMPLATE_PATH);
        LOGGER.debug("Got the path '{0}' to the template for this outgoing message.", templatePath);
        Node templateNode = session.getNode(templatePath);
        if (templateNode.hasProperty("sakai:template")) {
          String template = templateNode.getProperty("sakai:template").getString();
          LOGGER.debug("Pulled the template body from the template node: {0}", template);
          messageBody = templateService.evaluateTemplate(parameters, template);
          LOGGER.debug("Performed parameter substitution in the template: {0}", messageBody);
        }
      } else {
        LOGGER.debug(
            "Message node '{0}' does not have sakai:templatePath and sakai:templateParams properties",
            contentNode.getPath());
      }
      try {
        email.setMsg(messageBody);
      } catch (EmailException e) {
        throw new EmailDeliveryException(
            "Invalid Message Body, message is being dropped :" + e.getMessage(), e);
      }
    }

    if (contentNode.hasProperty(MessageConstants.PROP_SAKAI_SUBJECT)) {
      email.setSubject((String) contentNode.getProperty(MessageConstants.PROP_SAKAI_SUBJECT));
    }

    ContentManager contentManager = sparseSession.getContentManager();
    for (String streamId : contentNode.listStreams()) {
      String description = null;
      if (contentNode.hasProperty(
          StorageClientUtils.getAltField(
              MessageConstants.PROP_SAKAI_ATTACHMENT_DESCRIPTION, streamId))) {
        description =
            (String)
                contentNode.getProperty(
                    StorageClientUtils.getAltField(
                        MessageConstants.PROP_SAKAI_ATTACHMENT_DESCRIPTION, streamId));
      }
      LiteEmailDataSource ds = new LiteEmailDataSource(contentManager, contentNode, streamId);
      try {
        email.attach(ds, streamId, description);
      } catch (EmailException e) {
        throw new EmailDeliveryException(
            "Invalid Attachment [" + streamId + "] message is being dropped :" + e.getMessage(), e);
      }
    }
    return email;
  }