Skip to content

Commit 3a45258

Browse files
committed
- Implemented to EML string conversion (#66)
- Restructured code to avoid circular package tangles and to accomodate more conversion options
1 parent 04f0f9d commit 3a45258

File tree

16 files changed

+204
-144
lines changed

16 files changed

+204
-144
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package org.simplejavamail.converter;
2+
3+
import org.simplejavamail.converter.internal.MimeMessageHelper;
4+
import org.simplejavamail.converter.internal.MimeMessageParser;
5+
import org.simplejavamail.email.Email;
6+
7+
import javax.activation.DataSource;
8+
import javax.mail.Message;
9+
import javax.mail.MessagingException;
10+
import javax.mail.Session;
11+
import javax.mail.internet.InternetAddress;
12+
import javax.mail.internet.MimeMessage;
13+
import java.io.ByteArrayOutputStream;
14+
import java.io.IOException;
15+
import java.io.UnsupportedEncodingException;
16+
import java.util.Map;
17+
import java.util.Properties;
18+
19+
import static java.lang.String.format;
20+
import static java.nio.charset.StandardCharsets.UTF_8;
21+
import static org.simplejavamail.converter.internal.MimeMessageHelper.produceMimeMessage;
22+
import static org.simplejavamail.internal.util.MiscUtil.extractCID;
23+
24+
/**
25+
* Utility to help convert {@link org.simplejavamail.email.Email} instances to other formats (MimeMessage, EML etc.) and vice versa.
26+
*/
27+
@SuppressWarnings("WeakerAccess")
28+
public class FormatConverter {
29+
30+
/**
31+
* @param mimeMessage The MimeMessage from which to create the email.
32+
*/
33+
public static Email mimeMessageToEmail(final MimeMessage mimeMessage) {
34+
Email email = new Email(false);
35+
try {
36+
fillEmailFromMimeMessage(email, new MimeMessageParser(mimeMessage).parse());
37+
} catch (MessagingException | IOException e) {
38+
throw new FormatConverterException(format(FormatConverterException.PARSE_ERROR_MIMEMESSAGE, e.getMessage()), e);
39+
}
40+
return email;
41+
}
42+
43+
private static void fillEmailFromMimeMessage(final Email email, final MimeMessageParser parser)
44+
throws MessagingException {
45+
final InternetAddress from = parser.getFrom();
46+
email.setFromAddress(from.getPersonal(), from.getAddress());
47+
final InternetAddress replyTo = parser.getReplyTo();
48+
email.setReplyToAddress(replyTo.getPersonal(), replyTo.getAddress());
49+
for (final Map.Entry<String, Object> header : parser.getHeaders().entrySet()) {
50+
email.addHeader(header.getKey(), header.getValue());
51+
}
52+
for (final InternetAddress to : parser.getTo()) {
53+
email.addRecipient(to.getPersonal(), to.getAddress(), Message.RecipientType.TO);
54+
}
55+
//noinspection QuestionableName
56+
for (final InternetAddress cc : parser.getCc()) {
57+
email.addRecipient(cc.getPersonal(), cc.getAddress(), Message.RecipientType.CC);
58+
}
59+
for (final InternetAddress bcc : parser.getBcc()) {
60+
email.addRecipient(bcc.getPersonal(), bcc.getAddress(), Message.RecipientType.BCC);
61+
}
62+
email.setSubject(parser.getSubject());
63+
email.setText(parser.getPlainContent());
64+
email.setTextHTML(parser.getHtmlContent());
65+
for (final Map.Entry<String, DataSource> cid : parser.getCidMap().entrySet()) {
66+
email.addEmbeddedImage(extractCID(cid.getKey()), cid.getValue());
67+
}
68+
for (final Map.Entry<String, DataSource> attachment : parser.getAttachmentList().entrySet()) {
69+
email.addAttachment(extractCID(attachment.getKey()), attachment.getValue());
70+
}
71+
}
72+
73+
/**
74+
* Delegates to {@link #emailToMimeMessage(Email, Session)}, using a new empty {@link Session} instance.
75+
*
76+
* @see #emailToMimeMessage(Email, Session)
77+
*/
78+
public static MimeMessage emailToMimeMessage(final Email email) {
79+
return emailToMimeMessage(email, Session.getDefaultInstance(new Properties()));
80+
}
81+
82+
/**
83+
* Refer to {@link MimeMessageHelper#produceMimeMessage(Email, Session)}
84+
*/
85+
public static MimeMessage emailToMimeMessage(final Email email, final Session session) {
86+
try {
87+
return produceMimeMessage(email, session);
88+
} catch (UnsupportedEncodingException | MessagingException e) {
89+
// this should never happen, so we don't acknowledge this exception (and simply bubble up)
90+
throw new RuntimeException(e.getMessage(), e);
91+
}
92+
}
93+
94+
public static String readMimeMessageToEMLString(MimeMessage message) {
95+
ByteArrayOutputStream os = new ByteArrayOutputStream();
96+
try {
97+
message.writeTo(os);
98+
return os.toString(UTF_8.name());
99+
} catch (IOException | MessagingException e) {
100+
// this should never happen, so we don't acknowledge this exception (and simply bubble up)
101+
throw new RuntimeException(e.getMessage(), e);
102+
}
103+
}
104+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package org.simplejavamail.converter;
2+
3+
import org.simplejavamail.MailException;
4+
5+
/**
6+
* This exception is used to communicate errors during the creation of an email.
7+
*
8+
* @author Benny Bottema
9+
*/
10+
@SuppressWarnings("serial")
11+
class FormatConverterException extends MailException {
12+
13+
static final String PARSE_ERROR_MIMEMESSAGE = "Error parsing MimeMessage: %s";
14+
15+
public FormatConverterException(final String message, final Exception cause) {
16+
super(message, cause);
17+
}
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package org.simplejavamail.converter.internal;
2+
3+
import org.simplejavamail.MailException;
4+
5+
/**
6+
* This exception is used to communicate errors during the sending of email.
7+
*
8+
* @author Benny Bottema
9+
*/
10+
@SuppressWarnings("serial")
11+
class MimeMessageException extends MailException {
12+
13+
static final String INVALID_DOMAINKEY = "Error signing MimeMessage with DKIM";
14+
15+
MimeMessageException(final String message, final Exception cause) {
16+
super(message, cause);
17+
}
18+
}

src/main/java/org/simplejavamail/mailer/internal/mailsender/MimeMessageHelper.java renamed to src/main/java/org/simplejavamail/converter/internal/MimeMessageHelper.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package org.simplejavamail.mailer.internal.mailsender;
1+
package org.simplejavamail.converter.internal;
22

33
import net.markenwerk.utils.mail.dkim.Canonicalization;
44
import net.markenwerk.utils.mail.dkim.DkimMessage;
@@ -274,7 +274,7 @@ public static MimeMessage signMessageWithDKIM(final MimeMessage message, final E
274274
dkimSigner.setZParam(false);
275275
return new DkimMessage(message, dkimSigner);
276276
} catch (IOException | NoSuchAlgorithmException | InvalidKeySpecException | MessagingException e) {
277-
throw new MailSenderException(MailSenderException.INVALID_DOMAINKEY, e);
277+
throw new MimeMessageException(MimeMessageException.INVALID_DOMAINKEY, e);
278278
}
279279
}
280280

@@ -318,7 +318,7 @@ private static class MimeEmailMessageWrapper {
318318
multipartRelated.addBodyPart(contentAlternativeMessages);
319319
contentAlternativeMessages.setContent(multipartAlternativeMessages);
320320
} catch (final MessagingException e) {
321-
throw new MailSenderException(e.getMessage(), e);
321+
throw new MimeMessageException(e.getMessage(), e);
322322
}
323323
}
324324

src/main/java/org/simplejavamail/internal/util/MimeMessageParser.java renamed to src/main/java/org/simplejavamail/converter/internal/MimeMessageParser.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* See the License for the specific language governing permissions and
1616
* limitations under the License.
1717
*/
18-
package org.simplejavamail.internal.util;
18+
package org.simplejavamail.converter.internal;
1919

2020
import javax.activation.DataHandler;
2121
import javax.activation.DataSource;

src/main/java/org/simplejavamail/mailer/internal/mailsender/NamedDataSource.java renamed to src/main/java/org/simplejavamail/converter/internal/NamedDataSource.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package org.simplejavamail.mailer.internal.mailsender;
1+
package org.simplejavamail.converter.internal;
22

33
import javax.activation.DataSource;
44
import java.io.IOException;

src/main/java/org/simplejavamail/email/Email.java

+23-86
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,14 @@
11
package org.simplejavamail.email;
22

3-
import org.simplejavamail.internal.util.MimeMessageParser;
43
import org.simplejavamail.internal.util.MiscUtil;
54

65
import javax.activation.DataSource;
76
import javax.mail.Message.RecipientType;
8-
import javax.mail.MessagingException;
9-
import javax.mail.internet.InternetAddress;
10-
import javax.mail.internet.MimeMessage;
117
import javax.mail.util.ByteArrayDataSource;
128
import java.io.File;
13-
import java.io.IOException;
149
import java.io.InputStream;
1510
import java.util.*;
16-
import java.util.regex.Pattern;
1711

18-
import static java.lang.String.format;
1912
import static org.simplejavamail.util.ConfigLoader.Property.*;
2013
import static org.simplejavamail.util.ConfigLoader.getProperty;
2114
import static org.simplejavamail.util.ConfigLoader.hasProperty;
@@ -84,28 +77,34 @@ public class Email {
8477
* Constructor, creates all internal lists. Populates default from, reply-to, to, cc and bcc if provided in the config file.
8578
*/
8679
public Email() {
80+
this(true);
81+
}
82+
83+
public Email(boolean readFromDefaults) {
8784
recipients = new ArrayList<>();
8885
embeddedImages = new ArrayList<>();
8986
attachments = new ArrayList<>();
9087
headers = new HashMap<>();
9188

92-
if (hasProperty(DEFAULT_FROM_ADDRESS)) {
93-
setFromAddress((String) getProperty(DEFAULT_FROM_NAME), (String) getProperty(DEFAULT_FROM_ADDRESS));
94-
}
95-
if (hasProperty(DEFAULT_REPLYTO_ADDRESS)) {
96-
setReplyToAddress((String) getProperty(DEFAULT_REPLYTO_NAME), (String) getProperty(DEFAULT_REPLYTO_ADDRESS));
97-
}
98-
if (hasProperty(DEFAULT_TO_ADDRESS)) {
99-
addRecipient((String) getProperty(DEFAULT_TO_NAME), (String) getProperty(DEFAULT_TO_ADDRESS), RecipientType.TO);
100-
}
101-
if (hasProperty(DEFAULT_CC_ADDRESS)) {
102-
addRecipient((String) getProperty(DEFAULT_CC_NAME), (String) getProperty(DEFAULT_CC_ADDRESS), RecipientType.CC);
103-
}
104-
if (hasProperty(DEFAULT_BCC_ADDRESS)) {
105-
addRecipient((String) getProperty(DEFAULT_BCC_NAME), (String) getProperty(DEFAULT_BCC_ADDRESS), RecipientType.BCC);
106-
}
107-
if (hasProperty(DEFAULT_SUBJECT)) {
108-
setSubject((String) getProperty(DEFAULT_SUBJECT));
89+
if (readFromDefaults) {
90+
if (hasProperty(DEFAULT_FROM_ADDRESS)) {
91+
setFromAddress((String) getProperty(DEFAULT_FROM_NAME), (String) getProperty(DEFAULT_FROM_ADDRESS));
92+
}
93+
if (hasProperty(DEFAULT_REPLYTO_ADDRESS)) {
94+
setReplyToAddress((String) getProperty(DEFAULT_REPLYTO_NAME), (String) getProperty(DEFAULT_REPLYTO_ADDRESS));
95+
}
96+
if (hasProperty(DEFAULT_TO_ADDRESS)) {
97+
addRecipient((String) getProperty(DEFAULT_TO_NAME), (String) getProperty(DEFAULT_TO_ADDRESS), RecipientType.TO);
98+
}
99+
if (hasProperty(DEFAULT_CC_ADDRESS)) {
100+
addRecipient((String) getProperty(DEFAULT_CC_NAME), (String) getProperty(DEFAULT_CC_ADDRESS), RecipientType.CC);
101+
}
102+
if (hasProperty(DEFAULT_BCC_ADDRESS)) {
103+
addRecipient((String) getProperty(DEFAULT_BCC_NAME), (String) getProperty(DEFAULT_BCC_ADDRESS), RecipientType.BCC);
104+
}
105+
if (hasProperty(DEFAULT_SUBJECT)) {
106+
setSubject((String) getProperty(DEFAULT_SUBJECT));
107+
}
109108
}
110109
}
111110

@@ -395,66 +394,4 @@ public String toString() {
395394
signWithDomainKey(builder.getDkimPrivateKeyInputStream(), builder.getSigningDomain(), builder.getSelector());
396395
}
397396
}
398-
399-
/*
400-
* Email from MimeMessage
401-
*
402-
* @author Benny Bottema
403-
*/
404-
405-
/**
406-
* Constructor for {@link javax.mail.internet.MimeMessage}.
407-
* <p>
408-
* <strong>Doen add default recipient that may have been provided in a config file.</strong>
409-
*
410-
* @param mimeMessage The MimeMessage from which to create the email.
411-
*/
412-
public Email(final MimeMessage mimeMessage) {
413-
recipients = new ArrayList<>();
414-
embeddedImages = new ArrayList<>();
415-
attachments = new ArrayList<>();
416-
headers = new HashMap<>();
417-
418-
try {
419-
fillEmailFromMimeMessage(new MimeMessageParser(mimeMessage).parse());
420-
} catch (MessagingException | IOException e) {
421-
throw new EmailException(format(EmailException.PARSE_ERROR_MIMEMESSAGE, e.getMessage()), e);
422-
}
423-
}
424-
425-
private void fillEmailFromMimeMessage(final MimeMessageParser parser)
426-
throws MessagingException {
427-
final InternetAddress from = parser.getFrom();
428-
this.setFromAddress(from.getPersonal(), from.getAddress());
429-
final InternetAddress replyTo = parser.getReplyTo();
430-
this.setReplyToAddress(replyTo.getPersonal(), replyTo.getAddress());
431-
for (final Map.Entry<String, Object> header : parser.getHeaders().entrySet()) {
432-
this.addHeader(header.getKey(), header.getValue());
433-
}
434-
for (final InternetAddress to : parser.getTo()) {
435-
this.addRecipient(to.getPersonal(), to.getAddress(), RecipientType.TO);
436-
}
437-
//noinspection QuestionableName
438-
for (final InternetAddress cc : parser.getCc()) {
439-
this.addRecipient(cc.getPersonal(), cc.getAddress(), RecipientType.CC);
440-
}
441-
for (final InternetAddress bcc : parser.getBcc()) {
442-
this.addRecipient(bcc.getPersonal(), bcc.getAddress(), RecipientType.BCC);
443-
}
444-
this.setSubject(parser.getSubject());
445-
this.setText(parser.getPlainContent());
446-
this.setTextHTML(parser.getHtmlContent());
447-
for (final Map.Entry<String, DataSource> cid : parser.getCidMap().entrySet()) {
448-
this.addEmbeddedImage(extractCID(cid.getKey()), cid.getValue());
449-
}
450-
for (final Map.Entry<String, DataSource> attachment : parser.getAttachmentList().entrySet()) {
451-
this.addAttachment(extractCID(attachment.getKey()), attachment.getValue());
452-
}
453-
}
454-
455-
private static final Pattern MATCH_INSIDE_CIDBRACKETS = Pattern.compile("<?([^>]*)>?");
456-
457-
static String extractCID(final String cid) {
458-
return (cid != null) ? MATCH_INSIDE_CIDBRACKETS.matcher(cid).replaceAll("$1") : null;
459-
}
460397
}

src/main/java/org/simplejavamail/internal/util/MiscUtil.java

+7
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22

33
import javax.mail.internet.MimeUtility;
44
import java.io.UnsupportedEncodingException;
5+
import java.util.regex.Pattern;
56

67
import static java.lang.Integer.toHexString;
78

89
public final class MiscUtil {
910

11+
private static final Pattern MATCH_INSIDE_CIDBRACKETS = Pattern.compile("<?([^>]*)>?");
12+
1013
public static <T> T checkNotNull(final T value, final String msg) {
1114
if (value == null) {
1215
throw new NullPointerException(msg);
@@ -49,4 +52,8 @@ public static String encodeText(String name) {
4952
throw new IllegalArgumentException(e.getMessage(), e);
5053
}
5154
}
55+
56+
public static String extractCID(final String cid) {
57+
return (cid != null) ? MATCH_INSIDE_CIDBRACKETS.matcher(cid).replaceAll("$1") : null;
58+
}
5259
}

0 commit comments

Comments
 (0)