1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package fr.paris.lutece.portal.service.mail;
35
36 import fr.paris.lutece.portal.service.util.AppException;
37 import fr.paris.lutece.portal.service.util.AppLogService;
38 import fr.paris.lutece.portal.service.util.AppPropertiesService;
39 import fr.paris.lutece.util.mail.ByteArrayDataSource;
40 import fr.paris.lutece.util.mail.FileAttachment;
41 import fr.paris.lutece.util.mail.HtmlDocument;
42 import fr.paris.lutece.util.mail.UrlAttachment;
43
44 import org.apache.commons.lang.StringUtils;
45
46 import java.io.ByteArrayOutputStream;
47 import java.io.IOException;
48 import java.io.InputStream;
49 import java.io.UnsupportedEncodingException;
50
51 import java.util.ArrayList;
52 import java.util.Date;
53 import java.util.List;
54 import java.util.Properties;
55 import java.util.StringTokenizer;
56
57 import javax.activation.CommandInfo;
58 import javax.activation.DataHandler;
59 import javax.activation.MailcapCommandMap;
60 import javax.activation.MimetypesFileTypeMap;
61
62 import javax.mail.Authenticator;
63 import javax.mail.BodyPart;
64 import javax.mail.Message;
65 import javax.mail.MessagingException;
66 import javax.mail.NoSuchProviderException;
67 import javax.mail.PasswordAuthentication;
68 import javax.mail.SendFailedException;
69 import javax.mail.Session;
70 import javax.mail.Transport;
71 import javax.mail.internet.AddressException;
72 import javax.mail.internet.InternetAddress;
73 import javax.mail.internet.MimeBodyPart;
74 import javax.mail.internet.MimeMessage;
75 import javax.mail.internet.MimeMultipart;
76 import javax.mail.internet.MimeUtility;
77
78
79
80
81
82 final class MailUtil
83 {
84
85 private static final String PROPERTY_CHARSET = "mail.charset";
86 private static final String PROPERTY_MAIL_LIST_SEPARATOR = "mail.list.separator";
87 private static final String PROPERTY_MAIL_TYPE_HTML = "mail.type.html";
88 private static final String PROPERTY_MAIL_TYPE_PLAIN = "mail.type.plain";
89 private static final String PROPERTY_MAIL_TYPE_CALENDAR = "mail.type.calendar";
90 private static final String PROPERTY_MAIL_SESSION_DEBUG = "mail.session.debug";
91 private static final String PROPERTY_CALENDAR_SEPARATOR = "mail.type.calendar.separator";
92 private static final String PROPERTY_CALENDAR_METHOD_CREATE = "mail.type.calendar.create";
93 private static final String PROPERTY_CALENDAR_METHOD_CANCEL = "mail.type.calendar.cancel";
94
95
96 private static final String SMTP = "smtp";
97 private static final String MAIL_HOST = "mail.host";
98 private static final String MAIL_TRANSPORT_PROTOCOL = "mail.transport.protocol";
99 private static final String MAIL_SMTP_AUTH = "mail.smtp.auth";
100 private static final String MAIL_PROPTOCOL_HOST = "mail." + SMTP + ".host";
101 private static final String MAIL_PROPTOCOL_PORT = "mail." + SMTP + ".port";
102
103
104 private static final String TRUE = "true";
105 private static final String ENCODING = "Q";
106 private static final String HEADER_NAME = "Content-Transfer-Encoding";
107 private static final String HEADER_VALUE = "quoted-printable";
108 private static final String HEADER_CONTENT_LOCATION = "Content-Location";
109 private static final String CONTENT_HANDLER = "content-handler";
110 private static final String MULTIPART_RELATED = "related";
111 private static final String MSG_ATTACHMENT_NOT_FOUND = " not found, document ignored.";
112 private static final int CONSTANTE_FILE_ATTACHMET_BUFFER = 4096;
113 private static final String MIME_TYPE_TEXT_PLAIN = "text/plain";
114 private static final String MIME_TYPE_TEXT_CALENDAR = "text/calendar";
115 private static final String CONSTANT_REGISTER_MIME_TYPE_HANDLER = ";; x-java-content-handler=";
116 private static final String DEFAULT_PLAIN_TEXT_HANDLER = "com.sun.mail.handlers.text_plain";
117 private static final String CONSTANT_DISPOSITION_ATTACHMENT = "attachment";
118 private static final String CONSTANT_BASE64 = "base64";
119
120 static
121 {
122
123 MimetypesFileTypeMap mimetypes = (MimetypesFileTypeMap) MimetypesFileTypeMap.getDefaultFileTypeMap( );
124 mimetypes.addMimeTypes( MIME_TYPE_TEXT_CALENDAR );
125
126
127 MailcapCommandMap mailcap = (MailcapCommandMap) MailcapCommandMap.getDefaultCommandMap( );
128
129
130 CommandInfo[] commandInfos = mailcap.getAllCommands( MIME_TYPE_TEXT_PLAIN );
131 CommandInfo commandInfoText = null;
132
133 if ( ( commandInfos != null ) && ( commandInfos.length > 0 ) )
134 {
135 for ( CommandInfo commandInfo : commandInfos )
136 {
137 if ( StringUtils.equals( commandInfo.getCommandName( ), CONTENT_HANDLER ) )
138 {
139 commandInfoText = commandInfo;
140
141 break;
142 }
143 }
144
145 if ( commandInfoText == null )
146 {
147 commandInfoText = commandInfos[0];
148 }
149 }
150
151
152 String strHandler = ( commandInfoText != null ) ? commandInfoText.getCommandClass( ) : DEFAULT_PLAIN_TEXT_HANDLER;
153 mailcap.addMailcap( MIME_TYPE_TEXT_CALENDAR + CONSTANT_REGISTER_MIME_TYPE_HANDLER + strHandler + "\n" );
154 }
155
156
157
158
159 private MailUtil( )
160 {
161 }
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192 protected static void sendMessageText( String strRecipientsTo, String strRecipientsCc, String strRecipientsBcc,
193 String strSenderName, String strSenderEmail, String strSubject, String strMessage, Transport transport,
194 Session session ) throws MessagingException, AddressException, SendFailedException
195 {
196 Message msg = prepareMessage( strRecipientsTo, strRecipientsCc, strRecipientsBcc, strSenderName,
197 strSenderEmail, strSubject, session );
198 msg.setDataHandler( new DataHandler(
199 new ByteArrayDataSource( strMessage,
200 AppPropertiesService.getProperty( PROPERTY_MAIL_TYPE_PLAIN ) +
201 AppPropertiesService.getProperty( PROPERTY_CHARSET ) ) ) );
202
203 sendMessage( msg, transport );
204 }
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234 protected static void sendMessageHtml( String strRecipientsTo, String strRecipientsCc, String strRecipientsBcc,
235 String strSenderName, String strSenderEmail, String strSubject, String strMessage, Transport transport,
236 Session session ) throws MessagingException, AddressException, SendFailedException
237 {
238 Message msg = prepareMessage( strRecipientsTo, strRecipientsCc, strRecipientsBcc, strSenderName,
239 strSenderEmail, strSubject, session );
240
241 msg.setHeader( HEADER_NAME, HEADER_VALUE );
242
243 msg.setDataHandler( new DataHandler(
244 new ByteArrayDataSource( strMessage,
245 AppPropertiesService.getProperty( PROPERTY_MAIL_TYPE_HTML ) +
246 AppPropertiesService.getProperty( PROPERTY_CHARSET ) ) ) );
247
248 sendMessage( msg, transport );
249 }
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286 protected static void sendMultipartMessageHtml( String strRecipientsTo, String strRecipientsCc,
287 String strRecipientsBcc, String strSenderName, String strSenderEmail, String strSubject, String strMessage,
288 List<UrlAttachment> urlAttachements, List<FileAttachment> fileAttachements, Transport transport, Session session )
289 throws MessagingException, AddressException, SendFailedException
290 {
291 Message msg = prepareMessage( strRecipientsTo, strRecipientsCc, strRecipientsBcc, strSenderName,
292 strSenderEmail, strSubject, session );
293 msg.setHeader( HEADER_NAME, HEADER_VALUE );
294
295
296 MimeMultipart multipart = ( ( fileAttachements == null ) || ( fileAttachements.isEmpty( ) ) )
297 ? new MimeMultipart( MULTIPART_RELATED ) : new MimeMultipart( );
298
299
300 BodyPart msgBodyPart = new MimeBodyPart( );
301
302 msgBodyPart.setDataHandler( new DataHandler(
303 new ByteArrayDataSource( strMessage,
304 AppPropertiesService.getProperty( PROPERTY_MAIL_TYPE_HTML ) +
305 AppPropertiesService.getProperty( PROPERTY_CHARSET ) ) ) );
306 multipart.addBodyPart( msgBodyPart );
307
308 if ( urlAttachements != null )
309 {
310 ByteArrayDataSource urlByteArrayDataSource;
311
312 for ( UrlAttachment urlAttachement : urlAttachements )
313 {
314 urlByteArrayDataSource = convertUrlAttachmentDataSourceToByteArrayDataSource( urlAttachement );
315
316 if ( urlByteArrayDataSource != null )
317 {
318 msgBodyPart = new MimeBodyPart( );
319
320
321 msgBodyPart.setDataHandler( new DataHandler( urlByteArrayDataSource ) );
322 msgBodyPart.setHeader( HEADER_CONTENT_LOCATION, urlAttachement.getContentLocation( ) );
323 multipart.addBodyPart( msgBodyPart );
324 }
325 }
326 }
327
328
329 if ( fileAttachements != null )
330 {
331 for ( FileAttachment fileAttachement : fileAttachements )
332 {
333 String strFileName = fileAttachement.getFileName( );
334 byte[] bContentFile = fileAttachement.getData( );
335 String strContentType = fileAttachement.getType( );
336 ByteArrayDataSource dataSource = new ByteArrayDataSource( bContentFile, strContentType );
337 msgBodyPart = new MimeBodyPart( );
338 msgBodyPart.setDataHandler( new DataHandler( dataSource ) );
339 msgBodyPart.setFileName( strFileName );
340 msgBodyPart.setDisposition( CONSTANT_DISPOSITION_ATTACHMENT );
341 multipart.addBodyPart( msgBodyPart );
342 }
343 }
344
345 msg.setContent( multipart );
346
347 sendMessage( msg, transport );
348 }
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382 protected static void sendMultipartMessageText( String strRecipientsTo, String strRecipientsCc,
383 String strRecipientsBcc, String strSenderName, String strSenderEmail, String strSubject, String strMessage,
384 List<FileAttachment> fileAttachements, Transport transport, Session session )
385 throws MessagingException, AddressException, SendFailedException
386 {
387 Message msg = prepareMessage( strRecipientsTo, strRecipientsCc, strRecipientsBcc, strSenderName,
388 strSenderEmail, strSubject, session );
389 msg.setHeader( HEADER_NAME, HEADER_VALUE );
390
391
392 MimeMultipart multipart = new MimeMultipart( );
393
394
395 BodyPart msgBodyPart = new MimeBodyPart( );
396
397 msgBodyPart.setDataHandler( new DataHandler(
398 new ByteArrayDataSource( strMessage,
399 AppPropertiesService.getProperty( PROPERTY_MAIL_TYPE_PLAIN ) +
400 AppPropertiesService.getProperty( PROPERTY_CHARSET ) ) ) );
401 multipart.addBodyPart( msgBodyPart );
402
403
404 if ( fileAttachements != null )
405 {
406 for ( FileAttachment fileAttachement : fileAttachements )
407 {
408 String strFileName = fileAttachement.getFileName( );
409 byte[] bContentFile = fileAttachement.getData( );
410 String strContentType = fileAttachement.getType( );
411 ByteArrayDataSource dataSource = new ByteArrayDataSource( bContentFile, strContentType );
412 msgBodyPart = new MimeBodyPart( );
413 msgBodyPart.setDataHandler( new DataHandler( dataSource ) );
414 msgBodyPart.setFileName( strFileName );
415 msgBodyPart.setDisposition( CONSTANT_DISPOSITION_ATTACHMENT );
416 multipart.addBodyPart( msgBodyPart );
417 }
418 }
419
420 msg.setContent( multipart );
421
422 sendMessage( msg, transport );
423 }
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444 protected static void sendMessageCalendar( String strRecipientsTo, String strRecipientsCc, String strRecipientsBcc,
445 String strSenderName, String strSenderEmail, String strSubject, String strMessage, String strCalendarMessage,
446 boolean bCreateEvent, Transport transport, Session session )
447 throws MessagingException, AddressException, SendFailedException
448 {
449 Message msg = prepareMessage( strRecipientsTo, strRecipientsCc, strRecipientsBcc, strSenderName,
450 strSenderEmail, strSubject, session );
451 msg.setHeader( HEADER_NAME, HEADER_VALUE );
452
453 MimeMultipart multipart = new MimeMultipart( );
454 BodyPart msgBodyPart = new MimeBodyPart( );
455 msgBodyPart.setDataHandler( new DataHandler(
456 new ByteArrayDataSource( strMessage,
457 AppPropertiesService.getProperty( PROPERTY_MAIL_TYPE_HTML ) +
458 AppPropertiesService.getProperty( PROPERTY_CHARSET ) ) ) );
459
460 multipart.addBodyPart( msgBodyPart );
461
462 BodyPart calendarBodyPart = new MimeBodyPart( );
463
464 calendarBodyPart.setContent( strCalendarMessage,
465 AppPropertiesService.getProperty( PROPERTY_MAIL_TYPE_CALENDAR ) +
466 AppPropertiesService.getProperty( PROPERTY_CHARSET ) +
467 AppPropertiesService.getProperty( PROPERTY_CALENDAR_SEPARATOR ) +
468 AppPropertiesService.getProperty( bCreateEvent ? PROPERTY_CALENDAR_METHOD_CREATE
469 : PROPERTY_CALENDAR_METHOD_CANCEL ) );
470 calendarBodyPart.addHeader( HEADER_NAME, CONSTANT_BASE64 );
471 multipart.addBodyPart( calendarBodyPart );
472
473 msg.setContent( multipart );
474
475 sendMessage( msg, transport );
476 }
477
478
479
480
481
482
483
484
485
486
487
488
489
490 private static void sendMessage( Message msg, Transport transport )
491 throws MessagingException, AddressException
492 {
493 if ( msg.getAllRecipients( ) != null )
494 {
495
496 transport.sendMessage( msg, msg.getAllRecipients( ) );
497 }
498 else
499 {
500 throw new AddressException( "Mail adress is null" );
501 }
502 }
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517 protected static List<UrlAttachment> getUrlAttachmentList( String strHtml, String strBaseUrl, boolean useAbsoluteUrl )
518 {
519 List<UrlAttachment> listUrlAttachement = new ArrayList<UrlAttachment>( );
520 HtmlDocument doc = new HtmlDocument( strHtml, strBaseUrl, useAbsoluteUrl );
521 listUrlAttachement.addAll( doc.getAllUrlsAttachement( HtmlDocument.ELEMENT_IMG ) );
522 listUrlAttachement.addAll( doc.getAllUrlsAttachement( HtmlDocument.ELEMENT_CSS ) );
523 listUrlAttachement.addAll( doc.getAllUrlsAttachement( HtmlDocument.ELEMENT_JAVASCRIPT ) );
524
525 return listUrlAttachement;
526 }
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552 protected static Message prepareMessage( String strRecipientsTo, String strRecipientsCc, String strRecipientsBcc,
553 String strSenderName, String strSenderEmail, String strSubject, Session session )
554 throws MessagingException, AddressException
555 {
556
557 Message msg = new MimeMessage( session );
558 msg.setSentDate( new Date( ) );
559
560 try
561 {
562 msg.setFrom( new InternetAddress( strSenderEmail, strSenderName,
563 AppPropertiesService.getProperty( PROPERTY_CHARSET ) ) );
564 msg.setSubject( MimeUtility.encodeText( strSubject, AppPropertiesService.getProperty( PROPERTY_CHARSET ),
565 ENCODING ) );
566 }
567 catch ( UnsupportedEncodingException e )
568 {
569 throw new AppException( e.toString( ) );
570 }
571
572
573 if ( strRecipientsTo != null )
574 {
575 msg.setRecipients( Message.RecipientType.TO, getAllAdressOfRecipients( strRecipientsTo ) );
576 }
577
578 if ( strRecipientsCc != null )
579 {
580 msg.setRecipients( Message.RecipientType.CC, getAllAdressOfRecipients( strRecipientsCc ) );
581 }
582
583 if ( strRecipientsBcc != null )
584 {
585 msg.setRecipients( Message.RecipientType.BCC, getAllAdressOfRecipients( strRecipientsBcc ) );
586 }
587
588 return msg;
589 }
590
591
592
593
594
595
596
597
598
599
600
601 protected static Session getMailSession( String strHost, int nPort, final String strUsername,
602 final String strPassword )
603 {
604 String strDebug = AppPropertiesService.getProperty( PROPERTY_MAIL_SESSION_DEBUG, Boolean.FALSE.toString( ) );
605 boolean bSessionDebug = Boolean.parseBoolean( strDebug );
606
607
608 Properties props = System.getProperties( );
609 props.put( MAIL_HOST, strHost );
610 props.put( MAIL_TRANSPORT_PROTOCOL, SMTP );
611 props.put( MAIL_PROPTOCOL_HOST, strHost );
612 props.put( MAIL_PROPTOCOL_PORT, nPort );
613
614 Authenticator auth;
615
616 if ( StringUtils.isNotBlank( strUsername ) )
617 {
618 props.put( MAIL_SMTP_AUTH, TRUE );
619
620 auth = new Authenticator( )
621 {
622 @Override
623 protected PasswordAuthentication getPasswordAuthentication( )
624 {
625 return new PasswordAuthentication( strUsername, strPassword );
626 }
627 };
628 }
629 else
630 {
631
632 auth = null;
633 }
634
635 Session mailSession = Session.getDefaultInstance( props, auth );
636
637 mailSession.setDebug( bSessionDebug );
638
639 return mailSession;
640 }
641
642
643
644
645
646
647
648
649 protected static Transport getTransport( Session session )
650 throws NoSuchProviderException
651 {
652 return session.getTransport( SMTP );
653 }
654
655
656
657
658
659
660
661
662
663
664
665 private static InternetAddress[] getAllAdressOfRecipients( String strRecipients )
666 throws AddressException
667 {
668 List<String> listRecipients = getAllStringAdressOfRecipients( strRecipients );
669 InternetAddress[] address = new InternetAddress[listRecipients.size( )];
670
671
672 for ( int i = 0; i < listRecipients.size( ); i++ )
673 {
674 address[i] = new InternetAddress( listRecipients.get( i ) );
675 }
676
677 return address;
678 }
679
680
681
682
683
684
685
686
687 public static List<String> getAllStringAdressOfRecipients( String strRecipients )
688 {
689 StringTokenizer st = new StringTokenizer( strRecipients,
690 AppPropertiesService.getProperty( PROPERTY_MAIL_LIST_SEPARATOR, ";" ) );
691 List<String> listRecipients = new ArrayList<String>( );
692
693 while ( st.hasMoreTokens( ) )
694 {
695 listRecipients.add( st.nextToken( ) );
696 }
697
698 return listRecipients;
699 }
700
701
702
703
704
705
706
707
708 protected static String getStrRecipients( List<String> listRecipients )
709 {
710 String strMailListSeparator = AppPropertiesService.getProperty( PROPERTY_MAIL_LIST_SEPARATOR, ";" );
711 StringBuilder strRecipients = new StringBuilder( );
712 int ncpt = 0;
713
714 if ( listRecipients != null )
715 {
716 for ( String strRecipient : listRecipients )
717 {
718 strRecipients.append( strRecipient );
719
720 if ( ++ncpt < listRecipients.size( ) )
721 {
722 strRecipients.append( strMailListSeparator );
723 }
724 }
725 }
726
727 return strRecipients.toString( );
728 }
729
730
731
732
733
734
735
736 private static ByteArrayDataSource convertUrlAttachmentDataSourceToByteArrayDataSource(
737 UrlAttachment urlAttachement )
738 {
739 String strKey = MailAttachmentCacheService.getInstance( ).getKey( urlAttachement.getUrlData( ).toString( ) );
740 ByteArrayDataSource urlAttachmentDataSource = null;
741
742 if ( !MailAttachmentCacheService.getInstance( ).isCacheEnable( ) ||
743 ( MailAttachmentCacheService.getInstance( ).getFromCache( strKey ) == null ) )
744 {
745 DataHandler handler = new DataHandler( urlAttachement.getUrlData( ) );
746 ByteArrayOutputStream bo = null;
747 InputStream input = null;
748 String strType = null;
749
750 try
751 {
752 Object o = handler.getContent( );
753 strType = handler.getContentType( );
754
755 if ( o != null )
756 {
757 if ( o instanceof InputStream )
758 {
759 input = (InputStream) o;
760 bo = new ByteArrayOutputStream( );
761
762 int read;
763 byte[] tab = new byte[CONSTANTE_FILE_ATTACHMET_BUFFER];
764
765 do
766 {
767 read = input.read( tab );
768
769 if ( read > 0 )
770 {
771 bo.write( tab, 0, read );
772 }
773 }
774 while ( read > 0 );
775 }
776 }
777 }
778 catch ( IOException e )
779 {
780
781 AppLogService.info( urlAttachement.getContentLocation( ) + MSG_ATTACHMENT_NOT_FOUND );
782 }
783 finally
784 {
785
786 try
787 {
788 if ( input != null )
789 {
790 input.close( );
791 }
792
793 if ( bo != null )
794 {
795 bo.close( );
796 urlAttachmentDataSource = new ByteArrayDataSource( bo.toByteArray( ), strType );
797 }
798 }
799 catch ( IOException e )
800 {
801 AppLogService.error( e );
802 }
803 }
804
805 if ( MailAttachmentCacheService.getInstance( ).isCacheEnable( ) )
806 {
807
808 MailAttachmentCacheService.getInstance( ).putInCache( strKey, urlAttachmentDataSource );
809 }
810 }
811 else
812 {
813
814 urlAttachmentDataSource = (ByteArrayDataSource) MailAttachmentCacheService.getInstance( )
815 .getFromCache( strKey );
816 }
817
818 return urlAttachmentDataSource;
819 }
820 }