8000 #298, #315: further improved support for nested Outlook messages, by … · zdfsir/simple-java-mail@85ad8b1 · GitHub
[go: up one dir, main page]

Skip to content

Commit 85ad8b1

Browse files
committed
bbottema#298, bbottema#315: further improved support for nested Outlook messages, by serializing to standard EML instead of a binary form of an Email instance. Removed the Kryo dependency completely as a consequence. Also, started using Outlook's own strategy for naming the nested message attachment (basically by using its subject)
1 parent 5f29eb1 commit 85ad8b1

File tree

8 files changed

+96
-105
lines changed

8 files changed

+96
-105
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
package org.simplejavamail.internal.modules;
22

3+
import org.jetbrains.annotations.NotNull;
34
import org.simplejavamail.api.email.EmailStartingBuilder;
45
import org.simplejavamail.api.internal.general.EmailPopulatingBuilderFactory;
56
import org.simplejavamail.api.internal.outlooksupport.model.EmailFromOutlookMessage;
7+
import org.simplejavamail.internal.util.InternalEmailConverter;
68

7-
import org.jetbrains.annotations.NotNull;
89
import java.io.File;
910
import java.io.InputStream;
1011

1112
public interface OutlookModule {
12-
EmailFromOutlookMessage outlookMsgToEmailBuilder(@NotNull File msgFile, @NotNull EmailStartingBuilder emailStartingBuilder, @NotNull final EmailPopulatingBuilderFactory builderFactory);
13-
EmailFromOutlookMessage outlookMsgToEmailBuilder(@NotNull String msgData, @NotNull EmailStartingBuilder emailStartingBuilder, @NotNull final EmailPopulatingBuilderFactory builderFactory);
14-
EmailFromOutlookMessage outlookMsgToEmailBuilder(@NotNull InputStream msgInputStream, @NotNull EmailStartingBuilder emailStartingBuilder, @NotNull final EmailPopulatingBuilderFactory builderFactory);
13+
EmailFromOutlookMessage outlookMsgToEmailBuilder(@NotNull File msgFile, @NotNull EmailStartingBuilder emailStartingBuilder, @NotNull EmailPopulatingBuilderFactory builderFactory, @NotNull InternalEmailConverter internalEmailConverter);
14+
EmailFromOutlookMessage outlookMsgToEmailBuilder(@NotNull String msgData, @NotNull EmailStartingBuilder emailStartingBuilder, @NotNull EmailPopulatingBuilderFactory builderFactory, @NotNull InternalEmailConverter internalEmailConverter);
15+
EmailFromOutlookMessage outlookMsgToEmailBuilder(@NotNull InputStream msgInputStream, @NotNull EmailStartingBuilder emailStartingBuilder, @NotNull EmailPopulatingBuilderFactory builderFactory, @NotNull InternalEmailConverter internalEmailConverter);
1516
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package org.simplejavamail.internal.util;
2+
3+
import org.jetbrains.annotations.NotNull;
4+
import org.simplejavamail.api.email.Email;
5+
6+
import javax.mail.internet.MimeMessage;
7+
8+
/**
9+
* API that allows the Outlook module to invoke the EmailConverter API from the main Simple Java Mail module. This is used when converting Outlook messages to Email objects, which contain nested
10+
* Outlook messages that need to be converted to MimeMessage (via Email objects as well) so they can be added again as EML attachments.
11+
*/
12+
public interface InternalEmailConverter {
13+
MimeMessage emailToMimeMessage(@NotNull Email email);
14+
15+
byte[] mimeMessageToEMLByteArray(@NotNull MimeMessage mimeMessage);
16+
}

modules/outlook-module/pom.xml

-13
Original file line numberDiff line numberDiff line change
@@ -38,19 +38,6 @@
3838
<version>1.7.9</version>
3939
<scope>compile</scope>
4040
</dependency>
41-
<!-- needed for converting outlook messages to Email objects, including deeply nested attachments -->
42-
<dependency>
43-
<groupId>com.esotericsoftware</groupId>
44-
<artifactId>kryo</artifactId>
45-
<version>5.0.0-RC1</version>
46-
<scope>compile</scope>
47-
</dependency>
48-
<dependency><!-- adds support for deserializing UnmodifiableCollection -->
49-
<groupId>de.javakaffee</groupId>
50-
<artifactId>kryo-serializers</artifactId>
51-
<version>0.45</version>
52-
<scope>compile</scope>
53-
</dependency>
5441
</dependencies>
5542

5643
<!-- Apache POI 4.x is Java 8, so we can't use that -->

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

+21-17
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import org.simplejavamail.api.internal.outlooksupport.model.EmailFromOutlookMessage;
99
import org.simplejavamail.internal.modules.OutlookModule;
1010
import org.simplejavamail.internal.outlooksupport.internal.model.OutlookMessageProxy;
11+
import org.simplejavamail.internal.util.InternalEmailConverter;
1112
import org.simplejavamail.internal.util.MiscUtil;
1213
import org.simplejavamail.outlookmessageparser.model.OutlookAttachment;
1314
import org.simplejavamail.outlookmessageparser.model.OutlookFileAttachment;
@@ -16,13 +17,13 @@
1617
import org.simplejavamail.outlookmessageparser.model.OutlookRecipient;
1718
import org.slf4j.Logger;
1819

20+
import javax.mail.internet.MimeMessage;
1921
import javax.mail.util.ByteArrayDataSource;
2022
import java.io.File;
2123
import java.io.IOException;
2224
import java.io.InputStream;
2325
import java.util.Map;
2426

25-
import static org.simplejavamail.internal.outlooksupport.internal.util.SerializationUtil.serialize;
2627
import static org.simplejavamail.internal.util.MiscUtil.extractCID;
2728
import static org.simplejavamail.internal.util.Preconditions.assumeNonNull;
2829
import static org.simplejavamail.internal.util.Preconditions.checkNonEmptyArgument;
@@ -38,39 +39,46 @@ public class OutlookEmailConverter implements OutlookModule {
3839
public EmailFromOutlookMessage outlookMsgToEmailBuilder(
3940
@NotNull final File msgFile,
4041
@NotNull final EmailStartingBuilder emailStartingBuilder,
41-
@NotNull final EmailPopulatingBuilderFactory builderFactory) {
42+
@NotNull final EmailPopulatingBuilderFactory builderFactory,
43+
@NotNull final InternalEmailConverter internalEmailConverter) {
4244
return buildEmailFromOutlookMessage(
4345
emailStartingBuilder.ignoringDefaults().startingBlank(),
4446
parseOutlookMsg(checkNonEmptyArgument(msgFile, "msgFile")),
45-
builderFactory);
47+
builderFactory,
48+
internalEmailConverter);
4649
}
4750

4851
@Override
4952
public EmailFromOutlookMessage outlookMsgToEmailBuilder(
5053
@NotNull final String msgFile,
5154
@NotNull final EmailStartingBuilder emailStartingBuilder,
52-
@NotNull final EmailPopulatingBuilderFactory builderFactory) {
55+
@NotNull final EmailPopulatingBuilderFactory builderFactory,
56+
@NotNull final InternalEmailConverter internalEmailConverter) {
5357
return buildEmailFromOutlookMessage(
5458
emailStartingBuilder.ignoringDefaults().startingBlank(),
5559
parseOutlookMsg(checkNonEmptyArgument(msgFile, "msgFile")),
56-
builderFactory);
60+
builderFactory,
61+
internalEmailConverter);
5762
}
5863

