1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.mail2.javax.util;
18
19 import java.io.IOException;
20 import java.io.UnsupportedEncodingException;
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.Collection;
24 import java.util.Collections;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28
29 import javax.activation.DataSource;
30 import javax.mail.Address;
31 import javax.mail.Message;
32 import javax.mail.MessagingException;
33 import javax.mail.Multipart;
34 import javax.mail.Part;
35 import javax.mail.internet.ContentType;
36 import javax.mail.internet.InternetAddress;
37 import javax.mail.internet.MimeBodyPart;
38 import javax.mail.internet.MimeMessage;
39 import javax.mail.internet.MimePart;
40 import javax.mail.internet.MimeUtility;
41 import javax.mail.internet.ParseException;
42
43 import org.apache.commons.mail2.javax.activation.InputStreamDataSource;
44
45
46
47
48
49
50 public class MimeMessageParser {
51
52
53 private final MimeMessage mimeMessage;
54
55
56 private String plainContent;
57
58
59 private String htmlContent;
60
61
62 private final List<DataSource> attachmentList;
63
64
65 private final Map<String, DataSource> cidMap;
66
67
68 private boolean isMultiPart;
69
70
71
72
73
74
75 public MimeMessageParser(final MimeMessage mimeMessage) {
76 this.attachmentList = new ArrayList<>();
77 this.cidMap = new HashMap<>();
78 this.mimeMessage = mimeMessage;
79 this.isMultiPart = false;
80 }
81
82 private List<Address> asList(final Address[] recipients) {
83 return recipients != null ? Arrays.asList(recipients) : new ArrayList<>();
84 }
85
86
87
88
89
90
91
92
93
94
95 @SuppressWarnings("resource")
96 protected DataSource createDataSource(final Multipart parent, final MimePart part) throws MessagingException, IOException {
97 final DataSource dataSource = part.getDataHandler().getDataSource();
98 final String contentType = getBaseMimeType(dataSource.getContentType());
99 final String dataSourceName = getDataSourceName(part, dataSource);
100 return new InputStreamDataSource(dataSource.getInputStream(), contentType, dataSourceName);
101 }
102
103
104
105
106
107
108
109
110
111
112
113 public DataSource findAttachmentByCid(final String cid) {
114 return cidMap.get(cid);
115 }
116
117
118
119
120
121
122
123 public DataSource findAttachmentByName(final String name) {
124 for (final DataSource dataSource : getAttachmentList()) {
125 if (name.equalsIgnoreCase(dataSource.getName())) {
126 return dataSource;
127 }
128 }
129 return null;
130 }
131
132
133
134
135
136
137 public List<DataSource> getAttachmentList() {
138 return attachmentList;
139 }
140
141
142
143
144
145
146
147 private String getBaseMimeType(final String fullMimeType) {
148 final int pos = fullMimeType.indexOf(';');
149 return pos < 0 ? fullMimeType : fullMimeType.substring(0, pos);
150 }
151
152
153
154
155
156
157
158 public List<Address> getBcc() throws MessagingException {
159 return asList(mimeMessage.getRecipients(Message.RecipientType.BCC));
160 }
161
162
163
164
165
166
167
168 public List<Address> getCc() throws MessagingException {
169 return asList(mimeMessage.getRecipients(Message.RecipientType.CC));
170 }
171
172
173
174
175
176
177
178
179
180
181 public Collection<String> getContentIds() {
182 return Collections.unmodifiableSet(cidMap.keySet());
183 }
184
185
186
187
188
189
190
191
192
193
194 protected String getDataSourceName(final Part part, final DataSource dataSource) throws MessagingException, UnsupportedEncodingException {
195 String result = dataSource.getName();
196 if (isEmpty(result)) {
197 result = part.getFileName();
198 }
199 if (!isEmpty(result)) {
200 result = MimeUtility.decodeText(result);
201 } else {
202 result = null;
203 }
204 return result;
205 }
206
207
208
209
210
211
212
213 public String getFrom() throws MessagingException {
214 final Address[] addresses = mimeMessage.getFrom();
215 if (isEmpty(addresses)) {
216 return null;
217 }
218 return ((InternetAddress) addresses[0]).getAddress();
219 }
220
221
222
223
224
225
226 public String getHtmlContent() {
227 return htmlContent;
228 }
229
230
231
232
233
234
235 public MimeMessage getMimeMessage() {
236 return mimeMessage;
237 }
238
239
240
241
242
243
244 public String getPlainContent() {
245 return plainContent;
246 }
247
248
249
250
251
252
253
254 public String getReplyTo() throws MessagingException {
255 final Address[] addresses = mimeMessage.getReplyTo();
256 if (isEmpty(addresses)) {
257 return null;
258 }
259 return ((InternetAddress) addresses[0]).getAddress();
260 }
261
262
263
264
265
266
267
268 public String getSubject() throws MessagingException {
269 return mimeMessage.getSubject();
270 }
271
272
273
274
275
276
277
278 public List<Address> getTo() throws MessagingException {
279 return asList(mimeMessage.getRecipients(Message.RecipientType.TO));
280 }
281
282
283
284
285
286
287 public boolean hasAttachments() {
288 return !attachmentList.isEmpty();
289 }
290
291
292
293
294
295
296 public boolean hasHtmlContent() {
297 return htmlContent != null;
298 }
299
300
301
302
303
304
305 public boolean hasPlainContent() {
306 return plainContent != null;
307 }
308
309 private boolean isEmpty(final Object[] array) {
310 return array == null || array.length == 0;
311 }
312
313 private boolean isEmpty(final String result) {
314 return result == null || result.isEmpty();
315 }
316
317
318
319
320
321
322
323
324
325 private boolean isMimeType(final MimePart part, final String mimeType) throws MessagingException {
326
327
328 try {
329 return new ContentType(part.getDataHandler().getContentType()).match(mimeType);
330 } catch (final ParseException ex) {
331 return part.getContentType().equalsIgnoreCase(mimeType);
332 }
333 }
334
335
336
337
338
339
340 public boolean isMultipart() {
341 return isMultiPart;
342 }
343
344
345
346
347
348
349
350
351 public MimeMessageParser parse() throws MessagingException, IOException {
352 parse(null, mimeMessage);
353 return this;
354 }
355
356
357
358
359
360
361
362
363
364 protected void parse(final Multipart parent, final MimePart part) throws MessagingException, IOException {
365 if (isMimeType(part, "text/plain") && plainContent == null && !Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition())) {
366 plainContent = (String) part.getContent();
367 } else if (isMimeType(part, "text/html") && htmlContent == null && !Part.ATTACHMENT.equalsIgnoreCase(part.getDisposition())) {
368 htmlContent = (String) part.getContent();
369 } else if (isMimeType(part, "multipart/*")) {
370 isMultiPart = true;
371 final Multipart multipart = (Multipart) part.getContent();
372 final int count = multipart.getCount();
373
374 for (int i = 0; i < count; i++) {
375 parse(multipart, (MimeBodyPart) multipart.getBodyPart(i));
376 }
377 } else {
378 final String cid = stripContentId(part.getContentID());
379 final DataSource dataSource = createDataSource(parent, part);
380 if (cid != null) {
381 cidMap.put(cid, dataSource);
382 }
383 attachmentList.add(dataSource);
384 }
385 }
386
387
388
389
390
391
392
393 private String stripContentId(final String contentId) {
394 return contentId == null ? null : contentId.trim().replaceAll("[\\<\\>]", "");
395 }
396 }