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