此版本仍在开发中,尚不被认为是稳定的。对于最新的稳定版本,请使用 Spring Integration 6.5.1! |
邮件支持
本节介绍如何在 Spring Integration 中处理邮件消息。
您需要将此依赖项包含在您的项目中:
-
Maven
-
Gradle
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-mail</artifactId>
<version>6.5.2-SNAPSHOT</version>
</dependency>
compile "org.springframework.integration:spring-integration-mail:6.5.2-SNAPSHOT"
这jakarta.mail:jakarta.mail-api
必须通过特定于提供商的实施包含在内。
邮件发送通道适配器
Spring Integration 通过MailSendingMessageHandler
.
它委托给 Spring 的JavaMailSender
,如以下示例所示:
JavaMailSender mailSender = context.getBean("mailSender", JavaMailSender.class);
MailSendingMessageHandler mailSendingHandler = new MailSendingMessageHandler(mailSender);
MailSendingMessageHandler
有各种映射策略,使用 Spring 的MailMessage
抽象化。
如果收到的消息的有效负载已经是MailMessage
实例,它直接发送。
因此,我们通常建议您在该消费者之前使用转换器,以进行不平凡的MailMessage
施工要求。
但是,Spring Integration 支持一些简单的消息映射策略。
例如,如果消息有效负载是字节数组,则映射到附件。
对于简单的基于文本的电子邮件,可以提供基于字符串的邮件有效负载。
在这种情况下,一个MailMessage
是用它创建的String
作为文本内容。
如果您使用的消息有效负载类型,其toString()
方法返回适当的邮件文本内容,请考虑添加 Spring Integration 的ObjectToStringTransformer
在出站邮件适配器之前(有关更多详细信息,请参阅使用 XML 配置转换器中的示例)。
您还可以配置出站MailMessage
某些值来自MessageHeaders
.
如果可用,则值将映射到出站邮件的属性,例如收件人(收件人、抄送和 BCc)、from
这reply-to
和subject
.
标头名称由以下常量定义:
MailHeaders.SUBJECT
MailHeaders.TO
MailHeaders.CC
MailHeaders.BCC
MailHeaders.FROM
MailHeaders.REPLY_TO
MailHeaders 还允许您覆盖相应的MailMessage 值。
例如,如果MailMessage.to 设置为“[email protected]”,并且MailHeaders.TO message header 时,它优先并覆盖MailMessage . |
邮件接收通道适配器
Spring Integration 还通过MailReceivingMessageSource
.
它委托给 Spring Integration 自己的已配置实例MailReceiver
接口。
有两种实现方式:Pop3MailReceiver
和ImapMailReceiver
.
实例化其中任何一个的最简单方法是将邮件存储的“uri”绕过接收方的构造函数,如以下示例所示:
MailReceiver receiver = new Pop3MailReceiver("pop3://usr:pwd@localhost/INBOX");
接收邮件的另一种选择是 IMAPidle
命令(如果您的邮件服务器支持)。
Spring Integration 提供了ImapIdleChannelAdapter
,它本身就是一个生成消息的端点。
它委托给ImapMailReceiver
.
下一节提供了在“mail”模式中使用 Spring Integration 的命名空间支持配置两种类型的入站通道适配器的示例。
通常,当 |
To: [email protected]
From: [email protected]
Subject: Test Email
something
通过简单的MimeMessage
,getContent()
返回邮件正文 (something
在前面的示例中)。
从 2.2 版开始,该框架急切地获取 IMAP 消息并将它们公开为MimeMessage
.
这产生了不良副作用,即更改getContent()
行为。
4.3 版中引入的邮件映射增强功能进一步加剧了这种不一致,因为当提供标头映射器时,有效负载是由IMAPMessage.getContent()
方法。
这意味着 IMAP 内容会有所不同,具体取决于是否提供了标头映射器。
从版本 5.0 开始,源自 IMAP 源的消息将按照IMAPMessage.getContent()
行为,无论是否提供了标头映射器。
如果您不使用标头映射器,并且希望恢复到之前仅渲染正文的行为,请将simpleContent
邮件接收器上的布尔属性设置为true
.
现在,无论是否使用标头映射器,此属性都会控制渲染。
现在,当提供标头映射器时,它允许仅渲染正文。
从 5.2 版开始,autoCloseFolder
选项。
将其设置为false
不会在获取后自动关闭文件夹,而是IntegrationMessageHeaderAccessor.CLOSEABLE_RESOURCE
标题(请参阅MessageHeaderAccessor
应用程序接口有关更多信息)将填充到从通道适配器发送给生产者的每条消息中。
这不适用于Pop3MailReceiver
因为它依赖于打开和关闭文件夹来获取新邮件。
目标应用程序负责调用close()
在下游流中需要时在此标头上:
Closeable closeableResource = StaticMessageHeaderAccessor.getCloseableResource(mailMessage);
if (closeableResource != null) {
closeableResource.close();
}
在解析带有附件的电子邮件的多部分内容期间需要与服务器通信的情况下,保持文件夹打开非常有用。
这close()
在IntegrationMessageHeaderAccessor.CLOSEABLE_RESOURCE
标头委托给AbstractMailReceiver
以关闭文件夹,并使用expunge
选项shouldDeleteMessages
分别在AbstractMailReceiver
.
从 5.4 版开始,现在可以返回MimeMessage
没有任何转换或急切的内容加载。
此功能通过以下选项组合启用:否headerMapper
提供,simpleContent
属性是false
和autoCloseFolder
属性是false
.
这MimeMessage
作为生成的 Spring 消息的有效负载存在。
在这种情况下,唯一填充的标头是上面提到的IntegrationMessageHeaderAccessor.CLOSEABLE_RESOURCE
对于在处理MimeMessage
是完整的。
从 5.5.11 版本开始,文件夹在AbstractMailReceiver.receive()
如果未收到任何消息或所有消息都被过滤掉,则与autoCloseFolder
旗。
在这种情况下,没有任何东西可以为可能的逻辑生成下游IntegrationMessageHeaderAccessor.CLOSEABLE_RESOURCE
页眉。
从 6.0.5 版本开始,ImapIdleChannelAdapter
不再执行异步消息发布。
这对于阻止下游消息处理的空闲侦听器循环(例如,具有大附件)是必要的,因为邮件文件夹必须保持打开状态。
如果需要异步切换,则ExecutorChannel
可用作该通道适配器的输出通道。
入站邮件消息映射
默认情况下,入站适配器生成的消息的有效负载是原始的MimeMessage
.
您可以使用该对象来查询标题和内容。
从 4.3 版开始,您可以提供HeaderMapper<MimeMessage>
将标头映射到MessageHeaders
.
为方便起见,Spring Integration 提供了一个DefaultMailHeaderMapper
为此目的。
它映射以下标头:
-
mail_from
:一个String
的表示from
地址。 -
mail_bcc
:一个String
数组包含bcc
地址。 -
mail_cc
:一个String
数组包含cc
地址。 -
mail_to
:一个String
数组包含to
地址。 -
mail_replyTo
:一个String
的表示replyTo
地址。 -
mail_subject
:邮件主题。 -
mail_lineCount
:行计数(如果可用)。 -
mail_receivedDate
:接收日期(如果可用)。 -
mail_size
:邮件大小(如果可用)。 -
mail_expunged
:指示邮件是否被删除的布尔值。 -
mail_raw
:一个MultiValueMap
包含所有邮件标头及其值。 -
mail_contentType
:原始邮件的信息内容类型。 -
contentType
:有效负载内容类型(见下文)。
启用邮件映射后,有效负载取决于邮件邮件及其实现。
电子邮件内容通常由DataHandler
在MimeMessage
.
对于一个text/*
email,有效负载是String
和contentType
header 与mail_contentType
.
对于嵌入的消息jakarta.mail.Part
实例,则DataHandler
通常渲染Part
对象。
这些对象不是Serializable
并且不适合使用替代技术(例如Kryo
.
因此,默认情况下,启用映射时,此类有效负载将呈现为原始负载byte[]
包含Part
数据。
示例Part
是Message
和Multipart
.
这contentType
header 是application/octet-stream
在这种情况下。
要更改此行为并接收Multipart
对象有效负载, 设置embeddedPartsAsBytes
自false
上MailReceiver
.
对于未知的内容类型DataHandler
,则内容将呈现为byte[]
使用contentType
的标题application/octet-stream
.
如果不提供标头映射器,则消息有效负载是MimeMessage
主办方jakarta.mail
.
该框架提供了一个MailToStringTransformer
您可以使用该策略将邮件内容转换为String
:
-
Java DSL
-
Java
-
Kotlin
-
XML
...
.transform(Mail.toStringTransformer())
...
@Bean
@Transformer(inputChannel="...", outputChannel="...")
public Transformer transformer() {
return new MailToStringTransformer();
}
...
transform(Mail.toStringTransformer())
...
<int-mail:mail-to-string-transformer ... >
从 4.3 版开始,转换器处理嵌入Part
实例(以及Multipart
实例,之前已处理过)。
transformer 是AbstractMailTransformer
映射前面列表中的地址和主题标头。
如果您希望对消息执行一些其他转换,请考虑子类化AbstractMailTransformer
.
从 5.4 版开始,当没有headerMapper
提供,autoCloseFolder
是false
和simpleContent
是false
这MimeMessage
在生成的 Spring 消息的有效负载中按原样返回。
这样,内容MimeMessage
在流的后面引用时按需加载。
上述所有转换仍然有效。
邮件命名空间支持
Spring Integration 为与邮件相关的配置提供了一个命名空间。 若要使用它,请配置以下架构位置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int-mail="http://www.springframework.org/schema/integration/mail"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration/mail
https://www.springframework.org/schema/integration/mail/spring-integration-mail.xsd">
若要配置出站通道适配器,请提供要从中接收的通道和 MailSender,如以下示例所示:
<int-mail:outbound-channel-adapter channel="outboundMail"
mail-sender="mailSender"/>
或者,您可以提供主机、用户名和密码,如以下示例所示:
<int-mail:outbound-channel-adapter channel="outboundMail"
host="somehost" username="someuser" password="somepassword"/>
从 5.1.3 版本开始,host
,username
阿内mail-sender
如果java-mail-properties
被提供。
但是,host
和username
必须配置适当的 Java 邮件属性,例如对于 SMTP:
[email protected]
mail.smtp.host=smtp.gmail.com
mail.smtp.port=587
与任何出站通道适配器一样,如果引用的通道是PollableChannel ,您应该提供一个<poller> 元素(请参阅端点命名空间支持)。 |
使用命名空间支持时,还可以使用header-enricher
消息转换器。
这样做可以简化在发送到邮件出站通道适配器之前将前面提到的标头应用于任何邮件。
以下示例假定有效负载是一个 Java Bean,具有指定属性的适当 getter,但您可以使用任何 SpEL 表达式:
<int-mail:header-enricher input-channel="expressionsInput" default-overwrite="false">
<int-mail:to expression="payload.to"/>
<int-mail:cc expression="payload.cc"/>
<int-mail:bcc expression="payload.bcc"/>
<int-mail:from expression="payload.from"/>
<int-mail:reply-to expression="payload.replyTo"/>
<int-mail:subject expression="payload.subject" overwrite="true"/>
</int-mail:header-enricher>
或者,您可以使用value
属性来指定文字。您还可以指定default-overwrite
和个人overwrite
属性来控制现有标头的行为。
要配置入站通道适配器,您可以选择轮询或事件驱动(假设您的邮件服务器支持 IMAPidle
— 如果没有,则轮询是唯一的选项)。轮询通道适配器需要存储 URI 和向其发送入站消息的通道。URI 可以以pop3
或imap
. 以下示例使用imap
URI:
<int-mail:inbound-channel-adapter id="imapAdapter"
store-uri="imaps://[username]:[password]@imap.gmail.com/INBOX"
java-mail-properties="javaMailProperties"
channel="receiveChannel"
should-delete-messages="true"
should-mark-messages-as-read="true"
auto-startup="true">
<int:poller max-messages-per-poll="1" fixed-rate="5000"/>
</int-mail:inbound-channel-adapter>
如果您确实有 IMAPidle
support,您可能需要配置imap-idle-channel-adapter
元素。由于idle
命令启用事件驱动通知,此适配器不需要轮询器。一旦收到新邮件可用的通知,它就会立即向指定通道发送消息。以下示例配置 IMAPidle
邮件渠道:
<int-mail:imap-idle-channel-adapter id="customAdapter"
store-uri="imaps://[username]:[password]@imap.gmail.com/INBOX"
channel="receiveChannel"
auto-startup="true"
should-delete-messages="false"
should-mark-messages-as-read="true"
java-mail-properties="javaMailProperties"/>
您可以提供javaMailProperties
通过创建和填充常规java.utils.Properties
对象 — 例如,通过使用util
命名空间。
如果您的用户名包含该字符,请使用@ %40 而不是避免解析来自底层 JavaMail API 的错误。@ |
以下示例演示如何配置java.util.Properties
对象:
<util:properties id="javaMailProperties">
<prop key="mail.imap.socketFactory.class">javax.net.ssl.SSLSocketFactory</prop>
<prop key="mail.imap.socketFactory.fallback">false</prop>
<prop key="mail.store.protocol">imaps</prop>
<prop key="mail.debug">false</prop>
</util:properties>
默认情况下,ImapMailReceiver
根据默认值搜索邮件SearchTerm
,这是所有邮件:
-
是最近的(如果支持)
-
没有得到回答
-
未删除
-
看不见
-
h尚未由此邮件接收方处理(通过使用自定义 USER 标志启用,或者如果不支持则直接 NOT FLAGGED)
自定义用户标志是spring-integration-mail-adapter
,但您可以对其进行配置。
从 2.2 版本开始,SearchTerm
由ImapMailReceiver
完全可配置SearchTermStrategy
,您可以使用search-term-strategy
属性。
一个SearchTermStrategy
是一个策略接口,具有单一方法,可让您创建SearchTerm
由ImapMailReceiver
.
以下列表显示了SearchTermStrategy
接口:
public interface SearchTermStrategy {
SearchTerm generateSearchTerm(Flags supportedFlags, Folder folder);
}
以下示例依赖于TestSearchTermStrategy
而不是默认值SearchTermStrategy
:
<mail:imap-idle-channel-adapter id="customAdapter"
store-uri="imap:something"
…
search-term-strategy="searchTermStrategy"/>
<bean id="searchTermStrategy"
class="o.s.i.mail.config.ImapIdleChannelAdapterParserTests.TestSearchTermStrategy"/>
看在以下情况下标记 IMAP 消息Recent
不支持有关邮件标记的信息。
重要提示:IMAP PEEK
从版本 4.1.1 开始,IMAP 邮件接收器使用 |
IMAPidle
和失去的连接
使用 IMAP 时idle
channel adapter,则与服务器的连接可能会丢失(例如,由于网络故障),并且由于 JavaMail 文档明确指出实际的 IMAP API 是实验性的,因此了解 API 中的差异以及如何在配置 IMAP 时处理它们非常重要idle
适配器。
目前,Spring Integration 邮件适配器已使用 JavaMail 1.4.1 和 JavaMail 1.4.3 进行了测试。
根据使用的某个属性,您必须特别注意一些需要设置的与自动重新连接相关的 JavaMail 属性。
在 Gmail 中观察到以下行为,但应该会为您提供一些有关如何解决与其他提供商重新连接问题的提示。 但是,我们始终欢迎反馈。 同样,以下注释基于 Gmail。 |
在 JavaMail 1.4.1 中,如果您将mail.imaps.timeout
属性到相对较短的时间(在我们的测试中大约 5 分钟),IMAPFolder.idle()
抛出FolderClosedException
超时后。
但是,如果未设置此属性(它应该是无限的),则IMAPFolder.idle()
方法从不返回,也从不抛出异常。
但是,如果连接在短时间内丢失(在我们的测试中不到 10 分钟),它会自动重新连接。
但是,如果连接长时间(超过 10 分钟)丢失,IMAPFolder.idle()
,不抛FolderClosedException
并且不会重新建立连接,并且无限期地保持阻塞状态,因此如果不重新启动适配器,您就无法重新连接。
因此,使用 JavaMail 1.4.1 重新连接的唯一方法是将mail.imaps.timeout
属性显式设置为某个值,但这也意味着该值应该相对较短(10 分钟以内),并且应该相对较快地重新建立连接。
同样,与 Gmail 以外的提供商可能会有所不同。
在 JavaMail 1.4.3 中,对 API 进行了重大改进,确保始终有一个条件强制IMAPFolder.idle()
返回的方法StoreClosedException
或FolderClosedException
或者简单地返回,从而让您继续自动重新连接。
目前,自动重新连接无限运行,每十秒尝试一次重新连接。
在这两种配置中,channel 和should-delete-messages 是必需属性。
你应该明白为什么should-delete-messages 是必需的。
问题出在 POP3 协议上,该协议不知道已读取的消息。
它只能知道在单个会话中读取了什么。
这意味着,当您的 POP3 邮件适配器运行时,电子邮件在每次轮询期间可用时都会成功使用,并且不会多次传递单个电子邮件。
但是,一旦重新启动适配器并开始新会话,就会再次检索可能在上一个会话中检索到的所有电子邮件。
这就是 POP3 的本质。
有些人可能会争辩说should-delete-messages 应该是true 默认情况下。
换句话说,有两种有效且相互排斥的用途,这使得很难选择一个最佳默认值。
您可能希望将适配器配置为唯一的电子邮件接收方,在这种情况下,您希望能够重新启动适配器,而不必担心以前传递的邮件不会再次传递。
在这种情况下,将should-delete-messages 自true 最有意义。
但是,您可能还有另一个用例,您可能希望让多个适配器监控电子邮件服务器及其内容。
换句话说,你想“偷看但不触摸”。
然后设置should-delete-messages 自false 更合适。
因此,由于很难选择正确的默认值should-delete-messages 属性,我们将其设置为您需要设置的必需属性。
由你决定也意味着你不太可能最终做出意外行为。 |
配置轮询电子邮件适配器的should-mark-messages-as-read 属性,您应该了解要配置的用于检索消息的协议。
例如,POP3 不支持此标志,这意味着将其设置为任一值都无效,因为消息未标记为已读。 |
在无提示断开连接的情况下,会定期在后台运行空闲取消任务(通常会立即处理新的空闲)。
要控制此间隔,请cancelIdleInterval
选项;默认为 120(2 分钟)。
RFC 2177 建议间隔不超过 29 分钟。
您应该了解,这些作(标记已读消息和删除消息)是在收到消息之后但在处理消息之前执行的。 这可能会导致消息丢失。 您可能希望考虑使用事务同步。 请参阅事务同步。 |
这<imap-idle-channel-adapter/>
也接受 'error-channel' 属性。
如果抛出下游异常并指定了“错误通道”,则MessagingException
包含失败消息和原始异常的消息将发送到此通道。
否则,如果下游通道是同步的,则通道适配器将记录任何此类异常作为警告。
从 3.0 版本开始,IMAPidle adapter 发出应用程序事件(特别是ImapIdleExceptionEvent 实例)发生异常时。
这允许应用程序检测这些异常并对其采取行动。
您可以使用<int-event:inbound-channel-adapter> 或任何ApplicationListener 配置为接收ImapIdleExceptionEvent 或其超级类之一。 |
在以下情况下标记 IMAP 消息\Recent
不支持
如果shouldMarkMessagesAsRead
为 true,则 IMAP 适配器将\Seen
旗。
此外,当电子邮件服务器不支持\Recent
标志,IMAP 适配器使用用户标志标记消息(默认情况下,spring-integration-mail-adapter
),只要服务器支持用户标志即可。
如果没有,Flag.FLAGGED
设置为true
.
无论shouldMarkMessagesRead
设置。
但是,从版本 6.4 开始,\Flagged
也可以禁用。
这AbstractMailReceiver
公开一个setFlaggedAsFallback(boolean flaggedAsFallback)
跳过设置的选项\Flagged
.
在某些情况下,无论邮箱中的邮件上都不需要此类标志\Recent
或者用户标志也没有得到支持。
如SearchTerm
,默认值SearchTermStrategy
忽略被标记的邮件。
从 4.2.2 版开始,您可以使用setUserFlag
在MailReceiver
.
这样做可以让多个接收者使用不同的标志(只要邮件服务器支持用户标志)。
这user-flag
属性在使用命名空间配置适配器时可用。
电子邮件过滤
很多时候,您可能会遇到过滤传入邮件的要求(例如,您只想读取Subject
线)。
您可以通过将入站邮件适配器与基于表达式的Filter
.
虽然它会奏效,但这种方法有一个缺点。
由于邮件将在通过入站邮件适配器后进行过滤,因此所有此类邮件都将标记为已读 (SEEN
) 或未读(取决于should-mark-messages-as-read
属性)。
然而,实际上,将消息标记为SEEN
仅当它们通过筛选条件时。
这类似于在滚动浏览预览窗格中的所有邮件时查看您的电子邮件客户端,但仅标记实际打开并读取为SEEN
.
Spring Integration 2.0.4 引入了mail-filter-expression
属性inbound-channel-adapter
和imap-idle-channel-adapter
.
此属性允许您提供由 SpEL 和正则表达式组合而成的表达式。
例如,如果您只想阅读主题行中包含“Spring Integration”的电子邮件,则可以配置mail-filter-expression
属性,如下所示:mail-filter-expression="subject matches '(?i).*Spring Integration.*"
.
因为jakarta.mail.internet.MimeMessage
是 SpEL 评估上下文的根上下文,您可以通过以下方式过滤任何可用的值MimeMessage
,包括消息的实际正文。
这一点特别重要,因为读取消息正文通常会导致此类消息被标记为SEEN
默认情况下。
但是,由于我们现在将PEEK
每个传入消息的标志为“true”,仅显式标记为SEEN
标记为已读。
因此,在以下示例中,此适配器仅输出与筛选器表达式匹配的消息,并且仅将这些消息标记为已读:
<int-mail:imap-idle-channel-adapter id="customAdapter"
store-uri="imaps://some_google_address:${password}@imap.gmail.com/INBOX"
channel="receiveChannel"
should-mark-messages-as-read="true"
java-mail-properties="javaMailProperties"
mail-filter-expression="subject matches '(?i).*Spring Integration.*'"/>
在前面的示例中,由于mail-filter-expression
属性,则此适配器仅生成主题行中包含“Spring Integration”的消息。
另一个合理的问题是,在下一次轮询或空闲事件中会发生什么,或者当重新启动此类适配器时会发生什么。
可以重复过滤按摩吗?换句话说,如果在上次检索时,您有五条新消息,只有一封通过了过滤器,那么其他四条消息会发生什么?
他们会在下一次轮询中再次通过过滤逻辑还是空闲?
毕竟,它们没有被标记为SEEN
.
答案是否定的。
它们不会因另一个标志 (RECENT
)由电子邮件服务器设置并由 Spring Integration 邮件搜索过滤器使用。
文件夹实现设置此标志以指示此邮件是此文件夹的新邮件。
也就是说,自上次打开此文件夹以来,它就已经到达。
换句话说,虽然我们的适配器可能会偷看电子邮件,但它也会让电子邮件服务器知道此类电子邮件已被触摸,因此应标记为RECENT
由电子邮件服务器。
事务同步
入站适配器的事务同步允许您在事务提交或回滚后执行不同的作。
您可以通过添加<transactional/>
元素添加到轮询器中,以便轮询<inbound-adapter/>
或对<imap-idle-inbound-adapter/>
.
即使不涉及“真实”事务,您仍然可以使用PseudoTransactionManager
使用<transactional/>
元素。
有关详细信息,请参阅事务同步。
由于邮件服务器不同,特别是某些服务器的限制,目前我们只为这些事务同步提供策略。 您可以将消息发送到其他一些 Spring Integration 组件或调用自定义 bean 来执行某些作。 例如,若要在事务提交后将 IMAP 邮件移动到其他文件夹,可以使用类似于以下内容的内容:
<int-mail:imap-idle-channel-adapter id="customAdapter"
store-uri="imaps://something.com:[email protected]/INBOX"
channel="receiveChannel"
auto-startup="true"
should-delete-messages="false"
java-mail-properties="javaMailProperties">
<int:transactional synchronization-factory="syncFactory"/>
</int-mail:imap-idle-channel-adapter>
<int:transaction-synchronization-factory id="syncFactory">
<int:after-commit expression="@syncProcessor.process(payload)"/>
</int:transaction-synchronization-factory>
<bean id="syncProcessor" class="thing1.thing2.Mover"/>
以下示例显示了Mover
类可能如下所示:
public class Mover {
public void process(MimeMessage message) throws Exception {
Folder folder = message.getFolder();
folder.open(Folder.READ_WRITE);
String messageId = message.getMessageID();
Message[] messages = folder.getMessages();
FetchProfile contentsProfile = new FetchProfile();
contentsProfile.add(FetchProfile.Item.ENVELOPE);
contentsProfile.add(FetchProfile.Item.CONTENT_INFO);
contentsProfile.add(FetchProfile.Item.FLAGS);
folder.fetch(messages, contentsProfile);
// find this message and mark for deletion
for (int i = 0; i < messages.length; i++) {
if (((MimeMessage) messages[i]).getMessageID().equals(messageId)) {
messages[i].setFlag(Flags.Flag.DELETED, true);
break;
}
}
Folder somethingFolder = store.getFolder("SOMETHING");
somethingFolder.appendMessages(new MimeMessage[]{message});
folder.expunge();
folder.close(true);
somethingFolder.close(false);
}
}
为了使消息在事务后仍然可用于作,必须将 should-delete-messages 设置为 'false'。 |
使用 Java DSL 配置通道适配器
要在 Java DSL 中配置邮件组件,该框架提供了一个o.s.i.mail.dsl.Mail
factory,可以这样使用:
@SpringBootApplication
public class MailApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(MailApplication.class)
.web(false)
.run(args);
}
@Bean
public IntegrationFlow imapMailFlow() {
return IntegrationFlow
.from(Mail.imapInboundAdapter("imap://user:pw@host:port/INBOX")
.searchTermStrategy(this::fromAndNotSeenTerm)
.userFlag("testSIUserFlag")
.simpleContent(true)
.javaMailProperties(p -> p.put("mail.debug", "false")),
e -> e.autoStartup(true)
.poller(p -> p.fixedDelay(1000)))
.channel(MessageChannels.queue("imapChannel"))
.get();
}
@Bean
public IntegrationFlow sendMailFlow() {
return IntegrationFlow.from("sendMailChannel")
.enrichHeaders(Mail.headers()
.subjectFunction(m -> "foo")
.from("foo@bar")
.toFunction(m -> new String[] { "bar@baz" }))
.handle(Mail.outboundAdapter("gmail")
.port(smtpServer.getPort())
.credentials("user", "pw")
.protocol("smtp"),
e -> e.id("sendMailEndpoint"))
.get();
}
}