View Javadoc
1   /*
2    * Copyright (c) 2002-2022, City of Paris
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    *
9    *  1. Redistributions of source code must retain the above copyright notice
10   *     and the following disclaimer.
11   *
12   *  2. Redistributions in binary form must reproduce the above copyright notice
13   *     and the following disclaimer in the documentation and/or other materials
14   *     provided with the distribution.
15   *
16   *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
17   *     contributors may be used to endorse or promote products derived from
18   *     this software without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   * POSSIBILITY OF SUCH DAMAGE.
31   *
32   * License 1.0
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   * This class provides mail utils.
81   */
82  final class MailUtil
83  {
84      // Properties
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      // Javax.mail properties
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     // Constants
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         // We create the mime text/calendar mime type
124         MimetypesFileTypeMap mimetypes = (MimetypesFileTypeMap) FileTypeMap.getDefaultFileTypeMap( );
125         mimetypes.addMimeTypes( MIME_TYPE_TEXT_CALENDAR );
126 
127         // We register the handler for the text/calendar mime type
128         MailcapCommandMap mailcap = (MailcapCommandMap) CommandMap.getDefaultCommandMap( );
129 
130         // We try to get the default handler for plain text
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         // If the default handler for plain text was not found, we just use the default
153         // one
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      * Creates a new MailUtil object
160      */
161     private MailUtil( )
162     {
163     }
164 
165     /**
166      * Send a text message.
167      *
168      * @param mail
169      *            The mail to send
170      * @param transport
171      *            the smtp transport object
172      * @param session
173      *            the smtp session object
174      * @throws AddressException
175      *             If invalid address
176      * @throws SendFailedException
177      *             If an error occured during sending
178      * @throws MessagingException
179      *             If a messaging error occured
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      * Send a HTML formated message.
192      * 
193      * @param mail
194      *            The mail to send
195      * @param transport
196      *            the smtp transport object
197      * @param session
198      *            the smtp session object
199      * @throws AddressException
200      *             If invalid address
201      * @throws SendFailedException
202      *             If an error occured during sending
203      * @throws MessagingException
204      *             If a messaging error occured
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         // Message body formated in HTML
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      * Send a Multipart HTML message with the attachements associated to the message and attached files.
220      *
221      * @param mail
222      *            The mail to send
223      * @param transport
224      *            the smtp transport object
225      * @param session
226      *            the smtp session object
227      * @throws AddressException
228      *             If invalid address
229      * @throws SendFailedException
230      *             If an error occured during sending
231      * @throws MessagingException
232      *             If a messaging error occurred
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         // Creation of the root part containing all the elements of the message
240         MimeMultipart multipart = CollectionUtils.isEmpty( mail.getFilesAttachement( ) ) ? new MimeMultipart( MULTIPART_RELATED ) : new MimeMultipart( );
241 
242         // Creation of the html part, the "core" of the message
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                     // Fill this part, then add it to the root part with the
260                     // good headers
261                     msgBodyPart.setDataHandler( new DataHandler( urlByteArrayDataSource ) );
262                     msgBodyPart.setHeader( HEADER_CONTENT_LOCATION, urlAttachement.getContentLocation( ) );
263                     multipart.addBodyPart( msgBodyPart );
264                 }
265             }
266         }
267 
268         // add File Attachement
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      * Send a Multipart text message with attached files.
292      *
293      * @param mail
294      *            The mail to send
295      * @param transport
296      *            the smtp transport object
297      * @param session
298      *            the smtp session object
299      * @throws AddressException
300      *             If invalid address
301      * @throws SendFailedException
302      *             If an error occured during sending
303      * @throws MessagingException
304      *             If a messaging error occured
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         // Creation of the root part containing all the elements of the message
312         MimeMultipart multipart = new MimeMultipart( );
313 
314         // Creation of the html part, the "core" of the message
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         // add File Attachement
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      * Send a calendar message.
344      * 
345      * @param mail
346      *            The mail to send
347      * @param transport
348      *            the smtp transport object
349      * @param session
350      *            the smtp session object
351      * @throws AddressException
352      *             If invalid address
353      * @throws SendFailedException
354      *             If an error occurred during sending
355      * @throws MessagingException
356      *             If a messaging error occurred
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      * Send the message
385      *
386      * @param msg
387      *            the message to send
388      * @param transport
389      *            the transport used to send the message
390      * @throws MessagingException
391      *             If a messaging error occured
392      * @throws AddressException
393      *             If invalid address
394      */
395     private static void sendMessage( Message msg, Transport transport ) throws MessagingException
396     {
397         if ( msg.getAllRecipients( ) != null )
398         {
399             // Send the message
400             transport.sendMessage( msg, msg.getAllRecipients( ) );
401         }
402         else
403         {
404             throw new AddressException( "Mail adress is null" );
405         }
406     }
407 
408     /**
409      * Extract a collection of elements to be attached to a mail from an HTML string. The collection contains the Url used for created DataHandler for each url
410      * associated with an HTML tag img, script or link. Those urls must start with the url strBaseUrl.
411      * 
412      * @param strHtml
413      *            The HTML code.
414      * @param strBaseUrl
415      *            The base url, can be null in order to extract all urls.
416      * @param useAbsoluteUrl
417      *            Determine if we use absolute or relative url for attachement content-location
418      * @return a collection of UrlAttachment Object for created DataHandler associated with attachment urls.
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      * Common part for sending message process :
433      * <ul>
434      * <li>initializes a mail session with the SMTP server</li>
435      * <li>activates debugging</li>
436      * <li>instantiates and initializes a mime message</li>
437      * <li>sets the sent date, the from field, the subject field</li>
438      * <li>sets the recipients</li>
439      * </ul>
440      *
441      *
442      * @return the message object initialized with the common settings
443      * @param mail
444      *            The mail to send
445      * @param session
446      *            The SMTP session object
447      * @throws AddressException
448      *             If invalid address
449      * @throws MessagingException
450      *             If a messaging error occurred
451      */
452     protected static Message prepareMessage( MailItem mail, Session session ) throws MessagingException
453     {
454         // Instantiate and initialize a mime message
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         // Instantiation of the list of address
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      * Open mail session with the SMTP server using the given credentials. Will use no authentication if strUsername is null or blank.
489      *
490      * @param strHost
491      *            The SMTP name or IP address.
492      * @param nPort
493      *            The port to use
494      * @param strUsername
495      *            the username
496      * @param strPassword
497      *            the password
498      * @return the mails session object
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         // Initializes a mail session with the SMTP server
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             // using authenticator class that return a PasswordAuthentication
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             // no authentication data provided, no authenticator
530             auth = null;
531         }
532 
533         Session mailSession = Session.getDefaultInstance( props, auth );
534         // Activate debugging
535         mailSession.setDebug( bSessionDebug );
536 
537         return mailSession;
538     }
539 
540     /**
541      * return the transport object of the SMTP session
542      *
543      * @return the transport object of the SMTP session
544      * @param session
545      *            the SMTP session
546      * @throws NoSuchProviderException
547      *             If the provider is not found
548      */
549     protected static Transport getTransport( Session session ) throws NoSuchProviderException
550     {
551         return session.getTransport( SMTP );
552     }
553 
554     /**
555      * extract The list of Internet Address content in the string strRecipients
556      *
557      * @return The list of Internet Address content in the string strRecipients
558      * @param strRecipients
559      *            The list of recipient separated by the mail separator defined in config.properties
560      * @throws AddressException
561      *             If invalid address
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         // Initialization of the address array
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      * Extract The list of String Address content in the string strRecipients
579      * 
580      * @return The list of String Address content in the string strRecipients
581      * @param strRecipients
582      *            The list of recipient separated by the mail separator defined in config.properties
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      * Return a String that contains a list of recipients separated with mail separator
600      * 
601      * @param listRecipients
602      *            a list of string recipients
603      * @return A String that contains a list of recipients separated with mail separator
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      * This Method convert a UrlAttachmentDataSource to a ByteArrayDataSource and used MailAttachmentCacheService for caching resource.
629      * 
630      * @param urlAttachement
631      *            {@link UrlAttachment}
632      * @return a {@link ByteArrayDataSource}
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             // Document is ignored
675             AppLogService.info( "{} {} ", urlAttachement.getContentLocation( ), MSG_ATTACHMENT_NOT_FOUND );
676         }
677         finally
678         {
679             // closed inputstream and outputstream
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             // add resource in cache
702             MailAttachmentCacheService.getInstance( ).putInCache( strKey, urlAttachmentDataSource );
703         }
704 
705         return urlAttachmentDataSource;
706     }
707 }