Skip to content

Commit ead29fc

Browse files
committed
#502: treat all message headers case-insensitively
1 parent 3717559 commit ead29fc

File tree

10 files changed

+175
-78
lines changed

10 files changed

+175
-78
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,65 @@
11
package org.simplejavamail.api.internal.general;
22

3-
import java.util.ArrayList;
3+
import java.util.Arrays;
44
import java.util.List;
55

6+
import static java.util.Collections.singletonList;
7+
68
public class HeadersToIgnoreWhenParsingExternalEmails {
79

810
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
911
public static boolean shouldIgnoreHeader(final String headerName) {
10-
return HEADERS_TO_IGNORE.contains(headerName);
12+
return HEADERS_TO_IGNORE_CASE_INSENSITIVE.stream().map(MessageHeader::getName).anyMatch(headerName::equalsIgnoreCase) ||
13+
HEADERS_TO_IGNORE_CASE_SENSITIVE.stream().map(MessageHeader::getName).anyMatch(headerName::equals);
1114
}
1215

1316
/**
14-
* Contains the headers we will ignore, because either we set the information differently (such as Subject) or we recognize the header as
15-
* interfering or obsolete for new emails.
17+
* Contains the headers we will ignore, because either we set the information differently (such as Subject) or we
18+
* recognize the header as interfering or obsolete for new emails.
1619
*/
17-
private static final List<String> HEADERS_TO_IGNORE = new ArrayList<>();
20+
private static final List<MessageHeader> HEADERS_TO_IGNORE_CASE_INSENSITIVE = Arrays.asList(
21+
MessageHeader.RECEIVED,
22+
MessageHeader.RESENT_DATE,
23+
MessageHeader.RESENT_FROM,
24+
MessageHeader.RESENT_SENDER,
25+
MessageHeader.RESENT_TO,
26+
MessageHeader.RESENT_CC,
27+
MessageHeader.RESENT_BCC,
28+
MessageHeader.DATE,
29+
MessageHeader.FROM,
30+
MessageHeader.SENDER,
31+
MessageHeader.TO,
32+
MessageHeader.CC,
33+
MessageHeader.BCC,
34+
MessageHeader.SUBJECT,
35+
MessageHeader.CONTENT_MD5,
36+
MessageHeader.CONTENT_LENGTH,
37+
MessageHeader.COLON,
38+
MessageHeader.STATUS,
39+
MessageHeader.CONTENT_DISPOSITION,
40+
MessageHeader.SIZE,
41+
MessageHeader.FILENAME,
42+
MessageHeader.CONTENT_ID,
43+
MessageHeader.NAME,
44+
MessageHeader.RESENT_MESSAGE_ID,
45+
MessageHeader.COMMENTS,
46+
MessageHeader.KEYWORDS,
47+
MessageHeader.ERRORS_TO,
48+
MessageHeader.MIME_VERSION,
49+
MessageHeader.CONTENT_TYPE,
50+
MessageHeader.CONTENT_TRANSFER_ENCODING,
51+
MessageHeader.RESENT_MESSAGE_ID,
52+
MessageHeader.REPLY_TO
53+
);
1854

19-
static {
20-
// taken from: protected jakarta.mail.internet.InternetHeaders constructor
21-
/*
22-
* When extracting information to create an Email, we're NOT interested in the following headers:
23-
*/
24-
// HEADERS_TO_IGNORE.add("Return-Path"); // bounceTo address
25-
HEADERS_TO_IGNORE.add("Received");
26-
HEADERS_TO_IGNORE.add("Resent-Date");
27-
HEADERS_TO_IGNORE.add("Resent-From");
28-
HEADERS_TO_IGNORE.add("Resent-Sender");
29-
HEADERS_TO_IGNORE.add("Resent-To");
30-
HEADERS_TO_IGNORE.add("Resent-Cc");
31-
HEADERS_TO_IGNORE.add("Resent-Bcc");
32-
HEADERS_TO_IGNORE.add("Resent-Message-Id");
33-
HEADERS_TO_IGNORE.add("Date");
34-
HEADERS_TO_IGNORE.add("From");
35-
HEADERS_TO_IGNORE.add("Sender");
36-
HEADERS_TO_IGNORE.add("Reply-To");
37-
HEADERS_TO_IGNORE.add("To");
38-
HEADERS_TO_IGNORE.add("Cc");
39-
HEADERS_TO_IGNORE.add("Bcc");
40-
HEADERS_TO_IGNORE.add("Message-Id");
41-
// The next two are needed for replying to
42-
// HEADERS_TO_IGNORE.add("In-Reply-To");
43-
// HEADERS_TO_IGNORE.add("References");
44-
HEADERS_TO_IGNORE.add("Subject");
45-
HEADERS_TO_IGNORE.add("Comments");
46-
HEADERS_TO_IGNORE.add("Keywords");
47-
HEADERS_TO_IGNORE.add("Errors-To");
48-
HEADERS_TO_IGNORE.add("MIME-Version");
49-
HEADERS_TO_IGNORE.add("Content-Type");
50-
HEADERS_TO_IGNORE.add("Content-Transfer-Encoding");
51-
HEADERS_TO_IGNORE.add("Content-MD5");
52-
HEADERS_TO_IGNORE.add(":");
53-
HEADERS_TO_IGNORE.add("Content-Length");
54-
HEADERS_TO_IGNORE.add("Status");
55-
// extra headers that should be ignored, which may originate from nested attachments
56-
HEADERS_TO_IGNORE.add("Content-Disposition");
57-
HEADERS_TO_IGNORE.add("size");
58-
HEADERS_TO_IGNORE.add("filename");
59-
HEADERS_TO_IGNORE.add("Content-ID");
60-
HEADERS_TO_IGNORE.add("name");
61-
HEADERS_TO_IGNORE.add("From");
62-
}
55+
/**
56+
* Similar to {@link #HEADERS_TO_IGNORE_CASE_INSENSITIVE}, but case-sensitive. Why? Well, that's a little
57+
* complicated. These headers cause issues due to legacy code that is not case-insensitive. So we need to keep
58+
* track of these headers separately to avoid issues.
59+
* <p>
60+
* In practice, this should not cause any issues for real-world usage / use cases.
61+
*/
62+
private static final List<MessageHeader> HEADERS_TO_IGNORE_CASE_SENSITIVE = singletonList(
63+
MessageHeader.MESSAGE_ID
64+
);
6365
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package org.simplejavamail.api.internal.general;
2+
3+
import lombok.Getter;
4+
import lombok.RequiredArgsConstructor;
5+
6+
@Getter
7+
@RequiredArgsConstructor
8+
public enum MessageHeader {
9+
// taken from: protected jakarta.mail.internet.InternetHeaders constructor
10+
RECEIVED("Received"),
11+
RESENT_DATE("Resent-Date"),
12+
RESENT_FROM("Resent-From"),
13+
RESENT_SENDER("Resent-Sender"),
14+
RESENT_TO("Resent-To"),
15+
RESENT_CC("Resent-Cc"),
16+
RESENT_BCC("Resent-Bcc"),
17+
RESENT_MESSAGE_ID("Resent-Message-Id"),
18+
DATE("Date"),
19+
FROM("From"),
20+
SENDER("Sender"),
21+
REPLY_TO("Reply-To"),
22+
TO("To"),
23+
CC("Cc"),
24+
BCC("Bcc"),
25+
MESSAGE_ID("Message-Id"),
26+
SUBJECT("Subject"),
27+
COMMENTS("Comments"),
28+
KEYWORDS("Keywords"),
29+
ERRORS_TO("Errors-To"),
30+
MIME_VERSION("MIME-Version"),
31+
CONTENT_TYPE("Content-Type"),
32+
CONTENT_TRANSFER_ENCODING("Content-Transfer-Encoding"),
33+
CONTENT_MD5("Content-MD5"),
34+
CONTENT_LENGTH("Content-Length"),
35+
COLON(":"),
36+
STATUS("Status"),
37+
CONTENT_DISPOSITION("Content-Disposition"),
38+
SIZE("size"),
39+
FILENAME("filename"),
40+
CONTENT_ID("Content-ID"),
41+
NAME("name"),
42+
// headers that are not part of the standard but are used by some email clients
43+
DISPOSITION_NOTIFICATION_TO("Disposition-Notification-To"),
44+
RETURN_RECEIPT_TO("Return-Receipt-To"),
45+
RETURN_PATH("Return-Path"),
46+
// common headers from Google et all that we handle differently
47+
IN_REPLY_TO("In-Reply-To"),
48+
REFERENCES("References"),
49+
;
50+
private final String name;
51+
}

modules/outlook-module/src/main/java/org/simplejavamail/internal/outlooksupport/converter/OutlookEmailConverter.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import org.simplejavamail.api.email.EmailStartingBuilder;
1111
import org.simplejavamail.api.internal.general.EmailPopulatingBuilderFactory;
1212
import org.simplejavamail.api.internal.general.HeadersToIgnoreWhenParsingExternalEmails;
13+
import org.simplejavamail.api.internal.general.MessageHeader;
1314
import org.simplejavamail.api.internal.outlooksupport.model.EmailFromOutlookMessage;
1415
import org.simplejavamail.internal.modules.OutlookModule;
1516
import org.simplejavamail.internal.outlooksupport.internal.model.OutlookMessageProxy;
@@ -133,11 +134,11 @@ private static EmailFromOutlookMessage buildEmailFromOutlookMessage(
133134

134135
@SuppressWarnings("StatementWithEmptyBody")
135136
private static void parseHeader(final String headerName, final String headerValue, final EmailPopulatingBuilder builder) {
136-
if (isEmailHeader(headerName, headerValue, "Disposition-Notification-To")) {
137+
if (isEmailHeader(headerName, headerValue, MessageHeader.DISPOSITION_NOTIFICATION_TO.getName())) {
137138
builder.withDispositionNotificationTo(headerValue);
138-
} else if (isEmailHeader(headerName, headerValue, "Return-Receipt-To")) {
139+
} else if (isEmailHeader(headerName, headerValue, MessageHeader.RETURN_RECEIPT_TO.getName())) {
139140
builder.withReturnReceiptTo(headerValue);
140-
} else if (isEmailHeader(headerName, headerValue, "Return-Path")) {
141+
} else if (isEmailHeader(headerName, headerValue, MessageHeader.RETURN_PATH.getName())) {
141142
builder.withBounceTo(headerValue);
142143
} else if (!HeadersToIgnoreWhenParsingExternalEmails.shouldIgnoreHeader(headerName)) {
143144
builder.withHeader(headerName, headerValue);

modules/simple-java-mail/src/main/java/org/simplejavamail/converter/internal/mimemessage/MimeMessageHelper.java

+7-8
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import org.simplejavamail.api.email.ContentTransferEncoding;
2222
import org.simplejavamail.api.email.Email;
2323
import org.simplejavamail.api.email.Recipient;
24+
import org.simplejavamail.api.internal.general.MessageHeader;
2425
import org.simplejavamail.internal.util.MiscUtil;
2526
import org.simplejavamail.internal.util.NamedDataSource;
2627

@@ -49,8 +50,6 @@ public class MimeMessageHelper {
4950
*/
5051
private static final Charset CHARACTER_ENCODING = UTF_8;
5152

52-
private static final String HEADER_CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding";
53-
5453
static void setSubject(@NotNull final Email email, final MimeMessage message) throws MessagingException {
5554
message.setSubject(email.getSubject(), CHARACTER_ENCODING.name());
5655
}
@@ -107,20 +106,20 @@ static void setTexts(@NotNull final Email email, final MimeMultipart multipartAl
107106
if (email.getPlainText() != null) {
108107
val messagePart = new MimeBodyPart();
109108
messagePart.setText(email.getPlainText(), CHARACTER_ENCODING.name());
110-
messagePart.addHeader(HEADER_CONTENT_TRANSFER_ENCODING, determineContentTransferEncoder(email));
109+
messagePart.addHeader(MessageHeader.CONTENT_TRANSFER_ENCODING.getName(), determineContentTransferEncoder(email));
111110
multipartAlternativeMessages.addBodyPart(messagePart);
112111
}
113112
if (email.getHTMLText() != null) {
114113
val messagePartHTML = new MimeBodyPart();
115114
messagePartHTML.setContent(email.getHTMLText(), format("text/html; charset=\"%s\"", CHARACTER_ENCODING.name()));
116-
messagePartHTML.addHeader(HEADER_CONTENT_TRANSFER_ENCODING, determineContentTransferEncoder(email));
115+
messagePartHTML.addHeader(MessageHeader.CONTENT_TRANSFER_ENCODING.getName(), determineContentTransferEncoder(email));
117116
multipartAlternativeMessages.addBodyPart(messagePartHTML);
118117
}
119118
if (email.getCalendarText() != null) {
120119
val calendarMethod = requireNonNull(email.getCalendarMethod(), "calendarMethod is required when calendarText is set");
121120
val messagePartCalendar = new MimeBodyPart();
122121
messagePartCalendar.setContent(email.getCalendarText(), format("text/calendar; charset=\"%s\"; method=\"%s\"", CHARACTER_ENCODING.name(), calendarMethod));
123-
messagePartCalendar.addHeader(HEADER_CONTENT_TRANSFER_ENCODING, determineContentTransferEncoder(email));
122+
messagePartCalendar.addHeader(MessageHeader.CONTENT_TRANSFER_ENCODING.getName(), determineContentTransferEncoder(email));
124123
multipartAlternativeMessages.addBodyPart(messagePartCalendar);
125124
}
126125
}
@@ -151,7 +150,7 @@ static void setTexts(@NotNull final Email email, final MimePart messagePart)
151150
val calendarMethod = requireNonNull(email.getCalendarMethod(), "CalendarMethod must be set when CalendarText is set");
152151
messagePart.setContent(email.getCalendarText(), format("text/calendar; charset=\"%s\"; method=\"%s\"", CHARACTER_ENCODING.name(), calendarMethod));
153152
}
154-
messagePart.addHeader(HEADER_CONTENT_TRANSFER_ENCODING, determineContentTransferEncoder(email));
153+
messagePart.addHeader(MessageHeader.CONTENT_TRANSFER_ENCODING.getName(), determineContentTransferEncoder(email));
155154
}
156155

157156
/**
@@ -222,13 +221,13 @@ static void setHeaders(@NotNull final Email email, final Message message)
222221
if (TRUE.equals(email.getUseDispositionNotificationTo())) {
223222
final Recipient dispositionTo = checkNonEmptyArgument(email.getDispositionNotificationTo(), "dispositionNotificationTo");
224223
final Address address = MiscUtil.asInternetAddress(dispositionTo, CHARACTER_ENCODING);
225-
message.setHeader("Disposition-Notification-To", address.toString());
224+
message.setHeader(MessageHeader.DISPOSITION_NOTIFICATION_TO.getName(), address.toString());
226225
}
227226

228227
if (TRUE.equals(email.getUseReturnReceiptTo())) {
229228
final Recipient returnReceiptTo = checkNonEmptyArgument(email.getReturnReceiptTo(), "returnReceiptTo");
230229
final Address address = MiscUtil.asInternetAddress(returnReceiptTo, CHARACTER_ENCODING);
231-
message.setHeader("Return-Receipt-To", address.toString());
230+
message.setHeader(MessageHeader.RETURN_RECEIPT_TO.getName(), address.toString());
232231
}
233232
}
234233

modules/simple-java-mail/src/main/java/org/simplejavamail/converter/internal/mimemessage/MimeMessageParser.java

+13-12
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import org.eclipse.angus.mail.handlers.text_plain;
1515
import org.jetbrains.annotations.NotNull;
1616
import org.jetbrains.annotations.Nullable;
17+
import org.simplejavamail.api.internal.general.MessageHeader;
1718
import org.simplejavamail.internal.util.MiscUtil;
1819
import org.simplejavamail.internal.util.NamedDataSource;
1920
import org.simplejavamail.internal.util.Preconditions;
@@ -123,7 +124,7 @@ private static void parseDataSource(@NotNull MimePart currentPart, @NotNull Pars
123124
private static void checkContentTransferEncoding(final MimePart currentPart, @NotNull final ParsedMimeMessageComponents parsedComponents) {
124125
if (parsedComponents.contentTransferEncoding == null) {
125126
for (final Header header : retrieveAllHeaders(currentPart)) {
126-
if (isEmailHeader(DecodedHeader.of(header), "Content-Transfer-Encoding")) {
127+
if (isEmailHeader(DecodedHeader.of(header), MessageHeader.CONTENT_TRANSFER_ENCODING.getName())) {
127128
parsedComponents.contentTransferEncoding = header.getValue();
128129
}
129130
}
@@ -142,12 +143,12 @@ private static MimeDataSource parseAttachment(@Nullable final String contentId,
142143
private static void parseHeader(final Header header, @NotNull final ParsedMimeMessageComponents parsedComponents) {
143144
val decodedHeader = DecodedHeader.of(header);
144145

145-
if (isEmailHeader(decodedHeader, "Disposition-Notification-To")) {
146-
parsedComponents.dispositionNotificationTo = createAddressFromEncodedHeader(header, "Disposition-Notification-To");
147-
} else if (isEmailHeader(decodedHeader, "Return-Receipt-To")) {
148-
parsedComponents.returnReceiptTo = createAddressFromEncodedHeader(header, "Return-Receipt-To");
149-
} else if (isEmailHeader(decodedHeader, "Return-Path")) {
150-
parsedComponents.bounceToAddress = createAddressFromEncodedHeader(header, "Return-Path");
146+
if (isEmailHeader(decodedHeader, MessageHeader.DISPOSITION_NOTIFICATION_TO.getName())) {
147+
parsedComponents.dispositionNotificationTo = createAddressFromEncodedHeader(header, MessageHeader.DISPOSITION_NOTIFICATION_TO.getName());
148+
} else if (isEmailHeader(decodedHeader, MessageHeader.RETURN_RECEIPT_TO.getName())) {
149+
parsedComponents.returnReceiptTo = createAddressFromEncodedHeader(header, MessageHeader.RETURN_RECEIPT_TO.getName());
150+
} else if (isEmailHeader(decodedHeader, MessageHeader.RETURN_PATH.getName())) {
151+
parsedComponents.bounceToAddress = createAddressFromEncodedHeader(header, MessageHeader.RETURN_PATH.getName());
151152
} else {
152153
if (!parsedComponents.headers.containsKey(decodedHeader.getName())) {
153154
parsedComponents.headers.put(decodedHeader.getName(), new ArrayList<>());
@@ -170,7 +171,7 @@ public static String parseFileName(@NotNull final Part currentPart) {
170171
return decodeText(currentPart.getFileName());
171172
} else {
172173
// replicate behavior from Thunderbird
173-
if (Arrays.asList(currentPart.getHeader("Content-Type")).contains("message/rfc822")) {
174+
if (Arrays.asList(currentPart.getHeader(MessageHeader.CONTENT_TYPE.getName())).contains("message/rfc822")) {
174175
return "ForwardedMessage.eml";
175176
}
176177
}
@@ -421,12 +422,12 @@ public static Address[] retrieveRecipients(@NotNull final MimeMessage mimeMessag
421422

422423
private static String getHeaderName(RecipientType recipientType) {
423424
if (recipientType == RecipientType.TO) {
424-
return "To";
425+
return MessageHeader.TO.getName();
425426
} else if (recipientType == RecipientType.CC) {
426-
return "Cc";
427+
return MessageHeader.CC.getName();
427428
} else {
428429
Preconditions.assumeTrue(recipientType == RecipientType.BCC, "invalid recipient type: " + recipientType);
429-
return "Bcc";
430+
return MessageHeader.BCC.getName();
430431
}
431432
}
432433

@@ -448,7 +449,7 @@ public static String parseContentDescription(@NotNull final MimePart mimePart) {
448449
@Nullable
449450
public static String parseContentTransferEncoding(@NotNull final MimePart mimePart) {
450451
try {
451-
return ofNullable(mimePart.getHeader("Content-Transfer-Encoding", ","))
452+
return ofNullable(mimePart.getHeader(MessageHeader.CONTENT_TRANSFER_ENCODING.getName(), ","))
452453
.map(MimeMessageParser::decodeText)
453454
.orElse(null);
454455
} catch (final MessagingException e) {

modules/simple-java-mail/src/test/java/org/simplejavamail/converter/EmailConverterTest.java

+21-3
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@
1818
import java.io.File;
1919
import java.io.IOException;
2020
import java.util.ArrayList;
21+
import java.util.HashMap;
2122
import java.util.List;
2223
import java.util.regex.Matcher;
2324

2425
import static demo.ResourceFolderHelper.determineResourceFolder;
25-
import static jakarta.mail.Message.RecipientType.CC;
26-
import static jakarta.mail.Message.RecipientType.TO;
26+
import static jakarta.mail.Message.RecipientType.*;
2727
import static java.lang.String.format;
2828
import static java.nio.charset.Charset.defaultCharset;
2929
import static java.nio.charset.StandardCharsets.UTF_8;
@@ -51,6 +51,7 @@ public void testOutlookBasicConversions() {
5151
EmailAssert.assertThat(msg).hasOnlyRecipients(sven, niklas);
5252
EmailAssert.assertThat(msg).hasNoAttachments();
5353
assertThat(msg.getHeaders()).containsEntry("x-pmx-scanned", singletonList("Mail was scanned by Sophos Pure Message"));
54+
assertThat(msg.getHeaders()).doesNotContainKeys("CC", "Cc", "cc", "BCC", "Bcc", "bcc", "TO", "To", "to");
5455
assertThat(msg.getPlainText()).isNotEmpty();
5556
assertThat(normalizeNewlines(msg.getHTMLText())).isEqualTo("<div dir=\"auto\">Just a test to get an email with one cc recipient.</div>\n");
5657
assertThat(normalizeNewlines(msg.getPlainText())).isEqualTo("Just a test to get an email with one cc recipient.\n");
@@ -190,12 +191,29 @@ public void testProblematic8BitContentTransferEncoding() {
190191
}
191192

192193
@Test
193-
public void testProblematicCommasInRecipeints() {
194+
public void testProblematicCommasInRecipients() {
194195
Email s1 = EmailConverter.emlToEmail(new File(RESOURCE_TEST_MESSAGES + "/#444 Email with encoded comma in recipients.eml"));
195196
EmailAssert.assertThat(s1).hasFromRecipient(new Recipient("Some Name, Jane Doe", "[email protected]", null));
196197
EmailAssert.assertThat(s1).hasOnlyRecipients(new Recipient("Some Name 2, John Doe", "[email protected]", TO));
197198
}
198199

200+
@Test
201+
public void testProblematicCcHeader() {
202+
Email recipientsCamelcase = EmailConverter.emlToEmail(new File(RESOURCE_TEST_MESSAGES + "/#502 Recipients camelcase header.eml"));
203+
EmailAssert.assertThat(recipientsCamelcase).hasFromRecipient(new Recipient("from someone", "[email protected]", null));
204+
EmailAssert.assertThat(recipientsCamelcase).hasOnlyRecipients(
205+
new Recipient("to person", "[email protected]", TO),
206+
new Recipient("cc person", "[email protected]", CC),
207+
new Recipient("bcc person", "[email protected]", BCC));
208+
EmailAssert.assertThat(recipientsCamelcase).hasHeaders(new HashMap<>());
209+
210+
Email recipientsCapitals = EmailConverter.emlToEmail(new File(RESOURCE_TEST_MESSAGES + "/#502 Recipients capitals header.eml"));
211+
Email recipientsLowercase = EmailConverter.emlToEmail(new File(RESOURCE_TEST_MESSAGES + "/#502 Recipients lowercase header.eml"));
212+
213+
assertThat(recipientsCapitals).isEqualTo(recipientsCamelcase);
214+
assertThat(recipientsLowercase).isEqualTo(recipientsCamelcase);
215+
}
216+
199217
@Test
200218
public void testProblematicExchangeDeliveryReceipts() throws Exception {
201219
SecureTestDataHelper.runTestWithSecureTestData(passwords -> {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
From: from someone <[email protected]>
2+
To: to person <[email protected]>
3+
Cc: cc person <[email protected]>
4+
Bcc: bcc person <[email protected]>
5+
Subject: An RFC 822 formatted message
6+
7+
This is the plain text body of the message. Note the blank line
8+
between the header information and the body of the message.

0 commit comments

Comments
 (0)