INT-3994: Add Option to Map MimeMessage
JIRA: https://jira.spring.io/browse/INT-3994 If a header mapper is injected into the mail receiver, a mapped message is result instead of a message with the raw `MimeMessage`. `MimeMessage` properties are mapped as discrete headers; in addition the raw email headers are provided as a multivalue map in the headers. Handle Multipart Since a Multipart content has a reference to the original MimeMessage, convert to a simple byte[] by default. Add an option in case the user wants to map the message but still interpret the Multipart intact. Namespace and Docs Polishing Polishing - PR Comments
This commit is contained in:
committed by
Artem Bilan
parent
8df487c96f
commit
439559f255
@@ -16,9 +16,12 @@
|
||||
|
||||
package org.springframework.integration.mail;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.mail.Authenticator;
|
||||
@@ -27,6 +30,8 @@ import javax.mail.Flags;
|
||||
import javax.mail.Folder;
|
||||
import javax.mail.Message;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.Multipart;
|
||||
import javax.mail.Part;
|
||||
import javax.mail.Session;
|
||||
import javax.mail.Store;
|
||||
import javax.mail.URLName;
|
||||
@@ -40,7 +45,10 @@ import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.integration.context.IntegrationObjectSupport;
|
||||
import org.springframework.integration.expression.ExpressionUtils;
|
||||
import org.springframework.integration.mapping.HeaderMapper;
|
||||
import org.springframework.messaging.MessageHeaders;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
/**
|
||||
* Base class for {@link MailReceiver} implementations.
|
||||
@@ -88,10 +96,14 @@ public abstract class AbstractMailReceiver extends IntegrationObjectSupport impl
|
||||
|
||||
private volatile Expression selectorExpression;
|
||||
|
||||
private volatile HeaderMapper<MimeMessage> headerMapper;
|
||||
|
||||
protected volatile boolean initialized;
|
||||
|
||||
private volatile String userFlag = DEFAULT_SI_USER_FLAG;
|
||||
|
||||
private volatile boolean embeddedPartsAsBytes = true;
|
||||
|
||||
public AbstractMailReceiver() {
|
||||
this.url = null;
|
||||
}
|
||||
@@ -205,6 +217,33 @@ public abstract class AbstractMailReceiver extends IntegrationObjectSupport impl
|
||||
this.userFlag = userFlag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the header mapper; if a header mapper is not provided, the message payload is
|
||||
* a {@link MimeMessage}, when provided, the headers are mapped and the payload is
|
||||
* the {@link MimeMessage} content.
|
||||
* @param headerMapper the header mapper.
|
||||
* @since 4.3
|
||||
* @see #setEmbeddedPartsAsBytes(boolean)
|
||||
*/
|
||||
public void setHeaderMapper(HeaderMapper<MimeMessage> headerMapper) {
|
||||
this.headerMapper = headerMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* When a header mapper is provided determine whether an embedded {@link Part} (e.g
|
||||
* {@link Message} or {@link Multipart} content is rendered as a byte[] in the
|
||||
* payload. Otherwise, leave as a {@link Part}. These objects are not suitable for
|
||||
* downstream serialization. Default: true.
|
||||
* <p>This has no effect if there is no header mapper, in that case the payload is the
|
||||
* {@link MimeMessage}.
|
||||
* @param embeddedPartsAsBytes the embeddedPartsAsBytes to set.
|
||||
* @since 4.3
|
||||
* @see #setHeaderMapper(HeaderMapper)
|
||||
*/
|
||||
public void setEmbeddedPartsAsBytes(boolean embeddedPartsAsBytes) {
|
||||
this.embeddedPartsAsBytes = embeddedPartsAsBytes;
|
||||
}
|
||||
|
||||
protected Folder getFolder() {
|
||||
return this.folder;
|
||||
}
|
||||
@@ -274,7 +313,7 @@ public abstract class AbstractMailReceiver extends IntegrationObjectSupport impl
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message[] receive() throws javax.mail.MessagingException {
|
||||
public Object[] receive() throws javax.mail.MessagingException {
|
||||
synchronized (this.folderMonitor) {
|
||||
try {
|
||||
this.openFolder();
|
||||
@@ -298,11 +337,25 @@ public abstract class AbstractMailReceiver extends IntegrationObjectSupport impl
|
||||
this.logger.debug("Received " + messages.length + " messages");
|
||||
}
|
||||
|
||||
Message[] filteredMessages = filterMessagesThruSelector(messages);
|
||||
MimeMessage[] filteredMessages = filterMessagesThruSelector(messages);
|
||||
|
||||
postProcessFilteredMessages(filteredMessages);
|
||||
|
||||
return filteredMessages;
|
||||
if (this.headerMapper != null) {
|
||||
org.springframework.messaging.Message<?>[] converted =
|
||||
new org.springframework.messaging.Message<?>[filteredMessages.length];
|
||||
int n = 0;
|
||||
for (MimeMessage message : filteredMessages) {
|
||||
Map<String, Object> headers = this.headerMapper.toHeaders(message);
|
||||
converted[n++] = getMessageBuilderFactory().withPayload(extractContent(message, headers))
|
||||
.copyHeaders(headers)
|
||||
.build();
|
||||
}
|
||||
return converted;
|
||||
}
|
||||
else {
|
||||
return filteredMessages;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
MailTransportUtils.closeFolder(this.folder, this.shouldDeleteMessages);
|
||||
@@ -310,16 +363,58 @@ public abstract class AbstractMailReceiver extends IntegrationObjectSupport impl
|
||||
}
|
||||
}
|
||||
|
||||
private Object extractContent(MimeMessage message, Map<String, Object> headers) {
|
||||
Object content;
|
||||
try {
|
||||
content = message.getContent();
|
||||
if (content instanceof String) {
|
||||
String mailContentType = (String) headers.get(MailHeaders.CONTENT_TYPE);
|
||||
if (mailContentType != null && mailContentType.toLowerCase().startsWith("text")) {
|
||||
headers.put(MessageHeaders.CONTENT_TYPE, mailContentType);
|
||||
}
|
||||
else {
|
||||
headers.put(MessageHeaders.CONTENT_TYPE, "text/plain");
|
||||
}
|
||||
}
|
||||
else if (content instanceof InputStream) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
FileCopyUtils.copy((InputStream) content, baos);
|
||||
content = byteArrayToContent(headers, baos);
|
||||
}
|
||||
else if (content instanceof Multipart && this.embeddedPartsAsBytes) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
((Multipart) content).writeTo(baos);
|
||||
content = byteArrayToContent(headers, baos);
|
||||
}
|
||||
else if (content instanceof Part && this.embeddedPartsAsBytes) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
((Part) content).writeTo(baos);
|
||||
content = byteArrayToContent(headers, baos);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new org.springframework.messaging.MessagingException("Failed to extract content from " + message, e);
|
||||
}
|
||||
}
|
||||
|
||||
private Object byteArrayToContent(Map<String, Object> headers, ByteArrayOutputStream baos) {
|
||||
headers.put(MessageHeaders.CONTENT_TYPE, "application/octet-stream");
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
private void postProcessFilteredMessages(Message[] filteredMessages) throws MessagingException {
|
||||
setMessageFlags(filteredMessages);
|
||||
|
||||
if (shouldDeleteMessages()) {
|
||||
deleteMessages(filteredMessages);
|
||||
}
|
||||
// Copy messages to cause an eager fetch
|
||||
for (int i = 0; i < filteredMessages.length; i++) {
|
||||
MimeMessage mimeMessage = new IntegrationMimeMessage((MimeMessage) filteredMessages[i]);
|
||||
filteredMessages[i] = mimeMessage;
|
||||
if (this.headerMapper == null) {
|
||||
// Copy messages to cause an eager fetch
|
||||
for (int i = 0; i < filteredMessages.length; i++) {
|
||||
MimeMessage mimeMessage = new IntegrationMimeMessage((MimeMessage) filteredMessages[i]);
|
||||
filteredMessages[i] = mimeMessage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -358,8 +453,8 @@ public abstract class AbstractMailReceiver extends IntegrationObjectSupport impl
|
||||
* Will filter Messages thru selector. Messages that did not pass selector filtering criteria
|
||||
* will be filtered out and remain on the server as never touched.
|
||||
*/
|
||||
private Message[] filterMessagesThruSelector(Message[] messages) throws MessagingException {
|
||||
List<Message> filteredMessages = new LinkedList<Message>();
|
||||
private MimeMessage[] filterMessagesThruSelector(Message[] messages) throws MessagingException {
|
||||
List<MimeMessage> filteredMessages = new LinkedList<MimeMessage>();
|
||||
for (int i = 0; i < messages.length; i++) {
|
||||
MimeMessage message = (MimeMessage) messages[i];
|
||||
if (this.selectorExpression != null) {
|
||||
@@ -377,7 +472,7 @@ public abstract class AbstractMailReceiver extends IntegrationObjectSupport impl
|
||||
filteredMessages.add(message);
|
||||
}
|
||||
}
|
||||
return filteredMessages.toArray(new Message[filteredMessages.size()]);
|
||||
return filteredMessages.toArray(new MimeMessage[filteredMessages.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -182,12 +182,15 @@ public class ImapIdleChannelAdapter extends MessageProducerSupport implements Be
|
||||
}
|
||||
}
|
||||
|
||||
private Runnable createMessageSendingTask(final Message mailMessage) {
|
||||
private Runnable createMessageSendingTask(final Object mailMessage) {
|
||||
Runnable sendingTask = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@SuppressWarnings("unchecked")
|
||||
org.springframework.messaging.Message<?> message =
|
||||
ImapIdleChannelAdapter.this.getMessageBuilderFactory().withPayload(mailMessage).build();
|
||||
mailMessage instanceof Message
|
||||
? ImapIdleChannelAdapter.this.getMessageBuilderFactory().withPayload(mailMessage).build()
|
||||
: (org.springframework.messaging.Message<Object>) mailMessage;
|
||||
|
||||
if (TransactionSynchronizationManager.isActualTransactionActive()) {
|
||||
if (ImapIdleChannelAdapter.this.transactionSynchronizationFactory != null) {
|
||||
@@ -267,11 +270,11 @@ public class ImapIdleChannelAdapter extends MessageProducerSupport implements Be
|
||||
}
|
||||
ImapIdleChannelAdapter.this.mailReceiver.waitForNewMessages();
|
||||
if (ImapIdleChannelAdapter.this.mailReceiver.getFolder().isOpen()) {
|
||||
Message[] mailMessages = ImapIdleChannelAdapter.this.mailReceiver.receive();
|
||||
Object[] mailMessages = ImapIdleChannelAdapter.this.mailReceiver.receive();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("received " + mailMessages.length + " mail messages");
|
||||
}
|
||||
for (final Message mailMessage : mailMessages) {
|
||||
for (final Object mailMessage : mailMessages) {
|
||||
|
||||
Runnable messageSendingTask = createMessageSendingTask(mailMessage);
|
||||
|
||||
|
||||
@@ -21,8 +21,9 @@ package org.springframework.integration.mail;
|
||||
* Message attributes from/to integration Message Headers.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Gary Russell
|
||||
*/
|
||||
public abstract class MailHeaders {
|
||||
public final class MailHeaders {
|
||||
|
||||
public static final String PREFIX = "mail_";
|
||||
|
||||
@@ -44,4 +45,21 @@ public abstract class MailHeaders {
|
||||
|
||||
public static final String CONTENT_TYPE = PREFIX + "contentType";
|
||||
|
||||
public static final String RAW_HEADERS = PREFIX + "raw";
|
||||
|
||||
public static final String FLAGS = PREFIX + "flags";
|
||||
|
||||
public static final String LINE_COUNT = PREFIX + "lineCount";
|
||||
|
||||
public static final String RECEIVED_DATE = PREFIX + "receivedDate";
|
||||
|
||||
public static final String SIZE = PREFIX + "size";
|
||||
|
||||
public static final String EXPUNGED = PREFIX + "expunged";
|
||||
|
||||
private MailHeaders() {
|
||||
// empty
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -16,12 +16,6 @@
|
||||
|
||||
package org.springframework.integration.mail;
|
||||
|
||||
import javax.mail.Folder;
|
||||
import javax.mail.Message;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* Strategy interface for receiving mail {@link javax.mail.Message Messages}.
|
||||
*
|
||||
@@ -30,30 +24,6 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public interface MailReceiver {
|
||||
|
||||
javax.mail.Message[] receive() throws javax.mail.MessagingException;
|
||||
|
||||
class MailReceiverContext {
|
||||
|
||||
private final Folder folder;
|
||||
|
||||
private volatile Message[] messages = new Message[0];
|
||||
|
||||
MailReceiverContext(Folder folder) {
|
||||
this.folder = folder;
|
||||
}
|
||||
|
||||
Message[] getMessages() {
|
||||
return this.messages;
|
||||
}
|
||||
|
||||
void setMessages(Message[] messages) {
|
||||
Assert.noNullElements(messages, "messages cannot be null");
|
||||
this.messages = messages;
|
||||
}
|
||||
|
||||
Folder getFolder() {
|
||||
return this.folder;
|
||||
}
|
||||
}
|
||||
Object[] receive() throws javax.mail.MessagingException;
|
||||
|
||||
}
|
||||
|
||||
@@ -46,14 +46,14 @@ import org.springframework.util.Assert;
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Artem Bilan
|
||||
*/
|
||||
public class MailReceivingMessageSource implements MessageSource<javax.mail.Message>,
|
||||
public class MailReceivingMessageSource implements MessageSource<Object>,
|
||||
BeanFactoryAware, BeanNameAware, NamedComponent {
|
||||
|
||||
private final Log logger = LogFactory.getLog(this.getClass());
|
||||
|
||||
private final MailReceiver mailReceiver;
|
||||
|
||||
private final Queue<javax.mail.Message> mailQueue = new ConcurrentLinkedQueue<javax.mail.Message>();
|
||||
private final Queue<Object> mailQueue = new ConcurrentLinkedQueue<Object>();
|
||||
|
||||
private volatile BeanFactory beanFactory;
|
||||
|
||||
@@ -103,12 +103,13 @@ public class MailReceivingMessageSource implements MessageSource<javax.mail.Mess
|
||||
this.beanName = name;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Message<javax.mail.Message> receive() {
|
||||
public Message<Object> receive() {
|
||||
try {
|
||||
javax.mail.Message mailMessage = this.mailQueue.poll();
|
||||
Object mailMessage = this.mailQueue.poll();
|
||||
if (mailMessage == null) {
|
||||
javax.mail.Message[] messages = this.mailReceiver.receive();
|
||||
Object[] messages = this.mailReceiver.receive();
|
||||
if (messages != null) {
|
||||
this.mailQueue.addAll(Arrays.asList(messages));
|
||||
}
|
||||
@@ -118,7 +119,12 @@ public class MailReceivingMessageSource implements MessageSource<javax.mail.Mess
|
||||
if (this.logger.isDebugEnabled()) {
|
||||
this.logger.debug("received mail message [" + mailMessage + "]");
|
||||
}
|
||||
return getMessageBuilderFactory().withPayload(mailMessage).build();
|
||||
if (mailMessage instanceof Message) {
|
||||
return (Message<Object>) mailMessage;
|
||||
}
|
||||
else {
|
||||
return getMessageBuilderFactory().withPayload(mailMessage).build();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
|
||||
@@ -78,7 +78,8 @@ public class ImapIdleChannelAdapterParser extends AbstractChannelAdapterParser {
|
||||
}
|
||||
else {
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(receiverBuilder, element, "java-mail-properties");
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(receiverBuilder, element, "authenticator", "javaMailAuthenticator");
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(receiverBuilder, element, "authenticator",
|
||||
"javaMailAuthenticator");
|
||||
}
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(receiverBuilder, element, "max-fetch-size");
|
||||
receiverBuilder.addPropertyValue("shouldDeleteMessages", element.getAttribute("should-delete-messages"));
|
||||
@@ -95,6 +96,8 @@ public class ImapIdleChannelAdapterParser extends AbstractChannelAdapterParser {
|
||||
expressionDef.getConstructorArgumentValues().addGenericArgumentValue(selectorExpression);
|
||||
receiverBuilder.addPropertyValue("selectorExpression", expressionDef);
|
||||
}
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(receiverBuilder, element, "header-mapper");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(receiverBuilder, element, "embedded-parts-as-bytes");
|
||||
|
||||
return receiverBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
@@ -93,6 +93,8 @@ public class MailInboundChannelAdapterParser extends AbstractPollingInboundChann
|
||||
expressionDef.getConstructorArgumentValues().addGenericArgumentValue(selectorExpression);
|
||||
receiverBuilder.addPropertyValue("selectorExpression", expressionDef);
|
||||
}
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(receiverBuilder, element, "header-mapper");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(receiverBuilder, element, "embedded-parts-as-bytes");
|
||||
|
||||
return receiverBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.util.Properties;
|
||||
import javax.mail.Authenticator;
|
||||
import javax.mail.Session;
|
||||
import javax.mail.URLName;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -36,6 +37,7 @@ import org.springframework.integration.mail.ImapMailReceiver;
|
||||
import org.springframework.integration.mail.MailReceiver;
|
||||
import org.springframework.integration.mail.Pop3MailReceiver;
|
||||
import org.springframework.integration.mail.SearchTermStrategy;
|
||||
import org.springframework.integration.mapping.HeaderMapper;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -79,6 +81,10 @@ public class MailReceiverFactoryBean implements FactoryBean<MailReceiver>, Dispo
|
||||
|
||||
private volatile BeanFactory beanFactory;
|
||||
|
||||
private volatile HeaderMapper<MimeMessage> headerMapper;
|
||||
|
||||
private Boolean embeddedPartsAsBytes;
|
||||
|
||||
public void setStoreUri(String storeUri) {
|
||||
this.storeUri = storeUri;
|
||||
}
|
||||
@@ -127,6 +133,14 @@ public class MailReceiverFactoryBean implements FactoryBean<MailReceiver>, Dispo
|
||||
this.userFlag = userFlag;
|
||||
}
|
||||
|
||||
public void setHeaderMapper(HeaderMapper<MimeMessage> headerMapper) {
|
||||
this.headerMapper = headerMapper;
|
||||
}
|
||||
|
||||
public void setEmbeddedPartsAsBytes(Boolean embeddedPartsAsBytes) {
|
||||
this.embeddedPartsAsBytes = embeddedPartsAsBytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
@@ -210,6 +224,12 @@ public class MailReceiverFactoryBean implements FactoryBean<MailReceiver>, Dispo
|
||||
if (this.beanFactory != null) {
|
||||
receiver.setBeanFactory(this.beanFactory);
|
||||
}
|
||||
if (this.headerMapper != null) {
|
||||
receiver.setHeaderMapper(this.headerMapper);
|
||||
}
|
||||
if (this.embeddedPartsAsBytes != null) {
|
||||
receiver.setEmbeddedPartsAsBytes(this.embeddedPartsAsBytes);
|
||||
}
|
||||
receiver.afterPropertiesSet();
|
||||
return receiver;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 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.support;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.mail.Header;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
|
||||
import org.springframework.integration.mail.MailHeaders;
|
||||
import org.springframework.integration.mapping.HeaderMapper;
|
||||
import org.springframework.messaging.MessageHeaders;
|
||||
import org.springframework.messaging.MessagingException;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
* Maps an inbound {@link MimeMessage} to a {@link Map}.
|
||||
*
|
||||
* @author Gary Russell
|
||||
* @since 4.3
|
||||
*
|
||||
*/
|
||||
public class DefaultMailHeaderMapper implements HeaderMapper<MimeMessage> {
|
||||
|
||||
@Override
|
||||
public void fromHeaders(MessageHeaders headers, MimeMessage target) {
|
||||
throw new UnsupportedOperationException("Mapping to a mail message is not currently supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> toHeaders(MimeMessage source) {
|
||||
Map<String, Object> headers = MailUtils.extractStandardHeaders(source);
|
||||
try {
|
||||
Enumeration<?> allHeaders = source.getAllHeaders();
|
||||
MultiValueMap<String, String> rawHeaders = new LinkedMultiValueMap<String, String>();
|
||||
while (allHeaders.hasMoreElements()) {
|
||||
Object headerInstance = allHeaders.nextElement();
|
||||
if (headerInstance instanceof Header) {
|
||||
Header header = (Header) headerInstance;
|
||||
rawHeaders.add(header.getName(), header.getValue());
|
||||
}
|
||||
}
|
||||
headers.put(MailHeaders.RAW_HEADERS, rawHeaders);
|
||||
headers.put(MailHeaders.FLAGS, source.getFlags());
|
||||
int lineCount = source.getLineCount();
|
||||
if (lineCount > 0) {
|
||||
headers.put(MailHeaders.LINE_COUNT, lineCount);
|
||||
}
|
||||
Date receivedDate = source.getReceivedDate();
|
||||
if (receivedDate != null) {
|
||||
headers.put(MailHeaders.RECEIVED_DATE, receivedDate);
|
||||
}
|
||||
int size = source.getSize();
|
||||
if (size > 0) {
|
||||
headers.put(MailHeaders.SIZE, size);
|
||||
}
|
||||
headers.put(MailHeaders.EXPUNGED, source.isExpunged());
|
||||
headers.put(MailHeaders.CONTENT_TYPE, source.getContentType());
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new MessagingException("Failed to map message headers", e);
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 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.support;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.mail.Address;
|
||||
import javax.mail.Message;
|
||||
import javax.mail.Message.RecipientType;
|
||||
|
||||
import org.springframework.integration.mail.MailHeaders;
|
||||
import org.springframework.messaging.MessagingException;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Utilities for handling mail messages.
|
||||
*
|
||||
* @author Gary Russell
|
||||
* @since 4.3
|
||||
*
|
||||
*/
|
||||
public final class MailUtils {
|
||||
|
||||
private MailUtils() {
|
||||
// empty
|
||||
}
|
||||
|
||||
/**
|
||||
* Map the message headers to a Map using {@link MailHeaders} keys; specifically
|
||||
* maps the address headers and the subject.
|
||||
* @param source the message.
|
||||
* @return the map.
|
||||
*/
|
||||
public static Map<String, Object> extractStandardHeaders(Message source) {
|
||||
Map<String, Object> headers = new HashMap<String, Object>();
|
||||
try {
|
||||
headers.put(MailHeaders.FROM, convertToString(source.getFrom()));
|
||||
headers.put(MailHeaders.BCC, convertToStringArray(source.getRecipients(RecipientType.BCC)));
|
||||
headers.put(MailHeaders.CC, convertToStringArray(source.getRecipients(RecipientType.CC)));
|
||||
headers.put(MailHeaders.TO, convertToStringArray(source.getRecipients(RecipientType.TO)));
|
||||
headers.put(MailHeaders.REPLY_TO, convertToString(source.getReplyTo()));
|
||||
headers.put(MailHeaders.SUBJECT, source.getSubject());
|
||||
return headers;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new MessagingException("conversion of MailMessage headers failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static String convertToString(Address[] addresses) {
|
||||
if (addresses == null || addresses.length == 0) {
|
||||
return null;
|
||||
}
|
||||
Assert.state(addresses.length == 1, "expected a single value but received an Array");
|
||||
return addresses[0].toString();
|
||||
}
|
||||
|
||||
private static String[] convertToStringArray(Address[] addresses) {
|
||||
if (addresses != null) {
|
||||
String[] addressStrings = new String[addresses.length];
|
||||
for (int i = 0; i < addresses.length; i++) {
|
||||
addressStrings[i] = addresses[i].toString();
|
||||
}
|
||||
return addressStrings;
|
||||
}
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Provides classes to support email.
|
||||
*/
|
||||
package org.springframework.integration.mail.support;
|
||||
@@ -16,18 +16,14 @@
|
||||
|
||||
package org.springframework.integration.mail.transformer;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.mail.Address;
|
||||
import javax.mail.Message.RecipientType;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.integration.mail.MailHeaders;
|
||||
import org.springframework.integration.mail.support.MailUtils;
|
||||
import org.springframework.integration.support.AbstractIntegrationMessageBuilder;
|
||||
import org.springframework.integration.support.DefaultMessageBuilderFactory;
|
||||
import org.springframework.integration.support.MessageBuilderFactory;
|
||||
@@ -35,8 +31,6 @@ import org.springframework.integration.support.utils.IntegrationUtils;
|
||||
import org.springframework.integration.transformer.MessageTransformationException;
|
||||
import org.springframework.integration.transformer.Transformer;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessagingException;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Base class for Transformers that convert from a JavaMail Message to a
|
||||
@@ -99,38 +93,7 @@ public abstract class AbstractMailMessageTransformer<T> implements Transformer,
|
||||
|
||||
|
||||
private Map<String, Object> extractHeaderMapFromMailMessage(javax.mail.Message mailMessage) {
|
||||
try {
|
||||
Map<String, Object> headers = new HashMap<String, Object>();
|
||||
headers.put(MailHeaders.FROM, this.convertToString(mailMessage.getFrom()));
|
||||
headers.put(MailHeaders.BCC, this.convertToStringArray(mailMessage.getRecipients(RecipientType.BCC)));
|
||||
headers.put(MailHeaders.CC, this.convertToStringArray(mailMessage.getRecipients(RecipientType.CC)));
|
||||
headers.put(MailHeaders.TO, this.convertToStringArray(mailMessage.getRecipients(RecipientType.TO)));
|
||||
headers.put(MailHeaders.REPLY_TO, this.convertToString(mailMessage.getReplyTo()));
|
||||
headers.put(MailHeaders.SUBJECT, mailMessage.getSubject());
|
||||
return headers;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new MessagingException("conversion of MailMessage headers failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
private String convertToString(Address[] addresses) {
|
||||
if (addresses == null || addresses.length == 0) {
|
||||
return null;
|
||||
}
|
||||
Assert.state(addresses.length == 1, "expected a single value but received an Array");
|
||||
return addresses[0].toString();
|
||||
}
|
||||
|
||||
private String[] convertToStringArray(Address[] addresses) {
|
||||
if (addresses != null) {
|
||||
String[] addressStrings = new String[addresses.length];
|
||||
for (int i = 0; i < addresses.length; i++) {
|
||||
addressStrings[i] = addresses[i].toString();
|
||||
}
|
||||
return addressStrings;
|
||||
}
|
||||
return new String[0];
|
||||
return MailUtils.extractStandardHeaders(mailMessage);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,15 +20,16 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import javax.mail.Multipart;
|
||||
import javax.mail.Part;
|
||||
|
||||
import org.springframework.integration.support.AbstractIntegrationMessageBuilder;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Transforms a Message payload of type {@link javax.mail.Message} to a String.
|
||||
* If the mail message's content is a String, it will be the payload of the
|
||||
* result Message. If the content is a Multipart, a String will be created from
|
||||
* an output stream of bytes using the provided charset (or UTF-8 by default).
|
||||
* Transforms a Message payload of type {@link javax.mail.Message} to a String. If the
|
||||
* mail message's content is a String, it will be the payload of the result Message. If
|
||||
* the content is a Part or Multipart, a String will be created from an output stream of
|
||||
* bytes using the provided charset (or UTF-8 by default).
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Gary Russell
|
||||
@@ -62,6 +63,12 @@ public class MailToStringTransformer extends AbstractMailMessageTransformer<Stri
|
||||
return this.getMessageBuilderFactory().withPayload(
|
||||
new String(outputStream.toByteArray(), this.charset));
|
||||
}
|
||||
else if (content instanceof Part) {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
((Part) content).writeTo(outputStream);
|
||||
return this.getMessageBuilderFactory().withPayload(
|
||||
new String(outputStream.toByteArray(), this.charset));
|
||||
}
|
||||
throw new IllegalArgumentException("failed to transform contentType ["
|
||||
+ mailMessage.getContentType() + "] to String.");
|
||||
}
|
||||
|
||||
@@ -269,6 +269,7 @@
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attributeGroup ref="inboundMappingGroup" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:element name="mail-to-string-transformer">
|
||||
@@ -363,4 +364,38 @@
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:attributeGroup name="inboundMappingGroup">
|
||||
<xsd:attribute name="header-mapper" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
A reference to a 'org.springframework.integration.mapping.HeaderMapper<MimeMessage>' bean.
|
||||
When not supplied, the message payload will be the raw MimeMessage with no header mapping.
|
||||
When a mapper is provided, the mail headers are mapped to 'MessageHeaders' and the payload
|
||||
will depend on the email contents, and the setting of 'embedded-parts-as-bytes'. The framework
|
||||
provides a 'DefaultMailHeaderMapper'; see the reference manual regarding the headers mapped
|
||||
and the payload types.
|
||||
]]></xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.integration.mapping.HeaderMapper" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="embedded-parts-as-bytes">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
When a 'header-mapper' is provided, and the 'MimeMessage' has embedded 'Part' (e.g. 'Message' or
|
||||
'Multipart') contents, the message payload will be a byte[] containing the raw data. Set this
|
||||
boolean to 'false' for the payload to be a decoded 'Part' object. Note that 'Part's are not
|
||||
'Serializable', nor are they suitable for serialization using other technologies such as Kryo.
|
||||
Default 'true' (payload is 'byte[]').
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:simpleType>
|
||||
<xsd:union memberTypes="xsd:boolean xsd:string"/>
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
</xsd:attributeGroup>
|
||||
|
||||
</xsd:schema>
|
||||
|
||||
@@ -16,10 +16,13 @@
|
||||
|
||||
package org.springframework.integration.mail;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
@@ -29,7 +32,7 @@ import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
@@ -80,15 +83,15 @@ import org.springframework.integration.history.MessageHistory;
|
||||
import org.springframework.integration.mail.ImapIdleChannelAdapter.ImapIdleExceptionEvent;
|
||||
import org.springframework.integration.mail.PoorMansMailServer.ImapServer;
|
||||
import org.springframework.integration.mail.config.ImapIdleChannelAdapterParserTests;
|
||||
import org.springframework.integration.mail.support.DefaultMailHeaderMapper;
|
||||
import org.springframework.integration.test.support.LongRunningIntegrationTest;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.messaging.MessageHeaders;
|
||||
import org.springframework.messaging.PollableChannel;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
|
||||
import com.sun.mail.imap.IMAPFolder;
|
||||
import com.sun.mail.imap.IMAPMessage;
|
||||
|
||||
/**
|
||||
* @author Oleg Zhurakousky
|
||||
@@ -136,18 +139,26 @@ public class ImapMailReceiverTests {
|
||||
}
|
||||
}
|
||||
});
|
||||
testIdleWithServerGuts(receiver);
|
||||
testIdleWithServerGuts(receiver, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIdleWithServerDefaultSearch() throws Exception {
|
||||
ImapMailReceiver receiver = new ImapMailReceiver("imap://user:pw@localhost:" + imapIdleServer.getPort()
|
||||
+ "/INBOX");
|
||||
testIdleWithServerGuts(receiver);
|
||||
testIdleWithServerGuts(receiver, false);
|
||||
assertTrue(imapIdleServer.assertReceived("searchWithUserFlag"));
|
||||
}
|
||||
|
||||
public void testIdleWithServerGuts(ImapMailReceiver receiver) throws MessagingException {
|
||||
@Test
|
||||
public void testIdleWithMessageMapping() throws Exception {
|
||||
ImapMailReceiver receiver = new ImapMailReceiver("imap://user:pw@localhost:" + imapIdleServer.getPort()
|
||||
+ "/INBOX");
|
||||
receiver.setHeaderMapper(new DefaultMailHeaderMapper());
|
||||
testIdleWithServerGuts(receiver, true);
|
||||
}
|
||||
|
||||
public void testIdleWithServerGuts(ImapMailReceiver receiver, boolean mapped) throws MessagingException {
|
||||
imapIdleServer.resetServer();
|
||||
Properties mailProps = new Properties();
|
||||
mailProps.put("mail.debug", "true");
|
||||
@@ -168,12 +179,23 @@ public class ImapMailReceiverTests {
|
||||
adapter.setOutputChannel(channel);
|
||||
adapter.setTaskScheduler(taskScheduler);
|
||||
adapter.start();
|
||||
@SuppressWarnings("unchecked")
|
||||
org.springframework.messaging.Message<MimeMessage> received =
|
||||
(org.springframework.messaging.Message<MimeMessage>) channel.receive(10000);
|
||||
assertNotNull(received);
|
||||
assertNotNull(received.getPayload().getReceivedDate());
|
||||
assertTrue(received.getPayload().getLineCount() > -1);
|
||||
if (!mapped) {
|
||||
@SuppressWarnings("unchecked")
|
||||
org.springframework.messaging.Message<MimeMessage> received =
|
||||
(org.springframework.messaging.Message<MimeMessage>) channel.receive(10000);
|
||||
assertNotNull(received);
|
||||
assertNotNull(received.getPayload().getReceivedDate());
|
||||
assertTrue(received.getPayload().getLineCount() > -1);
|
||||
}
|
||||
else {
|
||||
org.springframework.messaging.Message<?> received = channel.receive(10000);
|
||||
assertNotNull(received);
|
||||
assertNotNull(received.getHeaders().get(MailHeaders.RAW_HEADERS));
|
||||
assertThat((String) received.getHeaders().get(MailHeaders.CONTENT_TYPE),
|
||||
equalTo("TEXT/PLAIN; charset=ISO-8859-1"));
|
||||
assertThat((String) received.getHeaders().get(MessageHeaders.CONTENT_TYPE),
|
||||
equalTo("TEXT/PLAIN; charset=ISO-8859-1"));
|
||||
}
|
||||
assertNotNull(channel.receive(10000)); // new message after idle
|
||||
assertNull(channel.receive(10000)); // no new message after second and third idle
|
||||
verify(logger).debug("Canceling IDLE");
|
||||
@@ -838,12 +860,52 @@ public class ImapMailReceiverTests {
|
||||
@Test
|
||||
public void testAttachments() throws Exception {
|
||||
final ImapMailReceiver receiver = new ImapMailReceiver("imap://foo");
|
||||
Folder folder = testAttachmentsGuts(receiver);
|
||||
Message[] messages = (Message[]) receiver.receive();
|
||||
Object content = messages[0].getContent();
|
||||
assertEquals("bar", ((Multipart) content).getBodyPart(0).getContent().toString().trim());
|
||||
assertEquals("foo", ((Multipart) content).getBodyPart(1).getContent().toString().trim());
|
||||
|
||||
assertSame(folder, messages[0].getFolder());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAttachmentsWithMappingMultiAsBytes() throws Exception {
|
||||
final ImapMailReceiver receiver = new ImapMailReceiver("imap://foo");
|
||||
receiver.setHeaderMapper(new DefaultMailHeaderMapper());
|
||||
testAttachmentsGuts(receiver);
|
||||
org.springframework.messaging.Message<?>[] messages = (org.springframework.messaging.Message<?>[]) receiver
|
||||
.receive();
|
||||
org.springframework.messaging.Message<?> received = messages[0];
|
||||
Object content = received.getPayload();
|
||||
assertThat(content, instanceOf(byte[].class));
|
||||
assertThat((String) received.getHeaders().get(MailHeaders.CONTENT_TYPE),
|
||||
equalTo("multipart/mixed;\r\n boundary=\"------------040903000701040401040200\""));
|
||||
assertThat((String) received.getHeaders().get(MessageHeaders.CONTENT_TYPE),
|
||||
equalTo("application/octet-stream"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAttachmentsWithMapping() throws Exception {
|
||||
final ImapMailReceiver receiver = new ImapMailReceiver("imap://foo");
|
||||
receiver.setHeaderMapper(new DefaultMailHeaderMapper());
|
||||
receiver.setEmbeddedPartsAsBytes(false);
|
||||
testAttachmentsGuts(receiver);
|
||||
org.springframework.messaging.Message<?>[] messages = (org.springframework.messaging.Message<?>[]) receiver
|
||||
.receive();
|
||||
Object content = messages[0].getPayload();
|
||||
assertThat(content, instanceOf(Multipart.class));
|
||||
assertEquals("bar", ((Multipart) content).getBodyPart(0).getContent().toString().trim());
|
||||
assertEquals("foo", ((Multipart) content).getBodyPart(1).getContent().toString().trim());
|
||||
}
|
||||
|
||||
private Folder testAttachmentsGuts(final ImapMailReceiver receiver) throws MessagingException, IOException {
|
||||
Store store = mock(Store.class);
|
||||
Folder folder = mock(Folder.class);
|
||||
when(folder.exists()).thenReturn(true);
|
||||
when(folder.isOpen()).thenReturn(true);
|
||||
|
||||
IMAPMessage message = mock(IMAPMessage.class);
|
||||
Message message = new MimeMessage(null, new ClassPathResource("test.mail").getInputStream());
|
||||
when(folder.search((SearchTerm) Mockito.any())).thenReturn(new Message[]{message});
|
||||
when(store.getFolder(Mockito.any(URLName.class))).thenReturn(folder);
|
||||
when(folder.getPermanentFlags()).thenReturn(new Flags(Flags.Flag.USER));
|
||||
@@ -852,20 +914,7 @@ public class ImapMailReceiverTests {
|
||||
receiver.setBeanFactory(mock(BeanFactory.class));
|
||||
receiver.afterPropertiesSet();
|
||||
|
||||
doAnswer(new Answer<Object>() {
|
||||
|
||||
@Override
|
||||
public Object answer(InvocationOnMock invocation) throws Throwable {
|
||||
OutputStream os = (OutputStream) invocation.getArguments()[0];
|
||||
FileCopyUtils.copy(new ClassPathResource("test.mail").getInputStream(), os);
|
||||
return null;
|
||||
}
|
||||
}).when(message).writeTo(Mockito.any(OutputStream.class));
|
||||
Message[] messages = receiver.receive();
|
||||
Object content = messages[0].getContent();
|
||||
assertEquals("bar", ((Multipart) content).getBodyPart(0).getContent().toString().trim());
|
||||
|
||||
assertSame(folder, messages[0].getFolder());
|
||||
return folder;
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -922,10 +971,10 @@ public class ImapMailReceiverTests {
|
||||
|
||||
}
|
||||
ImapMailReceiver receiver = new TestReceiver();
|
||||
Message[] received = receiver.receive();
|
||||
Message[] received = (Message[]) receiver.receive();
|
||||
assertEquals(1, received.length);
|
||||
assertSame(message1, received[0]);
|
||||
received = receiver.receive();
|
||||
received = (Message[]) receiver.receive();
|
||||
assertEquals(1, received.length);
|
||||
assertSame(messages2, received);
|
||||
assertSame(message2, received[0]);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* 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.
|
||||
@@ -60,6 +60,7 @@ public class MailReceivingMessageSourceTests {
|
||||
|
||||
private final ConcurrentLinkedQueue<javax.mail.Message[]> messages = new ConcurrentLinkedQueue<javax.mail.Message[]>();
|
||||
|
||||
@Override
|
||||
public javax.mail.Message[] receive() {
|
||||
return messages.poll();
|
||||
}
|
||||
@@ -74,16 +75,6 @@ public class MailReceivingMessageSourceTests {
|
||||
public void stop() {
|
||||
}
|
||||
|
||||
public MailReceiverContext getTransactionContext() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void closeContextAfterSuccess(MailReceiverContext context) {
|
||||
}
|
||||
|
||||
public void closeContextAfterFailure(MailReceiverContext context) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,13 +16,7 @@
|
||||
|
||||
package org.springframework.integration.mail;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import javax.mail.Folder;
|
||||
|
||||
import org.springframework.integration.mail.MailReceiver.MailReceiverContext;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.mail.SimpleMailMessage;
|
||||
import org.springframework.messaging.Message;
|
||||
|
||||
@@ -77,13 +71,4 @@ public class MailTestsHelper {
|
||||
.build();
|
||||
}
|
||||
|
||||
public static MailReceiverContext setupContextHolder(AbstractMailReceiver receiver) {
|
||||
@SuppressWarnings("unchecked")
|
||||
ThreadLocal<MailReceiverContext> contextHolder = TestUtils.getPropertyValue(receiver, "contextHolder", ThreadLocal.class);
|
||||
Folder folder = mock(Folder.class);
|
||||
MailReceiverContext context = new MailReceiverContext(folder);
|
||||
contextHolder.set(context);
|
||||
return context;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -35,8 +35,12 @@
|
||||
store-uri="imap:foo"
|
||||
channel="channel"
|
||||
auto-startup="false"
|
||||
header-mapper="mapper"
|
||||
embedded-parts-as-bytes="false"
|
||||
should-delete-messages="true"/>
|
||||
|
||||
<bean id="mapper" class="org.springframework.integration.mail.support.DefaultMailHeaderMapper" />
|
||||
|
||||
<mail:imap-idle-channel-adapter id="simpleAdapterWithErrorChannel"
|
||||
store-uri="imap:foo"
|
||||
channel="channel"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* 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.
|
||||
@@ -40,6 +40,7 @@ import org.springframework.integration.mail.ImapMailReceiver;
|
||||
import org.springframework.integration.mail.SearchTermStrategy;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
@@ -51,6 +52,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
@DirtiesContext
|
||||
public class ImapIdleChannelAdapterParserTests {
|
||||
|
||||
@Autowired
|
||||
@@ -82,7 +84,10 @@ public class ImapIdleChannelAdapterParserTests {
|
||||
assertEquals(Boolean.TRUE, receiverAccessor.getPropertyValue("shouldMarkMessagesAsRead"));
|
||||
assertNull(adapterAccessor.getPropertyValue("errorChannel"));
|
||||
assertNull(adapterAccessor.getPropertyValue("adviceChain"));
|
||||
assertEquals(Boolean.FALSE, receiverAccessor.getPropertyValue("embeddedPartsAsBytes"));
|
||||
assertNotNull(receiverAccessor.getPropertyValue("headerMapper"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleAdapterWithErrorChannel() {
|
||||
Object adapter = context.getBean("simpleAdapterWithErrorChannel");
|
||||
@@ -102,7 +107,10 @@ public class ImapIdleChannelAdapterParserTests {
|
||||
assertEquals(Boolean.TRUE, receiverAccessor.getPropertyValue("shouldDeleteMessages"));
|
||||
assertEquals(Boolean.TRUE, receiverAccessor.getPropertyValue("shouldMarkMessagesAsRead"));
|
||||
assertSame(context.getBean("errorChannel"), adapterAccessor.getPropertyValue("errorChannel"));
|
||||
assertEquals(Boolean.TRUE, receiverAccessor.getPropertyValue("embeddedPartsAsBytes"));
|
||||
assertNull(receiverAccessor.getPropertyValue("headerMapper"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleAdapterWithMarkeMessagesAsRead() {
|
||||
Object adapter = context.getBean("simpleAdapterMarkAsRead");
|
||||
|
||||
@@ -13,14 +13,24 @@
|
||||
|
||||
<!-- INT-982 -->
|
||||
|
||||
<mail:inbound-channel-adapter id="pop3ShouldDeleteTrue" store-uri="pop3:test" channel="testChannel" should-delete-messages="true" auto-startup="false"/>
|
||||
<mail:inbound-channel-adapter id="pop3ShouldDeleteTrue"
|
||||
store-uri="pop3:test" channel="testChannel" should-delete-messages="true"
|
||||
header-mapper="mapper" embedded-parts-as-bytes="false"
|
||||
auto-startup="false" />
|
||||
|
||||
<mail:inbound-channel-adapter id="pop3ShouldDeleteFalse" store-uri="pop3:test" channel="testChannel" should-delete-messages="false" auto-startup="false"/>
|
||||
<mail:inbound-channel-adapter id="pop3ShouldDeleteFalse"
|
||||
store-uri="pop3:test" channel="testChannel" should-delete-messages="false"
|
||||
auto-startup="false" />
|
||||
|
||||
<mail:inbound-channel-adapter id="imapShouldDeleteTrue" store-uri="imap:test" channel="testChannel" should-delete-messages="true" auto-startup="false"/>
|
||||
<mail:inbound-channel-adapter id="imapShouldDeleteTrue"
|
||||
store-uri="imap:test" channel="testChannel" should-delete-messages="true"
|
||||
auto-startup="false" />
|
||||
|
||||
<mail:inbound-channel-adapter id="imapShouldDeleteFalse" store-uri="imap:test" channel="testChannel" should-delete-messages="false" auto-startup="false"/>
|
||||
<mail:inbound-channel-adapter id="imapShouldDeleteFalse"
|
||||
store-uri="imap:test" channel="testChannel" should-delete-messages="false"
|
||||
auto-startup="false" />
|
||||
|
||||
<bean id="mapper" class="org.springframework.integration.mail.support.DefaultMailHeaderMapper" />
|
||||
|
||||
<!-- INT-1158 -->
|
||||
|
||||
@@ -31,46 +41,75 @@
|
||||
<prop key="mail.delete.false">false</prop>
|
||||
</util:properties>
|
||||
|
||||
<mail:inbound-channel-adapter id="pop3ShouldDeleteTrueProperty" store-uri="pop3:test" channel="testChannel" should-delete-messages="${mail.delete.true}" auto-startup="false"/>
|
||||
<mail:inbound-channel-adapter id="pop3ShouldDeleteTrueProperty"
|
||||
store-uri="pop3:test" channel="testChannel" should-delete-messages="${mail.delete.true}"
|
||||
auto-startup="false" />
|
||||
|
||||
<mail:inbound-channel-adapter id="pop3ShouldDeleteFalseProperty" store-uri="pop3:test" channel="testChannel" should-delete-messages="${mail.delete.false}" auto-startup="false"/>
|
||||
<mail:inbound-channel-adapter id="pop3ShouldDeleteFalseProperty"
|
||||
store-uri="pop3:test" channel="testChannel" should-delete-messages="${mail.delete.false}"
|
||||
auto-startup="false" />
|
||||
|
||||
<mail:inbound-channel-adapter id="imapShouldDeleteTrueProperty" store-uri="imap:test" channel="testChannel" should-delete-messages="${mail.delete.true}" auto-startup="false"/>
|
||||
<mail:inbound-channel-adapter id="imapShouldDeleteTrueProperty"
|
||||
store-uri="imap:test" channel="testChannel" should-delete-messages="${mail.delete.true}"
|
||||
auto-startup="false" />
|
||||
|
||||
<mail:inbound-channel-adapter id="imapShouldDeleteFalseProperty" store-uri="imap:test" channel="testChannel" should-delete-messages="${mail.delete.false}" auto-startup="false"/>
|
||||
<mail:inbound-channel-adapter id="imapShouldDeleteFalseProperty"
|
||||
store-uri="imap:test" channel="testChannel" should-delete-messages="${mail.delete.false}"
|
||||
auto-startup="false" />
|
||||
|
||||
|
||||
<!-- INT-1159 -->
|
||||
|
||||
<mail:inbound-channel-adapter id="pop3WithAuthenticator" store-uri="pop3:test" authenticator="testAuthenticator" channel="testChannel" should-delete-messages="false" auto-startup="false"/>
|
||||
<mail:inbound-channel-adapter id="pop3WithAuthenticator"
|
||||
store-uri="pop3:test" authenticator="testAuthenticator" channel="testChannel"
|
||||
should-delete-messages="false" auto-startup="false" />
|
||||
|
||||
<mail:inbound-channel-adapter id="imapWithAuthenticator" store-uri="imap:test" authenticator="testAuthenticator" channel="testChannel" should-delete-messages="false" auto-startup="false"/>
|
||||
<mail:inbound-channel-adapter id="imapWithAuthenticator"
|
||||
store-uri="imap:test" authenticator="testAuthenticator" channel="testChannel"
|
||||
should-delete-messages="false" auto-startup="false" />
|
||||
|
||||
<mail:imap-idle-channel-adapter id="imapIdleWithAuthenticator" store-uri="imap:test" authenticator="testAuthenticator" channel="testChannel" should-delete-messages="false" auto-startup="false"/>
|
||||
<mail:imap-idle-channel-adapter id="imapIdleWithAuthenticator"
|
||||
store-uri="imap:test" authenticator="testAuthenticator" channel="testChannel"
|
||||
should-delete-messages="false" auto-startup="false" />
|
||||
|
||||
<bean id="testAuthenticator" class="org.springframework.integration.mail.config.InboundChannelAdapterParserTests$TestAuthenticator"/>
|
||||
<bean id="testAuthenticator"
|
||||
class="org.springframework.integration.mail.config.InboundChannelAdapterParserTests$TestAuthenticator" />
|
||||
|
||||
|
||||
<!-- INT-1160 -->
|
||||
|
||||
<mail:inbound-channel-adapter id="pop3WithMaxFetchSize" store-uri="pop3:test" max-fetch-size="11" channel="testChannel" should-delete-messages="false" auto-startup="false"/>
|
||||
<mail:inbound-channel-adapter id="pop3WithMaxFetchSize"
|
||||
store-uri="pop3:test" max-fetch-size="11" channel="testChannel"
|
||||
should-delete-messages="false" auto-startup="false" />
|
||||
|
||||
<mail:inbound-channel-adapter id="pop3WithMaxFetchSizeFallsBackToPollerMax" store-uri="pop3:test" channel="testChannel" should-delete-messages="false" auto-startup="false">
|
||||
<si:poller max-messages-per-poll="99" fixed-rate="30000"/>
|
||||
<mail:inbound-channel-adapter
|
||||
id="pop3WithMaxFetchSizeFallsBackToPollerMax" store-uri="pop3:test"
|
||||
channel="testChannel" should-delete-messages="false" auto-startup="false">
|
||||
<si:poller max-messages-per-poll="99" fixed-rate="30000" />
|
||||
</mail:inbound-channel-adapter>
|
||||
|
||||
<mail:inbound-channel-adapter id="imapWithMaxFetchSize" store-uri="imap:test" max-fetch-size="22" channel="testChannel" should-delete-messages="false" auto-startup="false"/>
|
||||
<mail:inbound-channel-adapter id="imapWithMaxFetchSize"
|
||||
store-uri="imap:test" max-fetch-size="22" channel="testChannel"
|
||||
should-delete-messages="false" auto-startup="false" />
|
||||
|
||||
<mail:imap-idle-channel-adapter id="imapIdleWithMaxFetchSize" store-uri="imap:test" max-fetch-size="33" channel="testChannel" should-delete-messages="false" auto-startup="false"/>
|
||||
<mail:imap-idle-channel-adapter id="imapIdleWithMaxFetchSize"
|
||||
store-uri="imap:test" max-fetch-size="33" channel="testChannel"
|
||||
should-delete-messages="false" auto-startup="false" />
|
||||
|
||||
|
||||
<!-- INT-1161 -->
|
||||
|
||||
<mail:inbound-channel-adapter id="pop3WithSession" store-uri="pop3:test" session="testSession" channel="testChannel" should-delete-messages="false" auto-startup="false"/>
|
||||
<mail:inbound-channel-adapter id="pop3WithSession"
|
||||
store-uri="pop3:test" session="testSession" channel="testChannel"
|
||||
should-delete-messages="false" auto-startup="false" />
|
||||
|
||||
<mail:inbound-channel-adapter id="imapWithSession" store-uri="imap:test" session="testSession" channel="testChannel" should-delete-messages="false" auto-startup="false"/>
|
||||
<mail:inbound-channel-adapter id="imapWithSession"
|
||||
store-uri="imap:test" session="testSession" channel="testChannel"
|
||||
should-delete-messages="false" auto-startup="false" />
|
||||
|
||||
<mail:imap-idle-channel-adapter id="imapIdleWithSession" store-uri="imap:test" session="testSession" channel="testChannel" should-delete-messages="false" auto-startup="false"/>
|
||||
<mail:imap-idle-channel-adapter id="imapIdleWithSession"
|
||||
store-uri="imap:test" session="testSession" channel="testChannel"
|
||||
should-delete-messages="false" auto-startup="false" />
|
||||
|
||||
<bean id="testSession" class="javax.mail.Session" factory-method="getInstance">
|
||||
<constructor-arg>
|
||||
@@ -86,17 +125,28 @@
|
||||
|
||||
<!-- INT-1162 -->
|
||||
|
||||
<mail:inbound-channel-adapter id="pop3WithoutStoreUri" channel="testChannel" protocol="pop3" should-delete-messages="false" auto-startup="false"/>
|
||||
<mail:inbound-channel-adapter id="pop3WithoutStoreUri"
|
||||
channel="testChannel" protocol="pop3" should-delete-messages="false"
|
||||
auto-startup="false" />
|
||||
|
||||
<mail:inbound-channel-adapter id="imapWithoutStoreUri" channel="testChannel" protocol="imap" should-delete-messages="false" auto-startup="false"/>
|
||||
<mail:inbound-channel-adapter id="imapWithoutStoreUri"
|
||||
channel="testChannel" protocol="imap" should-delete-messages="false"
|
||||
auto-startup="false" />
|
||||
|
||||
<mail:imap-idle-channel-adapter id="imapIdleWithoutStoreUri" channel="testChannel" should-delete-messages="false" auto-startup="false"/>
|
||||
<mail:imap-idle-channel-adapter id="imapIdleWithoutStoreUri"
|
||||
channel="testChannel" should-delete-messages="false" auto-startup="false" />
|
||||
|
||||
<mail:inbound-channel-adapter id="pop3ShouldMarkAsReadTrue" channel="testChannel" protocol="pop3" should-delete-messages="false" auto-startup="false" should-mark-messages-as-read="true"/>
|
||||
<mail:inbound-channel-adapter id="pop3ShouldMarkAsReadTrue"
|
||||
channel="testChannel" protocol="pop3" should-delete-messages="false"
|
||||
auto-startup="false" should-mark-messages-as-read="true" />
|
||||
|
||||
<mail:inbound-channel-adapter id="pop3ShouldMarkAsReadFalse" channel="testChannel" protocol="pop3" should-delete-messages="false" auto-startup="false" should-mark-messages-as-read="false"/>
|
||||
<mail:inbound-channel-adapter id="pop3ShouldMarkAsReadFalse"
|
||||
channel="testChannel" protocol="pop3" should-delete-messages="false"
|
||||
auto-startup="false" should-mark-messages-as-read="false" />
|
||||
|
||||
<mail:inbound-channel-adapter id="imapShouldMarkAsReadTrue" channel="testChannel" protocol="imap" should-delete-messages="false" auto-startup="false" should-mark-messages-as-read="true"/>
|
||||
<mail:inbound-channel-adapter id="imapShouldMarkAsReadTrue"
|
||||
channel="testChannel" protocol="imap" should-delete-messages="false"
|
||||
auto-startup="false" should-mark-messages-as-read="true" />
|
||||
|
||||
<!-- INT-2407 -->
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ import org.springframework.integration.mail.Pop3MailReceiver;
|
||||
import org.springframework.integration.mail.SearchTermStrategy;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
@@ -56,6 +57,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
*/
|
||||
@ContextConfiguration
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@DirtiesContext
|
||||
public class InboundChannelAdapterParserTests {
|
||||
|
||||
@Autowired
|
||||
@@ -73,16 +75,22 @@ public class InboundChannelAdapterParserTests {
|
||||
public void pop3ShouldDeleteTrue() {
|
||||
AbstractMailReceiver receiver = this.getReceiver("pop3ShouldDeleteTrue");
|
||||
assertEquals(Pop3MailReceiver.class, receiver.getClass());
|
||||
Boolean value = (Boolean) new DirectFieldAccessor(receiver).getPropertyValue("shouldDeleteMessages");
|
||||
DirectFieldAccessor receiverAccessor = new DirectFieldAccessor(receiver);
|
||||
Boolean value = (Boolean) receiverAccessor.getPropertyValue("shouldDeleteMessages");
|
||||
assertTrue(value);
|
||||
assertEquals(Boolean.FALSE, receiverAccessor.getPropertyValue("embeddedPartsAsBytes"));
|
||||
assertNotNull(receiverAccessor.getPropertyValue("headerMapper"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void imapShouldMarkMessagesAsRead() {
|
||||
AbstractMailReceiver receiver = this.getReceiver("imapShouldMarkAsReadTrue");
|
||||
assertEquals(ImapMailReceiver.class, receiver.getClass());
|
||||
Boolean value = (Boolean) new DirectFieldAccessor(receiver).getPropertyValue("shouldMarkMessagesAsRead");
|
||||
DirectFieldAccessor receiverAccessor = new DirectFieldAccessor(receiver);
|
||||
Boolean value = (Boolean) receiverAccessor.getPropertyValue("shouldMarkMessagesAsRead");
|
||||
assertTrue(value);
|
||||
assertEquals(Boolean.TRUE, receiverAccessor.getPropertyValue("embeddedPartsAsBytes"));
|
||||
assertNull(receiverAccessor.getPropertyValue("headerMapper"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -20,7 +20,7 @@ However, a few simple Message mapping strategies are supported out-of-the-box.
|
||||
For example, if the message payload is a byte array, then that will be mapped to an attachment.
|
||||
For simple text-based emails, you can provide a String-based Message payload.
|
||||
In that case, a MailMessage will be created with that String as the text content.
|
||||
If you are working with a Message payload type whose `toString()`` method returns appropriate mail text content, then consider adding Spring Integration's _ObjectToStringTransformer_ prior to the outbound Mail adapter (see the example within <<transformer-namespace>> for more detail).
|
||||
If you are working with a Message payload type whose `toString()` method returns appropriate mail text content, then consider adding Spring Integration's _ObjectToStringTransformer_ prior to the outbound Mail adapter (see the example within <<transformer-namespace>> for more detail).
|
||||
|
||||
The outbound MailMessage may also be configured with certain values from the `MessageHeaders`.
|
||||
If available, values will be mapped to the outbound mail's properties, such as the recipients (TO, CC, and BCC), the from/reply-to, and the subject.
|
||||
@@ -55,6 +55,82 @@ Spring Integration provides the `ImapIdleChannelAdapter` which is itself a Messa
|
||||
It delegates to an instance of the `ImapMailReceiver` but enables asynchronous reception of Mail Messages.
|
||||
There are examples in the next section of configuring both types of inbound Channel Adapter with Spring Integration's namespace support in the 'mail' schema.
|
||||
|
||||
[[mail-mapping]]
|
||||
=== Inbound Mail Message Mapping
|
||||
|
||||
By default, the payload of messages produced by the inbound adapters is the raw `MimeMessage`; you can interrogate
|
||||
the headers and content using that object.
|
||||
Starting with _version 4.3_, you can provide a `HeaderMapper<MimeMessage>` to map the headers to `MessageHeaders`; for
|
||||
convenience, a `DefaultMailHeaderMapper` is provided for this purpose.
|
||||
This maps the following headers:
|
||||
|
||||
- `mail_from` - A String representation of the `from` address.
|
||||
- `mail_bcc` - A String array containing the `bcc` addresses.
|
||||
- `mail_cc` - A String array containing the `cc` addresses.
|
||||
- `mail_to` - A String array containing the `to` addresses.
|
||||
- `mail_replyTo` - A String representation of the `replyTo` address.
|
||||
- `mail_subject` - The mail subject.
|
||||
- `mail_lineCount` - A line count (if available).
|
||||
- `mail_receivedDate` - The received date (if available).
|
||||
- `mail_size` - The mail size (if available).
|
||||
- `mail_expunged` - A boolen indicating if the message is expunged.
|
||||
- `mail_raw` - A `MultiValueMap` containing all the mail headers and their values.
|
||||
- `mail_contentType` - The content type of the original mail message.
|
||||
- `contentType` - The payload content type (see below).
|
||||
|
||||
When message mapping is enabled, the payload depends on the mail message and its implementation.
|
||||
Email contents are usually rendered by a `DataHandler` within the `MimeMessage`.
|
||||
|
||||
- For a simple `text/*` email, the payload will be a String and the `contentType` header will be the same as
|
||||
`mail_contentType`.
|
||||
|
||||
- For a messages with embedded `javax.mail.Part` s, the `DataHandler` usually renders a `Part` object - these objects
|
||||
are not `Serializable`, and are not suitable for serialization using alternative technologies such as `Kryo`.
|
||||
For this reason, by default, when mapping is enabled, such payloads are rendered as a raw `byte[]` containing the
|
||||
`Part` data.
|
||||
Examples of `Part` are `Message` and `Multipart`.
|
||||
The `contentType` header is `application/octet-stream` in this case.
|
||||
To change this behavior, and receive a `Multipart` object payload, set `embeddedPartsAsBytes` to `false` on the
|
||||
`MailReceiver`.
|
||||
For content types that are unknown to the `DataHandler`, the contents are rendered as a `byte[]` with a `contentType`
|
||||
header of `application/octet-stream`.
|
||||
|
||||
When you do not provide a header mapper, the message payload is the `MimeMessage` presented by `javax.mail`.
|
||||
The framework provides a `MailToStringTransformer` which can be used to convert the message using a simple strategy
|
||||
to convert the mail contents to a String.
|
||||
This is also available using the XML namespace:
|
||||
|
||||
[source, xml]
|
||||
----
|
||||
<int-mail:mail-to-string-transformer ... >
|
||||
----
|
||||
|
||||
and with Java configuration:
|
||||
|
||||
[source, java]
|
||||
----
|
||||
@Bean
|
||||
@Transformer(inputChannel="...", outputChannel="...")
|
||||
public Transformer transformer() {
|
||||
return new MailToStringTransformer();
|
||||
}
|
||||
----
|
||||
|
||||
and with the Java DSL:
|
||||
|
||||
[source, java]
|
||||
----
|
||||
...
|
||||
.transform(Transformers.fromMail())
|
||||
...
|
||||
----
|
||||
|
||||
Starting with _version 4.3_, the transformer will handle embedded `Part` as well as `Multipart` which was handled
|
||||
previously.
|
||||
The transformer is a subclass of `AbstractMailTransformer` which maps the address and subject headers from the list
|
||||
above.
|
||||
If you wish to perform some other transformation on the message, consider subclassing `AbstractMailTransformer`.
|
||||
|
||||
[[mail-namespace]]
|
||||
=== Mail Namespace Support
|
||||
|
||||
@@ -171,7 +247,7 @@ See <<imap-seen>> regarding message flagging.
|
||||
----
|
||||
public interface SearchTermStrategy {
|
||||
|
||||
SearchTerm generateSearchTerm(Flags supportedFlags, Folder folder);
|
||||
SearchTerm generateSearchTerm(Flags supportedFlags, Folder folder);
|
||||
|
||||
}
|
||||
----
|
||||
@@ -206,11 +282,9 @@ If not specified, the previous behavior is retained (peek is `true`).
|
||||
When using IMAP IDLE channel adapter there might be situations where connection to the server may be lost (e.g., network failure) and since Java Mail documentation explicitly states that the actual IMAP API is EXPERIMENTAL it is important to understand the differences in the API and how to deal with them when configuring IMAP IDLE adapters.
|
||||
Currently Spring Integration Mail adapters was tested with Java Mail 1.4.1 and Java Mail 1.4.3 and depending on which one is used special attention must be payed to some of the java mail properties that needs to be set with regard to auto-reconnect.
|
||||
|
||||
_
|
||||
The following behavior was observed with GMAIL but should provide you with some tips on how to solve re-connect
|
||||
issue with other providers, however feedback is always welcome.
|
||||
NOTE: The following behavior was observed with GMAIL but should provide you with some tips on how to solve re-connect
|
||||
issue with other providers, however feedback is always welcome.
|
||||
Again, below notes are based on GMAIL.
|
||||
_
|
||||
|
||||
With Java Mail 1.4.1 if `mail.imaps.timeout` property is set for a relatively short period of time (e.g., ~ 5 min) then `IMAPFolder.idle()` will throw `FolderClosedException` after this timeout.
|
||||
However if this property is not set (should be indefinite) the behavior that was observed is that `IMAPFolder.idle()` method never returns nor it throws an exception.
|
||||
|
||||
@@ -55,10 +55,19 @@ See <<global-properties>> and <<annotations>> for more information.
|
||||
|
||||
==== Mail Changes
|
||||
|
||||
===== Customizable User Flag
|
||||
|
||||
The customizable `userFlag` added in 4.2.2 to provide customization of the flag used to denote that the mail has been
|
||||
seen is now available using the XML namespace.
|
||||
See <<imap-seen>> for more information.
|
||||
|
||||
===== Mail Message Mapping
|
||||
|
||||
There is now an option to map inbound mail messages with the `MessageHeaders` containing the mail headers and the
|
||||
payload containing the email content.
|
||||
Previously, the payload was always the raw `MimeMessage`.
|
||||
See <<mail-mapping>> for more information.
|
||||
|
||||
==== JMS Changes
|
||||
|
||||
===== Header Mapper
|
||||
|
||||
Reference in New Issue
Block a user