View Javadoc
1   /*
2    * Copyright (c) 2002-2014, Mairie de 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 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   * 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_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     // Constants
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         // We create the mime text/calendar mime type
123         MimetypesFileTypeMap mimetypes = (MimetypesFileTypeMap) MimetypesFileTypeMap.getDefaultFileTypeMap(  );
124         mimetypes.addMimeTypes( MIME_TYPE_TEXT_CALENDAR );
125 
126         // We register the handler for the text/calendar mime type
127         MailcapCommandMap mailcap = (MailcapCommandMap) MailcapCommandMap.getDefaultCommandMap(  );
128 
129         // We try to get the default handler for plain text
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         // If the default handler for plain text was not found, we just use the default one
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      * Creates a new MailUtil object
158      */
159     private MailUtil(  )
160     {
161     }
162 
163     /**
164      * Send a text message.
165      *
166      * @param strRecipientsTo
167      *            The list of the main recipients email.Every recipient must be
168      *            separated by the mail separator defined in config.properties
169      * @param strRecipientsCc
170      *            The recipients list of the carbon copies .
171      * @param strRecipientsBcc
172      *            The recipients list of the blind carbon copies .
173      * @param strSenderName
174      *            The sender name.
175      * @param strSenderEmail
176      *            The sender email address.
177      * @param strSubject
178      *            The message subject.
179      * @param strMessage
180      *            The message.
181      * @param transport
182      *            the smtp transport object
183      * @param session
184      *            the smtp session object
185      * @throws AddressException
186      *             If invalid address
187      * @throws SendFailedException
188      *             If an error occured during sending
189      * @throws MessagingException
190      *             If a messaging error occured
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      * Send a HTML formated message.
208      * @param strRecipientsTo
209      *            The list of the main recipients email.Every recipient must be
210      *            separated by the mail separator defined in config.properties
211      * @param strRecipientsCc
212      *            The recipients list of the carbon copies .
213      * @param strRecipientsBcc
214      *            The recipients list of the blind carbon copies .
215      * @param strSenderName
216      *            The sender name.
217      * @param strSenderEmail
218      *            The sender email address.
219      * @param strSubject
220      *            The message subject.
221      * @param strMessage
222      *            The message.
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 occured
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         // Message body formated in HTML
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      * Send a Multipart HTML message with the attachements associated to the
253      * message and attached files. FIXME: use prepareMessage method
254      *
255      * @param strRecipientsTo
256      *            The list of the main recipients email.Every recipient must be
257      *            separated by the mail separator defined in config.properties
258      * @param strRecipientsCc
259      *            The recipients list of the carbon copies .
260      * @param strRecipientsBcc
261      *            The recipients list of the blind carbon copies .
262      * @param strSenderName
263      *            The sender name.
264      * @param strSenderEmail
265      *            The sender email address.
266      * @param strSubject
267      *            The message subject.
268      * @param strMessage
269      *            The message.
270      * @param urlAttachements
271      *            The List of UrlAttachement Object, containing the URL of
272      *            attachments associated with their content-location.
273      * @param fileAttachements
274      *            The list of files attached
275      * @param transport
276      *            the smtp transport object
277      * @param session
278      *            the smtp session object
279      * @throws AddressException
280      *             If invalid address
281      * @throws SendFailedException
282      *             If an error occured during sending
283      * @throws MessagingException
284      *             If a messaging error occurred
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         // Creation of the root part containing all the elements of the message
296         MimeMultipart multipart = ( ( fileAttachements == null ) || ( fileAttachements.isEmpty(  ) ) )
297             ? new MimeMultipart( MULTIPART_RELATED ) : new MimeMultipart(  );
298 
299         // Creation of the html part, the "core" of the message
300         BodyPart msgBodyPart = new MimeBodyPart(  );
301         // msgBodyPart.setContent( strMessage, BODY_PART_MIME_TYPE );
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                     // Fill this part, then add it to the root part with the
320                     // good headers
321                     msgBodyPart.setDataHandler( new DataHandler( urlByteArrayDataSource ) );
322                     msgBodyPart.setHeader( HEADER_CONTENT_LOCATION, urlAttachement.getContentLocation(  ) );
323                     multipart.addBodyPart( msgBodyPart );
324                 }
325             }
326         }
327 
328         // add File Attachement
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      * Send a Multipart text message with attached files. FIXME: use
352      * prepareMessage method
353      *
354      * @param strRecipientsTo
355      *            The list of the main recipients email.Every recipient must be
356      *            separated by the mail separator defined in config.properties
357      * @param strRecipientsCc
358      *            The recipients list of the carbon copies .
359      * @param strRecipientsBcc
360      *            The recipients list of the blind carbon copies .
361      * @param strSenderName
362      *            The sender name.
363      * @param strSenderEmail
364      *            The sender email address.
365      * @param strSubject
366      *            The message subject.
367      * @param strMessage
368      *            The message.
369      * @param fileAttachements
370      *            The list of attached files
371      * @param transport
372      *            the smtp transport object
373      * @param session
374      *            the smtp session object
375      * @throws AddressException
376      *             If invalid address
377      * @throws SendFailedException
378      *             If an error occured during sending
379      * @throws MessagingException
380      *             If a messaging error occured
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         // Creation of the root part containing all the elements of the message
392         MimeMultipart multipart = new MimeMultipart(  );
393 
394         // Creation of the html part, the "core" of the message
395         BodyPart msgBodyPart = new MimeBodyPart(  );
396         // msgBodyPart.setContent( strMessage, BODY_PART_MIME_TYPE );
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         // add File Attachement
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      * Send a calendar message.
427      * @param strRecipientsTo The list of the main recipients email. Every
428      *            recipient must be separated by the mail separator defined in
429      *            config.properties
430      * @param strRecipientsCc The recipients list of the carbon copies .
431      * @param strRecipientsBcc The recipients list of the blind carbon copies .
432      * @param strSenderName The sender name.
433      * @param strSenderEmail The sender email address.
434      * @param strSubject The message subject.
435      * @param strMessage The HTML message.
436      * @param strCalendarMessage The calendar message.
437      * @param bCreateEvent True to create the event, false to remove it
438      * @param transport the smtp transport object
439      * @param session the smtp session object
440      * @throws AddressException If invalid address
441      * @throws SendFailedException If an error occurred during sending
442      * @throws MessagingException If a messaging error occurred
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         //        calendarBodyPart.addHeader( "Content-Class", "urn:content-classes:calendarmessage" );
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      * Send the message
480      *
481      * @param msg
482      *            the message to send
483      * @param transport
484      *            the transport used to send the message
485      * @throws MessagingException
486      *             If a messaging error occured
487      * @throws AddressException
488      *             If invalid address
489      */
490     private static void sendMessage( Message msg, Transport transport )
491         throws MessagingException, AddressException
492     {
493         if ( msg.getAllRecipients(  ) != null )
494         {
495             // Send the message
496             transport.sendMessage( msg, msg.getAllRecipients(  ) );
497         }
498         else
499         {
500             throw new AddressException( "Mail adress is null" );
501         }
502     }
503 
504     /**
505      * Extract a collection of elements to be attached to a mail from an HTML
506      * string.
507      * The collection contains the Url used for created DataHandler for each url
508      * associated with an HTML tag img, script or link. Those urls must start
509      * with the url strBaseUrl.
510      * @param strHtml The HTML code.
511      * @param strBaseUrl The base url, can be null in order to extract all urls.
512      * @param useAbsoluteUrl Determine if we use absolute or relative url for
513      *            attachement content-location
514      * @return a collection of UrlAttachment Object for created DataHandler
515      *         associated with attachment urls.
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      * Common part for sending message process :
530      * <ul>
531      * <li>initializes a mail session with the SMTP server</li>
532      * <li>activates debugging</li>
533      * <li>instantiates and initializes a mime message</li>
534      * <li>sets the sent date, the from field, the subject field</li>
535      * <li>sets the recipients</li>
536      * </ul>
537      *
538      *
539      * @return the message object initialized with the common settings
540      * @param strRecipientsTo The list of the main recipients email.Every
541      *            recipient must be separated by the mail separator defined in
542      *            config.properties
543      * @param strRecipientsCc The recipients list of the carbon copies .
544      * @param strRecipientsBcc The recipients list of the blind carbon copies .
545      * @param strSenderName The sender name.
546      * @param strSenderEmail The sender email address.
547      * @param strSubject The message subject.
548      * @param session The SMTP session object
549      * @throws AddressException If invalid address
550      * @throws MessagingException If a messaging error occurred
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         // Instantiate and initialize a mime message
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         // Instantiation of the list of address
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      * Open mail session with the SMTP server using the given credentials. Will
593      * use no authentication if strUsername is null or blank.
594      *
595      * @param strHost The SMTP name or IP address.
596      * @param nPort The port to use
597      * @param strUsername the username
598      * @param strPassword the password
599      * @return the mails session object
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         // Initializes a mail session with the SMTP server
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             // using authenticator class that return a PasswordAuthentication
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             // no authentication data provided, no authenticator
632             auth = null;
633         }
634 
635         Session mailSession = Session.getDefaultInstance( props, auth );
636         // Activate debugging
637         mailSession.setDebug( bSessionDebug );
638 
639         return mailSession;
640     }
641 
642     /**
643      * return the transport object of the SMTP session
644      *
645      * @return the transport object of the SMTP session
646      * @param session the SMTP session
647      * @throws NoSuchProviderException If the provider is not found
648      */
649     protected static Transport getTransport( Session session )
650         throws NoSuchProviderException
651     {
652         return session.getTransport( SMTP );
653     }
654 
655     /**
656      * extract The list of Internet Address content in the string strRecipients
657      *
658      * @return The list of Internet Address content in the string strRecipients
659      * @param strRecipients
660      *            The list of recipient separated by the mail separator defined
661      *            in config.properties
662      * @throws AddressException
663      *             If invalid address
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         // Initialization of the address array
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      * Extract The list of String Address content in the string strRecipients
682      * @return The list of String Address content in the string strRecipients
683      * @param strRecipients The list of recipient separated by the mail
684      *            separator defined in config.properties
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      * Return a String that contains a list of recipients separated with mail
703      * separator
704      * @param listRecipients a list of string recipients
705      * @return A String that contains a list of recipients separated with mail
706      *         separator
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      * This Method convert a UrlAttachmentDataSource to a ByteArrayDataSource
732      * and used MailAttachmentCacheService for caching resource.
733      * @param urlAttachement {@link UrlAttachment}
734      * @return a {@link ByteArrayDataSource}
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                 // Document is ignored
781                 AppLogService.info( urlAttachement.getContentLocation(  ) + MSG_ATTACHMENT_NOT_FOUND );
782             }
783             finally
784             {
785                 //closed inputstream and outputstream 
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                 //add resource in cache
808                 MailAttachmentCacheService.getInstance(  ).putInCache( strKey, urlAttachmentDataSource );
809             }
810         }
811         else
812         {
813             //used the resource store in cache
814             urlAttachmentDataSource = (ByteArrayDataSource) MailAttachmentCacheService.getInstance(  )
815                                                                                       .getFromCache( strKey );
816         }
817 
818         return urlAttachmentDataSource;
819     }
820 }