MailSenderDaemon.java

  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. import fr.paris.lutece.portal.service.daemon.AppDaemonService;
  36. import fr.paris.lutece.portal.service.daemon.Daemon;
  37. import fr.paris.lutece.portal.service.util.AppLogService;
  38. import fr.paris.lutece.portal.service.util.AppPropertiesService;

  39. import java.util.Date;
  40. import java.util.List;
  41. import java.util.concurrent.TimeUnit;

  42. import javax.mail.MessagingException;
  43. import javax.mail.NoSuchProviderException;
  44. import javax.mail.SendFailedException;
  45. import javax.mail.Session;
  46. import javax.mail.Transport;
  47. import javax.mail.internet.AddressException;

  48. import org.apache.logging.log4j.LogManager;
  49. import org.apache.logging.log4j.Logger;

  50. /**
  51.  * MailSender Daemon
  52.  */
  53. public class MailSenderDaemon extends Daemon
  54. {
  55.     protected static final String DAEMON_ID = "mailSender";

  56.     private static final String MESSAGE_ERROR_MAIL = "MailService - Error sending mail : ";
  57.     private static final String MESSAGE_STATUS_FAILED = " - Status [ Failed ] : ";
  58.     private static final String MESSAGE_ERROR_MAIL_MESSAGING = "MailService - Error sending mail (MessagingException): ";
  59.     private static final String PROPERTY_MAIL_HOST = "mail.server";
  60.     private static final String PROPERTY_MAIL_PORT = "mail.server.port";
  61.     private static final String PROPERTY_MAIL_DEAMON_WAITTIME = "mail.daemon.waittime";
  62.     private static final String PROPERTY_MAIL_DEAMON_COUNT = "mail.daemon.count";
  63.     private static final String PROPERTY_MAIL_USERNAME = "mail.username";
  64.     private static final String PROPERTY_MAIL_PASSWORD = "mail.password";
  65.     private static final String PROPERTY_MAIL_DAEMON_RETRYONERROR_WAITTIME = "mail.daemon.retryonerror.waittime";
  66.     private static final String PROPERTY_MAIL_DAEMON_RETRYONERROR_WAITTIME_UNIT = "mail.daemon.retryonerror.waittime.unit";
  67.     private static final int DEFAULT_SMTP_PORT = 25;

  68.     /**
  69.      * {@inheritDoc}
  70.      */
  71.     @Override
  72.     public synchronized void run( )
  73.     {
  74.         Logger logger = LogManager.getLogger( "lutece.mail" );

  75.         String strHost = AppPropertiesService.getProperty( PROPERTY_MAIL_HOST );
  76.         String strUsername = AppPropertiesService.getProperty( PROPERTY_MAIL_USERNAME, null );
  77.         String strPassword = AppPropertiesService.getProperty( PROPERTY_MAIL_PASSWORD, null );
  78.         int nStmpPort = AppPropertiesService.getPropertyInt( PROPERTY_MAIL_PORT, DEFAULT_SMTP_PORT );

  79.         // Initializes a mail session with the SMTP server
  80.         StringBuilder sbLogs = new StringBuilder( );
  81.         IMailQueue queue = MailService.getQueue( );

  82.         if ( queue.size( ) != 0 )
  83.         {
  84.             sbLogs.append( new Date( ).toString( ) );

  85.             Session session = MailUtil.getMailSession( strHost, nStmpPort, strUsername, strPassword );
  86.             Transport transportSmtp = null;

  87.             try
  88.             {
  89.                 transportSmtp = MailUtil.getTransport( session );
  90.             }
  91.             catch( NoSuchProviderException e )
  92.             {
  93.                 AppLogService.error( e.getMessage( ), e );
  94.             }

  95.             if ( transportSmtp != null )
  96.             {
  97.                 try
  98.                 {
  99.                     transportSmtp.connect( strHost, nStmpPort, strUsername, strPassword );

  100.                     sendMails( transportSmtp, session, queue, logger, sbLogs );

  101.                     transportSmtp.close( );
  102.                 }
  103.                 catch( MessagingException e )
  104.                 {
  105.                     sbLogs.append( MESSAGE_ERROR_MAIL_MESSAGING );
  106.                     sbLogs.append( e.getMessage( ) );
  107.                     AppLogService.error( "{} {} ", MESSAGE_ERROR_MAIL_MESSAGING, e.getMessage( ), e );
  108.                 }
  109.                 catch( Exception e )
  110.                 {
  111.                     sbLogs.append( MESSAGE_ERROR_MAIL );
  112.                     sbLogs.append( e.getMessage( ) );
  113.                     AppLogService.error( "{} {} ", MESSAGE_ERROR_MAIL, e.getMessage( ), e );
  114.                 }
  115.             }

  116.             // reset all resource stored in MailAttachmentCacheService
  117.             MailAttachmentCacheService.getInstance( ).resetCache( );
  118.             setLastRunLogs( sbLogs.toString( ) );
  119.         }
  120.         else
  121.         {
  122.             sbLogs.append( "\r\nNo mail to send " );
  123.             sbLogs.append( new Date( ).toString( ) );
  124.             logger.debug( sbLogs.toString( ) );
  125.         }
  126.     }

  127.     private void sendMails( Transport transportSmtp, Session session, IMailQueue queue, Logger logger, StringBuilder sbLogs ) throws MessagingException
  128.     {
  129.         int nWaitTime = AppPropertiesService.getPropertyInt( PROPERTY_MAIL_DEAMON_WAITTIME, 1 );
  130.         int nCount = AppPropertiesService.getPropertyInt( PROPERTY_MAIL_DEAMON_COUNT, 1000 );
  131.         long nRetryWaitTime = AppPropertiesService.getPropertyLong( PROPERTY_MAIL_DAEMON_RETRYONERROR_WAITTIME, 60L );
  132.         TimeUnit retryWaitTimeUnit = TimeUnit.valueOf( AppPropertiesService.getProperty( PROPERTY_MAIL_DAEMON_RETRYONERROR_WAITTIME_UNIT, "SECONDS" ) );

  133.         MailItem mail = queue.consume( );
  134.         int count = 0;

  135.         while ( mail != null )
  136.         {
  137.             try
  138.             {
  139.                 if ( mail.isUniqueRecipientTo( ) )
  140.                 {
  141.                     List<String> listAdressTo = MailUtil.getAllStringAdressOfRecipients( mail.getRecipientsTo( ) );

  142.                     for ( String strAdressTo : listAdressTo )
  143.                     {
  144.                         StringBuilder sbLogsLine = new StringBuilder( );
  145.                         // just one recipient by mail
  146.                         mail.setRecipientsTo( strAdressTo );
  147.                         sendMail( mail, transportSmtp, session, sbLogsLine );
  148.                         logger.info( sbLogsLine.toString( ) );
  149.                         sbLogs.append( "\r\n" );
  150.                         sbLogs.append( sbLogsLine );
  151.                     }
  152.                 }
  153.                 else
  154.                 {
  155.                     StringBuilder sbLogsLine = new StringBuilder( );
  156.                     sendMail( mail, transportSmtp, session, sbLogsLine );
  157.                     logger.info( sbLogsLine.toString( ) );
  158.                     sbLogs.append( "\r\n" );
  159.                     sbLogs.append( sbLogsLine );
  160.                 }
  161.             }
  162.             catch( MessagingException e )
  163.             {
  164.                 // if the connection is dead or not in the connected state
  165.                 // we put the mail in the queue before end process
  166.                 queue.send( mail );
  167.                 AppLogService.error( "Error while sending a message. Will schedule a retry", e );
  168.                 AppDaemonService.signalDaemon( DAEMON_ID, nRetryWaitTime, retryWaitTimeUnit );
  169.                 break;
  170.             }

  171.             mail = queue.consume( );
  172.             // Tempo
  173.             count++;

  174.             if ( ( count % nCount ) == 0 )
  175.             {
  176.                 transportSmtp.close( );
  177.                 AppDaemonService.signalDaemon( DAEMON_ID, nWaitTime, TimeUnit.MILLISECONDS );
  178.                 break;
  179.             }
  180.         }
  181.     }

  182.     /**
  183.      * send mail
  184.      *
  185.      * @param mail
  186.      *            the mail item
  187.      * @param transportSmtp
  188.      *            the smtp transport
  189.      * @param session
  190.      *            the session smtp
  191.      * @param sbLogsLine
  192.      *            the log line
  193.      * @throws MessagingException
  194.      *             See {@link MessagingException}
  195.      */
  196.     private void sendMail( MailItem mail, Transport transportSmtp, Session session, StringBuilder sbLogsLine ) throws MessagingException
  197.     {
  198.         try
  199.         {
  200.             sbLogsLine.append( " - To " );
  201.             sbLogsLine.append( ( ( mail.getRecipientsTo( ) != null ) ? mail.getRecipientsTo( ) : "" ) );
  202.             sbLogsLine.append( " - Cc " );
  203.             sbLogsLine.append( ( mail.getRecipientsCc( ) != null ) ? mail.getRecipientsCc( ) : "" );
  204.             sbLogsLine.append( " - Bcc " );
  205.             sbLogsLine.append( ( mail.getRecipientsBcc( ) != null ) ? mail.getRecipientsBcc( ) : "" );
  206.             sbLogsLine.append( " - Subject : " );
  207.             sbLogsLine.append( mail.getSubject( ) );

  208.             switch( mail.getFormat( ) )
  209.             {
  210.                 case MailItem.FORMAT_HTML:
  211.                     MailUtil.sendMessageHtml( mail, transportSmtp, session );
  212.                     break;
  213.                 case MailItem.FORMAT_TEXT:
  214.                     MailUtil.sendMessageText( mail, transportSmtp, session );
  215.                     break;
  216.                 case MailItem.FORMAT_MULTIPART_HTML:
  217.                     MailUtil.sendMultipartMessageHtml( mail, transportSmtp, session );
  218.                     break;
  219.                 case MailItem.FORMAT_MULTIPART_TEXT:
  220.                     MailUtil.sendMultipartMessageText( mail, transportSmtp, session );
  221.                     break;
  222.                 case MailItem.FORMAT_CALENDAR:
  223.                     MailUtil.sendMessageCalendar( mail, transportSmtp, session );
  224.                     break;
  225.                 default:
  226.                     break;
  227.             }

  228.             sbLogsLine.append( " - Status [ OK ]" );
  229.         }
  230.         catch( SendFailedException | AddressException e )
  231.         {
  232.             // a wrongly formatted address is encountered in the list of recipients
  233.             sbLogsLine.append( MESSAGE_STATUS_FAILED );
  234.             sbLogsLine.append( e.getMessage( ) );
  235.             AppLogService.error( "{} {} ", MESSAGE_ERROR_MAIL, e.getMessage( ), e );
  236.         }
  237.         catch( MessagingException e )
  238.         {
  239.             // if the connection is dead or not in the connected state
  240.             // we put the mail in the queue before end process
  241.             sbLogsLine.append( MESSAGE_STATUS_FAILED );
  242.             sbLogsLine.append( e.getMessage( ) );
  243.             AppLogService.error( "{} {} ", MESSAGE_ERROR_MAIL, e.getMessage( ), e );
  244.             throw e;
  245.         }
  246.     }
  247. }