/* * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.integration.mail; import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; import org.springframework.core.io.ByteArrayResource; import org.springframework.integration.handler.AbstractMessageHandler; import org.springframework.integration.mapping.MessageMappingException; import org.springframework.mail.MailMessage; import org.springframework.mail.MailSender; import org.springframework.mail.SimpleMailMessage; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.MimeMailMessage; import org.springframework.mail.javamail.MimeMessageHelper; import org.springframework.messaging.Message; import org.springframework.messaging.MessageHandler; import org.springframework.messaging.MessageHandlingException; import org.springframework.messaging.MessageHeaders; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; /** * A {@link MessageHandler} implementation for sending mail. * * <p>If the Message is an instance of {@link MailMessage}, it will be passed * as-is. If the Message payload is a byte array, it will be passed as an * attachment, and in that case, the {@link MailHeaders#ATTACHMENT_FILENAME} * header is required. Otherwise, a String type is expected, and its content * will be used as the text within a {@link SimpleMailMessage}. * * @see MailHeaders * * @author Marius Bogoevici * @author Mark Fisher * @author Oleg Zhurakousky * @author Artem Bilan */ public class MailSendingMessageHandler extends AbstractMessageHandler { private final MailSender mailSender; /** * Create a MailSendingMessageHandler. * @param mailSender the {@link MailSender} instance to which this * adapter will delegate. */ public MailSendingMessageHandler(MailSender mailSender) { Assert.notNull(mailSender, "'mailSender' must not be null"); this.mailSender = mailSender; } @Override public String getComponentType() { return "mail:outbound-channel-adapter"; } @Override protected final void handleMessageInternal(Message<?> message) { MailMessage mailMessage = convertMessageToMailMessage(message); if (mailMessage instanceof SimpleMailMessage) { this.mailSender.send((SimpleMailMessage) mailMessage); } else if (mailMessage instanceof MimeMailMessage) { Assert.state(this.mailSender instanceof JavaMailSender, "this adapter requires a 'JavaMailSender' to send a 'MimeMailMessage'"); ((JavaMailSender) this.mailSender).send(((MimeMailMessage) mailMessage).getMimeMessage()); } else { throw new IllegalArgumentException( "Unsupported MailMessage type [" + mailMessage.getClass().getName() + "]."); } } @SuppressWarnings("unchecked") private MailMessage convertMessageToMailMessage(Message<?> message) { MailMessage mailMessage = null; Object payload = message.getPayload(); if (payload instanceof MimeMessage) { mailMessage = new MimeMailMessage((MimeMessage) payload); } else if (payload instanceof MailMessage) { mailMessage = (MailMessage) payload; } else if (payload instanceof byte[]) { mailMessage = this.createMailMessageFromByteArrayMessage((Message<byte[]>) message); } else if (payload instanceof String) { String contentType = (String) message.getHeaders().get(MailHeaders.CONTENT_TYPE); if (StringUtils.hasText(contentType)) { mailMessage = this.createMailMessageWithContentType((Message<String>) message, contentType); } else { mailMessage = new SimpleMailMessage(); mailMessage.setText((String) payload); } } else { throw new MessageHandlingException(message, "Unable to create MailMessage from payload type [" + message.getPayload().getClass().getName() + "], " + "expected MimeMessage, MailMessage, byte array or String."); } this.applyHeadersToMailMessage(mailMessage, message.getHeaders()); return mailMessage; } private MailMessage createMailMessageWithContentType(Message<String> message, String contentType) { Assert.state(this.mailSender instanceof JavaMailSender, "this adapter requires a 'JavaMailSender' to send a 'MimeMailMessage'"); MimeMessage mimeMessage = ((JavaMailSender) this.mailSender).createMimeMessage(); try { mimeMessage.setContent(message.getPayload(), contentType); return new MimeMailMessage(mimeMessage); } catch (Exception e) { throw new org.springframework.messaging.MessagingException("Failed to create MimeMessage with contentType: " + contentType, e); } } private MailMessage createMailMessageFromByteArrayMessage(Message<byte[]> message) { Assert.state(this.mailSender instanceof JavaMailSender, "this adapter requires a 'JavaMailSender' to send a 'MimeMailMessage'"); String attachmentFileName = message.getHeaders().get(MailHeaders.ATTACHMENT_FILENAME, String.class); if (attachmentFileName == null) { throw new MessageMappingException(message, "Header '" + MailHeaders.ATTACHMENT_FILENAME + "' is required when mapping a Message with a byte array payload to a MailMessage."); } Integer multipartMode = message.getHeaders().get(MailHeaders.MULTIPART_MODE, Integer.class); if (multipartMode == null) { multipartMode = MimeMessageHelper.MULTIPART_MODE_MIXED; } MimeMessage mimeMessage = ((JavaMailSender) this.mailSender).createMimeMessage(); try { MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, multipartMode); helper.addAttachment(attachmentFileName, new ByteArrayResource(message.getPayload())); return new MimeMailMessage(helper); } catch (MessagingException e) { throw new MessageMappingException(message, "failed to create MimeMessage", e); } } private void applyHeadersToMailMessage(MailMessage mailMessage, MessageHeaders headers) { String subject = headers.get(MailHeaders.SUBJECT, String.class); if (subject != null) { mailMessage.setSubject(subject); } String[] to = this.retrieveHeaderValueAsStringArray(headers, MailHeaders.TO); if (to != null) { mailMessage.setTo(to); } if (mailMessage instanceof SimpleMailMessage) { Assert.state(!ObjectUtils.isEmpty(((SimpleMailMessage) mailMessage).getTo()), "No recipient has been provided on the MailMessage or the 'MailHeaders.TO' header."); } String[] cc = this.retrieveHeaderValueAsStringArray(headers, MailHeaders.CC); if (cc != null) { mailMessage.setCc(cc); } String[] bcc = this.retrieveHeaderValueAsStringArray(headers, MailHeaders.BCC); if (bcc != null) { mailMessage.setBcc(bcc); } String from = headers.get(MailHeaders.FROM, String.class); if (from != null) { mailMessage.setFrom(from); } String replyTo = headers.get(MailHeaders.REPLY_TO, String.class); if (replyTo != null) { mailMessage.setReplyTo(replyTo); } } private String[] retrieveHeaderValueAsStringArray(MessageHeaders headers, String key) { Object value = headers.get(key); String[] returnedHeaders = null; if (value != null) { if (value instanceof String[]) { returnedHeaders = (String[]) value; } else if (value instanceof String) { returnedHeaders = StringUtils.commaDelimitedListToStringArray((String) value); } } if (returnedHeaders == null || ObjectUtils.isEmpty(returnedHeaders)) { returnedHeaders = null; } return returnedHeaders; } }