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);
}