5964
@Override
6065
public EmailFromOutlookMessage outlookMsgToEmailBuilder(
6166
@NotNull final InputStream msgInputStream,
6267
@NotNull final EmailStartingBuilder emailStartingBuilder,
63-
@NotNull final EmailPopulatingBuilderFactory builderFactory) {
68+
@NotNull final EmailPopulatingBuilderFactory builderFactory,
69+
@NotNull final InternalEmailConverter internalEmailConverter) {
6470
return buildEmailFromOutlookMessage(
6571
emailStartingBuilder.ignoringDefaults().startingBlank(),
6672
parseOutlookMsg(checkNonEmptyArgument(msgInputStream, "msgInputStream")),
67-
builderFactory);
73+
builderFactory,
74+
internalEmailConverter);
6875
}
6976

7077
private static EmailFromOutlookMessage buildEmailFromOutlookMessage(
7178
@NotNull final EmailPopulatingBuilder builder,
7279
@NotNull final OutlookMessage outlookMessage,
73-
@NotNull final EmailPopulatingBuilderFactory builderFactory) {
80+
@NotNull final EmailPopulatingBuilderFactory builderFactory,
81+
@NotNull final InternalEmailConverter internalEmailConverter) {
7482
checkNonEmptyArgument(builder, "emailBuilder");
7583
checkNonEmptyArgument(outlookMessage, "outlookMessage");
7684
String fromEmail = ofNullable(outlookMessage.getFromEmail()).orElse("donotreply@unknown-from-address.net");
@@ -97,15 +105,11 @@ private static EmailFromOutlookMessage buildEmailFromOutlookMessage(
97105
final OutlookAttachment attachment = outlookMessage.getOutlookAttachments().get(i);
98106
if (attachment instanceof OutlookMsgAttachment) {
99107
final OutlookMessage nestedMsg = ((OutlookMsgAttachment) attachment).getOutlookMessage();
100-
final Email email = buildEmailFromOutlookMessage(builderFactory.create(), nestedMsg, builderFactory).getEmailBuilder().buildEmail();
101-
102-
try {
103-
builder.withAttachment("attachment " + i + " as nested Outlook message (converted).sjm",
104-
new ByteArrayDataSource(serialize(email), "application/octet-stream"));
105-
} catch (IOException e) {
106-
// don't crash on serialization errors: this is mostly a best effort supported feature
107-
LOGGER.error("Was unable to serialize Email converted from nested Outlook message", e);
108-
}
108+
final Email email = buildEmailFromOutlookMessage(builderFactory.create(), nestedMsg, builderFactory, internalEmailConverter)
109+
.getEmailBuilder().buildEmail();
110+
final MimeMessage message = internalEmailConverter.emailToMimeMessage(email);
111+
final byte[] mimedata = internalEmailConverter.mimeMessageToEMLByteArray(message);
112+
builder.withAttachment(nestedMsg.getSubject() + ".eml", new ByteArrayDataSource(mimedata, "message/rfc822"));
109113
}
110114
}
111115

modules/outlook-module/src/main/java/org/simplejavamail/internal/outlooksupport/internal/util/SerializationUtil.java

-59
This file was deleted.

modules/simple-java-mail/src/main/java/org/simplejavamail/converter/EmailConverter.java

+18-3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import org.simplejavamail.api.internal.outlooksupport.model.OutlookMessage;
1212
import org.simplejavamail.api.internal.smimesupport.builder.SmimeParseResult;
1313
import org.simplejavamail.api.mailer.config.Pkcs12Config;
14+
import org.simplejavamail.converter.internal.InternalEmailConverterImpl;
1415
import org.simplejavamail.converter.internal.mimemessage.MimeMessageParser;
1516
import org.simplejavamail.converter.internal.mimemessage.MimeMessageParser.ParsedMimeMessageComponents;
1617
import org.simplejavamail.converter.internal.mimemessage.MimeMessageProducerHelper;
@@ -126,7 +127,7 @@ public static Email outlookMsgToEmail(@NotNull final String msgData) {
126127
public static Email outlookMsgToEmail(@NotNull final String msgData, @Nullable final Pkcs12Config pkcs12Config) {
127128
checkNonEmptyArgument(msgData, "msgFile");
128129
EmailFromOutlookMessage result = ModuleLoader.loadOutlookModule()
129-
.outlookMsgToEmailBuilder(msgData, new EmailStartingBuilderImpl(), new EmailPopulatingBuilderFactoryImpl());
130+
.outlookMsgToEmailBuilder(msgData, new EmailStartingBuilderImpl(), new EmailPopulatingBuilderFactoryImpl(), InternalEmailConverterImpl.INSTANCE);
130131
return decryptAttachments(result.getEmailBuilder(), result.getOutlookMessage(), pkcs12Config)
131132
.buildEmail();
132133
}
@@ -175,7 +176,7 @@ public static EmailPopulatingBuilder outlookMsgToEmailBuilder(@NotNull final Fil
175176
throw new EmailConverterException(format(EmailConverterException.FILE_NOT_RECOGNIZED_AS_OUTLOOK, msgFile));
176177
}
177178
EmailFromOutlookMessage result = ModuleLoader.loadOutlookModule()
178-
.outlookMsgToEmailBuilder(msgFile, new EmailStartingBuilderImpl(), new EmailPopulatingBuilderFactoryImpl());
179+
.outlookMsgToEmailBuilder(msgFile, new EmailStartingBuilderImpl(), new EmailPopulatingBuilderFactoryImpl(), InternalEmailConverterImpl.INSTANCE);
179180
return decryptAttachments(result.getEmailBuilder(), result.getOutlookMessage(), pkcs12Config);
180181
}
181182

@@ -211,7 +212,7 @@ public static EmailFromOutlookMessage outlookMsgToEmailBuilder(@NotNull final In
211212
@NotNull
212213
public static EmailFromOutlookMessage outlookMsgToEmailBuilder(@NotNull final InputStream msgInputStream, @Nullable final Pkcs12Config pkcs12Config) {
213214
EmailFromOutlookMessage fromMsgBuilder = ModuleLoader.loadOutlookModule()
214-
.outlookMsgToEmailBuilder(msgInputStream, new EmailStartingBuilderImpl(), new EmailPopulatingBuilderFactoryImpl());
215+
.outlookMsgToEmailBuilder(msgInputStream, new EmailStartingBuilderImpl(), new EmailPopulatingBuilderFactoryImpl(), InternalEmailConverterImpl.INSTANCE);
215216
decryptAttachments(fromMsgBuilder.getEmailBuilder(), fromMsgBuilder.getOutlookMessage(), pkcs12Config);
216217
return fromMsgBuilder;
217218
}
@@ -509,6 +510,20 @@ public static MimeMessage emlToMimeMessage(@NotNull final String eml, @NotNull f
509510
/**
510511
* @return The result of {@link MimeMessage#writeTo(OutputStream)} which should be in the standard EML format.
511512
*/
513+
public static byte[] mimeMessageToEMLByteArray(@NotNull final MimeMessage mimeMessage) {
514+
final ByteArrayOutputStream os = new ByteArrayOutputStream();
515+
try {
516+
checkNonEmptyArgument(mimeMessage, "mimeMessage").writeTo(os);
517+
return os.toByteArray();
518+
} catch (IOException | MessagingException e) {
519+
// this should never happen, so we don't acknowledge this exception (and simply bubble up)
520+
throw new IllegalStateException("This should never happen", e);
521+
}
522+
}
523+
524+
/**
525+
* @return The result of {@link MimeMessage#writeTo(OutputStream)} with which should be in the standard EML format, to UTF8 string.
526+
*/
512527
public static String mimeMessageToEML(@NotNull final MimeMessage mimeMessage) {
513528
final ByteArrayOutputStream os = new ByteArrayOutputStream();
514529
try {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package org.simplejavamail.converter.internal;
2+
3+
import org.jetbrains.annotations.NotNull;
4+
import org.simplejava 10000 mail.api.email.Email;
5+
import org.simplejavamail.converter.EmailConverter;
6+
import org.simplejavamail.internal.util.InternalEmailConverter;
7+
8+
import javax.mail.internet.MimeMessage;
9+
10+
/**
11+
* @see InternalEmailConverter
12+
*/
13+
// FIXME lombok
14+
public class InternalEmailConverterImpl implements InternalEmailConverter {
15+
16+
public static final InternalEmailConverter INSTANCE = new InternalEmailConverterImpl();
17+
18+
private InternalEmailConverterImpl() {}
19+
20+
@Override
21+
public MimeMessage emailToMimeMessage(@NotNull final Email email) {
22+
return EmailConverter.emailToMimeMessage(email);
23+
}
24+
25+
@Override
26+
public byte[] mimeMessageToEMLByteArray(@NotNull final MimeMessage mimeMessage) {
27+
return EmailConverter.mimeMessageToEMLByteArray(mimeMessage);
28+
}
29+
}

modules/simple-java-mail/src/test/java/org/simplejavamail/mailer/MailerLiveTest.java

+7-9
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
import static org.assertj.core.data.MapEntry.entry;
4141
import static org.simplejavamail.converter.EmailConverter.mimeMessageToEmail;
4242
import static org.simplejavamail.converter.EmailConverter.mimeMessageToEmailBuilder;
43-
import static org.simplejavamail.internal.outlooksupport.internal.util.SerializationUtil.deserialize;
4443
import static org.simplejavamail.internal.util.MiscUtil.normalizeNewlines;
4544
import static org.simplejavamail.internal.util.Preconditions.assumeNonNull;
4645
import static org.simplejavamail.internal.util.Preconditions.checkNonEmptyArgument;
@@ -139,10 +138,10 @@ public void testOutlookMessageWithNestedOutlookMessageAttachment()
139138
Email email = EmailConverter.outlookMsgToEmail(checkNonEmptyArgument(resourceAsStream, "resourceAsStream"));
140139

141140
assertThat(email.getAttachments()).hasSize(2);
142-
assertThat(email.getAttachments().get(1).getName()).isEqualTo("attachment 0 as nested Outlook message (converted).sjm");
141+
assertThat(email.getAttachments().get(1).getName()).isEqualTo("This msg file is an attachment.eml");
143142

144-
final InputStream sjmInputstream = email.getAttachments().get(1).getDataSourceInputStream();
145-
Email nestedEmail = deserialize(sjmInputstream);
143+
final InputStream emlInputstream = email.getAttachments().get(1).getDataSourceInputStream();
144+
Email nestedEmail = EmailConverter.emlToEmail(emlInputstream);
146145

147146
EmailAssert.assertThat(nestedEmail).hasSubject("This msg file is an attachment");
148147
assertThat(normalizeNewlines(nestedEmail.getPlainText()))
@@ -151,16 +150,15 @@ public void testOutlookMessageWithNestedOutlookMessageAttachment()
151150
}
152151

153152
@Test
154-
public void testOutlookMessageWithNestedOutlookMessageAttachmentThatHasItsOwnNestedAttachment()
155-
throws IOException {
153+
public void testOutlookMessageWithNestedOutlookMessageAttachmentThatHasItsOwnNestedAttachment() {
156154
InputStream resourceAsStream = EmailHelper.class.getClassLoader().getResourceAsStream("test-messages/#298 Email with nested msg with own attachment.msg");
157155
Email email = EmailConverter.outlookMsgToEmail(checkNonEmptyArgument(resourceAsStream, "resourceAsStream"));
158156

159157
assertThat(email.getAttachments()).hasSize(2);
160-
assertThat(email.getAttachments().get(1).getName()).isEqualTo("attachment 1 as nested Outlook message (converted).sjm");
158+
assertThat(email.getAttachments().get(1).getName()).isEqualTo("This msg file is an attachment.eml");
161159

162-
final InputStream sjmInputstream = email.getAttachments().get(1).getDataSourceInputStream();
163-
Email nestedEmail = deserialize(sjmInputstream);
160+
final InputStream emlInputstream = email.getAttachments().get(1).getDataSourceInputStream();
161+
Email nestedEmail = EmailConverter.emlToEmail(emlInputstream);
164162

165163
EmailAssert.assertThat(nestedEmail).hasSubject("This msg file is an attachment");
166164
assertThat(normalizeNewlines(nestedEmail.getPlainText()))

0 commit comments

Comments
 (0)
0