public void sendMessage()

in api/src/main/java/com/google/appengine/api/mail/stdimpl/GMTransport.java [126:305]


  public void sendMessage(Message message, Address[] addresses)
      throws MessagingException {
    MailService service = MailServiceFactory.getMailService();
    MailService.Message msg = new MailService.Message();

    // fill in message sender. If there is a Sender: header field we use
    // that, otherwise we use the From: field.
    String sender = null;
    if (message instanceof MimeMessage) {
      Address senderAddr = ((MimeMessage) message).getSender();
      if (senderAddr != null) {
        sender = senderAddr.toString();
      }
    }
    if (sender == null && message.getFrom() != null
        && message.getFrom().length > 0) {
      // there better be a from address, or we fail right here
      // in RFC822 it's okay to have multiple from addresses, but not for
      // Prometheus. We pick the first one only.
      sender = message.getFrom()[0].toString();
    }
    // mail_service.cc does a string compare on this. so, be precise.
    msg.setSender(sender);

    // optionally fill in reply-to header verbatim,
    // keeping multiple addresses, if present
    // the default javaMail implementation returns the From: address
    // array, if no Reply-To: header is present, which gives us a way
    // to preserve multiple from addresses
    try {
      msg.setReplyTo(Joiner.on(", ").useForNull("null").join(message.getReplyTo()));
    } catch (NullPointerException e) {
      // don't do anything, the header field will stay unset
    }

    //is this intended to go to Admins?
    boolean toAdmins = false;
    Address[] allRecipients = message.getAllRecipients();
    if (allRecipients != null) {
      for (Address addr : allRecipients) {
        if (ADMINS_ADDRESS.equals(addr.toString())) {
          toAdmins = true;
        }
      }
    }

    // fill in To:, Cc:, Bcc: header, if present.
    // Otherwise they will be (re-set) to null.
    if (!toAdmins) {
      Set<String> allAddresses = new HashSet<String>();
      for (Address addr : addresses) {
        allAddresses.add(addr.toString());
      }
      msg.setTo(convertAddressFields(message.getRecipients(RecipientType.TO), allAddresses));
      msg.setCc(convertAddressFields(message.getRecipients(RecipientType.CC), allAddresses));
      msg.setBcc(convertAddressFields(message.getRecipients(RecipientType.BCC), allAddresses));
    }

    // subject
    msg.setSubject(message.getSubject());

    //text and html bodies
    Object textObject = null;
    Object htmlObject = null;
    Object ampHtmlObject = null;
    String textType = null;
    String htmlType = null;
    String ampHtmlType = null;
    Multipart otherMessageParts = null;

    // headers
    List<MailService.Header> headers = new ArrayList<MailService.Header>();
    // The message exposes all fields as headers so we need to fetch only those
    // that are allowlisted.
    @SuppressWarnings("unchecked")
    List<Header> originalHeaders = Collections.list(message.getMatchingHeaders(HEADERS_ALLOWLIST));
    for (Header header : originalHeaders) {
      headers.add(new MailService.Header(header.getName(), header.getValue()));
    }
    msg.setHeaders(headers);

    if (message.getContentType() == null) {
      // it's not defined, and it's not a MimeMessage (which would force this
      // to be text/plain) -- treat this as a 'plain' text body.
      try {
        textObject = message.getContent();
        textType = message.getContentType();
      } catch (IOException e) {
        throw new MessagingException("Getting typeless content failed", e);
      }
    } else if (message.isMimeType("text/html")) {
      try {
        htmlObject = message.getContent();
        htmlType = message.getContentType();
      } catch (IOException e) {
        throw new MessagingException("Getting html content failed", e);
      }
    } else if (message.isMimeType("text/*")) {
      // text body (could be anything, but we treat it as plain). Otherwise,
      // we'd have to trash all but plain explicitly, which I find rude.
      try {
        textObject = message.getContent();
        textType = message.getContentType();
      } catch (IOException e) {
        throw new MessagingException("Getting text/* content failed", e);
      }
    } else if (message.isMimeType("multipart/*")) {
      // ah, now the fun starts once again. lets find a first plain and/or
      // html part to use them as the message body. we also clone the multipart
      // since we don't want to modify the original input by deleting parts.
      // this will also give you a runtime exception if the returned object
      // is not really a Multipart.
      Multipart mp;
      try {
        mp = (Multipart) message.getContent();
        for (int i = 0; i < mp.getCount(); i++) {
          BodyPart bp = mp.getBodyPart(i);
          if (bp.isMimeType("text/plain") && textObject == null && canInline(message, bp)) {
            textObject = bp.getContent();
            textType = bp.getContentType();
          } else if (bp.isMimeType("text/html") && htmlObject == null && canInline(message, bp)) {
            htmlObject = bp.getContent();
            htmlType = bp.getContentType();
          } else if (bp.isMimeType("text/x-amp-html")
              && ampHtmlObject == null
              && canInline(message, bp)) {
            ampHtmlObject = bp.getContent();
            ampHtmlType = bp.getContentType();
          } else {
            if (otherMessageParts == null) {
              String type = mp.getContentType();
              assert (type.startsWith("multipart/"));
              otherMessageParts = new MimeMultipart(
                  type.substring("multipart/".length()));
            }
            otherMessageParts.addBodyPart(bp);
          }
        }
      } catch (IOException e) {
        throw new MessagingException("Getting multipart content failed", e);
      }
    }

    if (textObject != null) {
      msg.setTextBody(convertAttachmentToString(textObject, textType));
    }

    if (htmlObject != null) {
      msg.setHtmlBody(convertAttachmentToString(htmlObject, htmlType));
    }

    if (ampHtmlObject != null) {
      msg.setAmpHtmlBody(convertAttachmentToString(ampHtmlObject, ampHtmlType));
    }

    // convert arbitrary attachments
    // fail for missing filenames
    if (otherMessageParts != null) {
      msg.setAttachments(convertAttachments(otherMessageParts));
    }

    try {
      if (toAdmins) {
        service.sendToAdmins(msg);
      } else {
        service.send(msg);
      }
    } catch (IOException e) {
      notifyTransportListeners(
          TransportEvent.MESSAGE_NOT_DELIVERED, new Address[0], addresses,
          new Address[0], message);
      throw new SendFailedException("MailService IO failed", e);
    } catch (IllegalArgumentException e) {
      throw new MessagingException("Illegal Arguments", e);
    }

    notifyTransportListeners(
        TransportEvent.MESSAGE_DELIVERED, addresses, new Address[0],
        new Address[0], message);
  }