メールサポート
このセクションでは、Spring Integration でメールメッセージを操作する方法について説明します。
この依存関係をプロジェクトに含める必要があります。
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-mail</artifactId>
<version>5.5.8</version>
</dependency>
compile "org.springframework.integration:spring-integration-mail:5.5.8"
javax.mail:javax.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 はいくつかの単純なメッセージマッピング戦略をサポートしています。例: メッセージペイロードがバイト配列の場合、添付ファイルにマップされます。単純なテキストベースのメールの場合、文字列ベースのメッセージペイロードを提供できます。その場合、String
をテキストコンテンツとして使用して MailMessage
が作成されます。toString()
メソッドが適切なメールテキストコンテンツを返すメッセージペイロード型を使用する場合は、送信メールアダプターの前に Spring Integration の ObjectToStringTransformer
を追加することを検討してください(詳細については、XML を使用した Transformer の構成の例を参照してください)。
MessageHeaders
の特定の値を使用して、送信 MailMessage
を構成することもできます。可能な場合、値は、受信者(To、Cc、BCc)、from、reply-to、subject などの送信メールのプロパティにマップされます。ヘッダー名は、次の定数によって定義されます。
MailHeaders.SUBJECT
MailHeaders.TO
MailHeaders.CC
MailHeaders.BCC
MailHeaders.FROM
MailHeaders.REPLY_TO
MailHeaders では、対応する MailMessage 値をオーバーライドすることもできます。例: MailMessage.to が '[ メール保護 ] (英語) ' に設定され、MailHeaders.TO メッセージヘッダーが提供される場合、それが優先され、MailMessage の対応する値をオーバーライドします。 |
メール受信チャネルアダプター
Spring Integration は、MailReceivingMessageSource
を使用した受信メールのサポートも提供します。Spring Integration 自身の MailReceiver
インターフェースの構成済みインスタンスに委譲します。Pop3MailReceiver
と ImapMailReceiver
の 2 つの実装があります。これらのいずれかをインスタンス化する最も簡単な方法は、次の例に示すように、メールストアの "uri" を受信者のコンストラクターに渡すことです。
MailReceiver receiver = new Pop3MailReceiver("pop3://usr:pwd@localhost/INBOX");
メールを受信する別のオプションは、IMAP idle
コマンドです(メールサーバーでサポートされている場合)。Spring Integration は、それ自体がメッセージ生成エンドポイントである ImapIdleChannelAdapter
を提供します。ImapMailReceiver
のインスタンスに委譲しますが、メールメッセージの非同期受信を有効にします。次のセクションでは、「メール」スキーマで 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
API を参照)がチャネルアダプターからプロデューサーへのすべてのメッセージに入力されます。これは、新しいメッセージを取得するためにフォルダーを開いたり閉じたりすることに依存しているため、Pop3MailReceiver
では機能しません。ダウンストリームフローで必要な場合は常に、このヘッダーで close()
を呼び出すのはターゲットアプリケーションの責任です。
Closeable closeableResource = StaticMessageHeaderAccessor.getCloseableResource(mailMessage);
if (closeableResource != null) {
closeableResource.close();
}
フォルダーを開いたままにしておくと、添付ファイル付きのメールのマルチパートコンテンツの解析中にサーバーとの通信が必要な場合に役立ちます。shouldDeleteMessages
が AbstractMailReceiver
でそれぞれ構成されている場合、IntegrationMessageHeaderAccessor.CLOSEABLE_RESOURCE
ヘッダーの close()
は AbstractMailReceiver
に委譲して、expunge
オプションでフォルダーを閉じます。
バージョン 5.4 以降、変換や先行したコンテンツの読み込みを行わずに、MimeMessage
をそのまま返すことができるようになりました。この機能は、次のオプションの組み合わせで有効になります。headerMapper
は提供されず、simpleContent
プロパティは false
であり、autoCloseFolder
プロパティは false
です。MimeMessage
は、生成された Spring メッセージのペイロードとして存在します。この場合、入力されるヘッダーは、MimeMessage
の処理が完了したときに閉じる必要があるフォルダーの上記の IntegrationMessageHeaderAccessor.CLOSEABLE_RESOURCE
のみです。
受信メールメッセージマッピング
デフォルトでは、受信アダプターによって生成されるメッセージのペイロードは生の MimeMessage
です。そのオブジェクトを使用して、ヘッダーとコンテンツを調べることができます。バージョン 4.3 から、HeaderMapper<MimeMessage>
を提供してヘッダーを MessageHeaders
にマップできます。便宜上、Spring Integration はこの目的のために DefaultMailHeaderMapper
を提供します。次のヘッダーをマップします。
mail_from
:from
アドレスのString
表現。mail_bcc
:bcc
アドレスを含むString
配列。mail_cc
:cc
アドレスを含むString
配列。mail_to
:to
アドレスを含むString
配列。mail_replyTo
:replyTo
アドレスのString
表現。mail_subject
: メールの件名。mail_lineCount
: 行数(使用可能な場合)。mail_receivedDate
: 受信日(利用可能な場合)。mail_size
: メールのサイズ(利用可能な場合)。mail_expunged
: メッセージが削除されたかどうかを示すブール値。mail_raw
: すべてのメールヘッダーとその値を含むMultiValueMap
。mail_contentType
: 元のメールメッセージのコンテンツ型。contentType
: ペイロードコンテンツ型(以下を参照)。
メッセージマッピングが有効な場合、ペイロードはメールメッセージとその実装に依存します。通常、メールの内容は、MimeMessage
内の DataHandler
によってレンダリングされます。
text/*
メールの場合、ペイロードは String
であり、contentType
ヘッダーは mail_contentType
と同じです。
javax.mail.Part
インスタンスが埋め込まれたメッセージの場合、DataHandler
は通常 Part
オブジェクトをレンダリングします。これらのオブジェクトは Serializable
ではなく、Kryo
などの代替技術による直列化には適していません。このため、デフォルトでは、マッピングが有効になっている場合、そのようなペイロードは Part
データを含む生の byte[]
としてレンダリングされます。Part
の例は、Message
および Multipart
です。この場合、contentType
ヘッダーは application/octet-stream
です。この動作を変更して Multipart
オブジェクトペイロードを受信するには、MailReceiver
で embeddedPartsAsBytes
を false
に設定します。DataHandler
にとって未知のコンテンツ型の場合、コンテンツは application/octet-stream
の contentType
ヘッダーを持つ byte[]
としてレンダリングされます。
ヘッダーマッパーを指定しない場合、メッセージペイロードは javax.mail
によって提示される MimeMessage
です。フレームワークは、メールの内容を String
に変換する戦略を使用してメッセージを変換するために使用できる MailToStringTransformer
を提供します。
...
.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
インスタンス)を処理します。トランスフォーマーは、上記のリストのアドレスおよびサブジェクトヘッダーをマップする 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 以降、java-mail-properties
が提供されている場合、host
、username
、mail-sender
は省略できます。ただし、host
および username
は、適切な Java メールプロパティで構成する必要があります。SMTP の場合:
[email protected] (英語)
mail.smtp.host=smtp.gmail.com
mail.smtp.port=587
送信チャネルアダプターと同様に、参照されるチャネルが PollableChannel である場合、<poller> 要素を提供する必要があります(エンドポイント名前空間のサポートを参照)。 |
名前空間のサポートを使用する場合、header-enricher
メッセージトランスフォーマーも使用できます。そうすることで、メール送信チャネルアダプターに送信する前のメッセージへの前述のヘッダーの適用が簡単になります。
次の例では、ペイロードが、指定されたプロパティに適切な getter を備えた Java Bean であると想定していますが、任意の 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
属性を指定して、既存のヘッダーの動作を制御することもできます。
受信チャネルアダプターを構成するには、ポーリングまたはイベントドリブンのいずれかを選択できます(メールサーバーが IMAP idle
をサポートしている場合は、ポーリングが唯一のオプションです)。ポーリングチャネルアダプターには、ストア 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>
IMAP idle
をサポートしている場合は、代わりに imap-idle-channel-adapter
要素を構成することができます。idle
コマンドはイベント駆動型通知を有効にするため、このアダプターにポーラーは必要ありません。新しいメールが利用可能であるという通知を受信するとすぐに、指定されたチャネルにメッセージを送信します。次の例では、IMAP idle
メールチャネルを構成します。
<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
オブジェクトを作成および設定します。たとえば、Spring が提供する 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 以降、ImapMailReceiver
が使用する SearchTerm
は SearchTermStrategy
で完全に構成可能であり、search-term-strategy
属性を使用して注入できます。SearchTermStrategy
は、ImapMailReceiver
が使用する SearchTerm
のインスタンスを作成できる単一のメソッドを持つストラテジーインターフェースです。次のリストは、SearchTermStrategy
インターフェースを示しています。
public interface SearchTermStrategy {
SearchTerm generateSearchTerm(Flags supportedFlags, Folder folder);
}
次の例は、デフォルトの SearchTermStrategy
ではなく TestSearchTermStrategy
に依存しています。
<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"/>
メッセージのフラグ付けについては、\Recent
がサポートされていない場合の IMAP メッセージのマーキングを参照してください。
重要: IMAP PEEK バージョン 4.1.1 以降、IMAP メールレシーバーは、指定されている場合、 |
IMAP idle
と失われた接続
IMAP idle
チャネルアダプターを使用すると、サーバーへの接続が失われる場合があります(たとえば、ネットワーク障害など)。また、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
を強制的に返すか、単に戻るように強制する条件が常に存在するようになり、自動再接続を続行できます。現在、自動再接続は無限に実行され、10 秒ごとに再接続を試みます。
どちらの構成でも、channel と should-delete-messages は必須属性です。should-delete-messages が必要な理由を理解する必要があります。課題は POP3 プロトコルにあります。POP3 プロトコルには、読み取られたメッセージに関する知識がありません。単一セッション内で読み取られた内容のみを知ることができます。つまり、POP3 メールアダプターを実行すると、各ポーリング中にメールが利用可能になり、メールが正常に消費され、単一のメールメッセージが複数回配信されることはありません。ただし、アダプターを再起動して新しいセッションを開始するとすぐに、以前のセッションで取得された可能性のあるすべてのメールメッセージが再度取得されます。それが POP3 の性質です。should-delete-messages はデフォルトで true であると主張する人もいます。言い換えれば、1 つの最適なデフォルトを選択するのが非常に困難になる、2 つの有効で相互排他的な使用箇所があります。アダプターを唯一のメール受信者として設定することもできます。その場合、以前に配信されたメッセージが再度配信されないことを恐れずにアダプターを再起動できるようにする必要があります。この場合、should-delete-messages を true に設定するのが最も理にかなっています。ただし、別のユースケースでは、複数のアダプターでメールサーバーとそのコンテンツを監視することもできます。言い換えると、「タッチするのではなく、のぞきたい」ということです。次に、should-delete-messages を false に設定するのがはるかに適切です。そのため、should-delete-messages 属性の正しいデフォルト値を選択するのは難しいため、ユーザーが設定する必要のある属性にしました。また、あなたに任せておくと、意図しない動作が発生する可能性が低くなります。 |
ポーリングメールアダプターの should-mark-messages-as-read 属性を構成する場合、メッセージを取得するために構成しているプロトコルに注意する必要があります。例: POP3 はこのフラグをサポートしていません。つまり、メッセージが既読としてマークされていないため、どちらの値に設定しても効果がありません。 |
サイレントにドロップされた接続の場合、アイドルキャンセルタスクがバックグラウンドで定期的に実行されます(通常、新しい IDLE はすぐに処理されます)。この間隔を制御するために、cancelIdleInterval
オプションが提供されています。デフォルト 120 (2 分)。RFC 2177 は、29 分以内の間隔を推奨しています。
これらのアクション(メッセージの開封と削除)は、メッセージを受信した後、処理する前に実行されることを理解する必要があります。これにより、メッセージが失われる可能性があります。 代わりにトランザクション同期の使用を検討することをお勧めします。トランザクションの同期を参照してください。 |
<imap-idle-channel-adapter/>
は 'error-channel' 属性も受け入れます。ダウンストリーム例外がスローされ、「エラーチャネル」が指定されている場合、失敗したメッセージと元の例外を含む MessagingException
メッセージがこのチャネルに送信されます。そうでない場合、ダウンストリームチャネルが同期である場合、そのような例外はチャネルアダプターによって警告としてログに記録されます。
3.0 リリース以降、IMAP idle アダプターは、例外が発生するとアプリケーションイベント(具体的には ImapIdleExceptionEvent インスタンス)を発行します。これにより、アプリケーションはこれらの例外を検出して処理できます。ImapIdleExceptionEvent またはそのスーパークラスの 1 つを受信するように構成された <int-event:inbound-channel-adapter> または任意の ApplicationListener を使用して、イベントを取得できます。 |
\Recent
がサポートされていない場合の IMAP メッセージのマーキング
shouldMarkMessagesAsRead
が true の場合、IMAP アダプターは \Seen
フラグを設定します。
さらに、メールサーバーが \Recent
フラグをサポートしていない場合、サーバーがユーザーフラグをサポートしている限り、IMAP アダプターはメッセージをユーザーフラグ(デフォルトでは spring-integration-mail-adapter
)でマークします。そうでない場合、Flag.FLAGGED
は true
に設定されます。これらのフラグは、shouldMarkMessagesRead
設定に関係なく適用されます。
[ 検索語 ] で説明したように、デフォルトの SearchTermStrategy
は、フラグが立てられたメッセージを無視します。
バージョン 4.2.2 以降、MailReceiver
で setUserFlag
を使用してユーザーフラグの名前を設定できます。これにより、複数の受信者が異なるフラグを使用できるようになります(メールサーバーがユーザーフラグをサポートしている場合)。user-flag
属性は、名前空間を使用してアダプターを構成するときに使用できます。
メールメッセージのフィルタリング
多くの場合、受信メッセージをフィルタリングする必要があります(たとえば、Subject
行に "Spring Integration" が含まれるメールのみを読み取りたい場合)。これは、受信メールアダプターを式ベースの Filter
に接続することで実現できます。それは機能しますが、このアプローチには欠点があります。受信メールアダプターを通過した後、メッセージはフィルタリングされるため、そのようなメッセージはすべて既読(SEEN
)または未読(should-mark-messages-as-read
属性の値に応じて)としてマークされます。ただし、実際には、メッセージがフィルタリング条件に合格した場合にのみ、SEEN
としてメッセージをマークする方が便利です。これは、プレビューペインですべてのメッセージをスクロールしながらメールクライアントを表示するのと似ていますが、実際に開かれて SEEN
として読み取られたメッセージにのみフラグを付けます。
Spring Integration 2.0.4 は、inbound-channel-adapter
および imap-idle-channel-adapter
に mail-filter-expression
属性を導入しました。この属性を使用すると、SpEL と正規表現を組み合わせた式を提供できます。たとえば、件名に "Spring Integration" を含むメールのみを読みたい場合は、mail-filter-expression
属性を mail-filter-expression="subject matches '(?i).Spring Integration."
のように構成します。
javax.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" を含むメッセージのみがこのアダプターによって生成されます。
別の妥当な質問は、次のポーリングまたはアイドルイベントで何が起こるか、そのようなアダプターが再起動されたときに何が起こるかです。フィルタリングするマッサージの重複はありますか? つまり、最後の取得時に、5 つの新しいメッセージがあり、1 つだけがフィルターを通過した場合、他の 4 つのメッセージはどうなるでしょうか? 次のポーリングまたはアイドルで再びフィルタリングロジックを使用しますか? 結局、それらは SEEN
としてマークされていませんでした。答えはいいえだ。メールサーバーによって設定され、Spring Integration メール検索フィルターによって使用される別のフラグ(RECENT
)により、重複処理の対象にはなりません。フォルダー実装はこのフラグを設定して、このメッセージがこのフォルダーにとって新しいものであることを示します。つまり、このフォルダーが最後に開かれてから届きました。言い換えれば、アダプターはメールを覗き込むかもしれませんが、メールサーバーはそのようなメールがタッチされたため、メールサーバーによって 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
ファクトリを提供します。これは次のように使用できます。
@SpringBootApplication
public class MailApplication {
public static void main(String[] args) {
new SpringApplicationBuilder(MailApplication.class)
.web(false)
.run(args);
}
@Bean
public IntegrationFlow imapMailFlow() {
return IntegrationFlows
.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 IntegrationFlows.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();
}
}