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