GH-3560 Parse mail FROM as comma-delimited header (#3562)

Fixes https://github.com/spring-projects/spring-integration/issues/3560

According RFC 5322 `FROM` and `REPLY-TO` received mail message can be
as an array of addresses.

* Fix `MailUtils` to present those arrays as comma-delimited strings for
Spring message headers
* Fix tests to deal already with several addresses for `FROM` mime header.

In the future we may change the logic to map those mime headers to arrays
as it states according the mentioned RFC

**Cherry-pick to `5.4.x` & `5.3.x`**
This commit is contained in:
Artem Bilan
2021-05-05 16:56:01 -04:00
committed by Gary Russell
parent c682309edb
commit 09e5a1cf7e
5 changed files with 17 additions and 23 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2019 the original author or authors.
* Copyright 2016-2021 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.
@@ -25,12 +25,14 @@ import javax.mail.Message.RecipientType;
import org.springframework.integration.mail.MailHeaders;
import org.springframework.messaging.MessagingException;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Utilities for handling mail messages.
*
* @author Gary Russell
* @author Artem Bilan
*
* @since 4.3
*
*/
@@ -47,29 +49,21 @@ public final class MailUtils {
* @return the map.
*/
public static Map<String, Object> extractStandardHeaders(Message source) {
Map<String, Object> headers = new HashMap<String, Object>();
Map<String, Object> headers = new HashMap<>();
try {
headers.put(MailHeaders.FROM, convertToString(source.getFrom()));
headers.put(MailHeaders.FROM, StringUtils.arrayToCommaDelimitedString(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.REPLY_TO, StringUtils.arrayToCommaDelimitedString(source.getReplyTo()));
headers.put(MailHeaders.SUBJECT, source.getSubject());
return headers;
}
catch (Exception e) {
throw new MessagingException("conversion of MailMessage headers failed", e);
catch (Exception ex) {
throw new MessagingException("conversion of MailMessage headers failed", ex);
}
}
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];

View File

@@ -709,7 +709,7 @@ public class ImapMailReceiverTests {
@Test // see INT-1801
public void testImapLifecycleForRaceCondition() throws Exception {
for (int i = 0; i < 1000; i++) {
for (int i = 0; i < 100; i++) {
final ImapMailReceiver receiver = new ImapMailReceiver("imap://foo");
Store store = mock(Store.class);
Folder folder = mock(Folder.class);

View File

@@ -67,7 +67,7 @@ public class Pop3Tests {
assertThat(headers.get(MailHeaders.TO, String[].class)[0]).isEqualTo("Foo <foo@bar>");
assertThat(Arrays.toString(headers.get(MailHeaders.CC, String[].class))).isEqualTo("[a@b, c@d]");
assertThat(Arrays.toString(headers.get(MailHeaders.BCC, String[].class))).isEqualTo("[e@f, g@h]");
assertThat(headers.get(MailHeaders.FROM)).isEqualTo("Bar <bar@baz>");
assertThat(headers.get(MailHeaders.FROM)).isEqualTo("Bar <bar@baz>,Bar2 <bar2@baz>");
assertThat(headers.get(MailHeaders.SUBJECT)).isEqualTo("Test Email");
assertThat(message.getPayload()).isEqualTo("foo\r\n\r\n");
}

View File

@@ -142,7 +142,7 @@ public class MailTests {
assertThat(message).isNotNull();
MessageHeaders headers = message.getHeaders();
assertThat(headers.get(MailHeaders.TO, String[].class)).containsExactly("Foo <foo@bar>");
assertThat(headers.get(MailHeaders.FROM)).isEqualTo("Bar <bar@baz>");
assertThat(headers.get(MailHeaders.FROM)).isEqualTo("Bar <bar@baz>,Bar2 <bar2@baz>");
assertThat(headers.get(MailHeaders.SUBJECT)).isEqualTo("Test Email");
assertThat(message.getPayload()).isEqualTo("foo\r\n\r\n");
assertThat(message.getHeaders().containsKey(IntegrationMessageHeaderAccessor.CLOSEABLE_RESOURCE)).isTrue();

View File

@@ -484,11 +484,11 @@ public final class TestMailServer {
public static final String MESSAGE =
"To: Foo <foo@bar>\r\n"
+ "cc: a@b, c@d\r\n"
+ "bcc: e@f, g@h\r\n"
+ "From: Bar <bar@baz>\r\n"
+ "Subject: Test Email\r\n"
+ "\r\n" + BODY;
+ "cc: a@b, c@d\r\n"
+ "bcc: e@f, g@h\r\n"
+ "From: Bar <bar@baz>, Bar2 <bar2@baz>\r\n"
+ "Subject: Test Email\r\n"
+ "\r\n" + BODY;
protected final Socket socket; // NOSONAR protected