CommonsNetSender.java

  1. /*
  2.  * GovWay - A customizable API Gateway
  3.  * https://govway.org
  4.  *
  5.  * Copyright (c) 2005-2025 Link.it srl (https://link.it).
  6.  *
  7.  * This program is free software: you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License version 3, as published by
  9.  * the Free Software Foundation.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18.  *
  19.  */

  20. package org.openspcoop2.utils.mail;

  21. import java.io.ByteArrayOutputStream;
  22. import java.io.PrintWriter;
  23. import java.io.Writer;
  24. import java.nio.charset.Charset;
  25. import java.text.SimpleDateFormat;
  26. import java.util.Date;
  27. import java.util.List;
  28. import java.util.Locale;
  29. import java.util.TimeZone;
  30. import java.util.UUID;

  31. import javax.mail.Multipart;
  32. import javax.mail.internet.MimeBodyPart;
  33. import javax.mail.internet.MimeMultipart;
  34. import javax.net.ssl.SSLContext;

  35. import org.apache.commons.io.output.WriterOutputStream;
  36. import org.apache.commons.net.PrintCommandListener;
  37. import org.apache.commons.net.smtp.AuthenticatingSMTPClient;
  38. import org.apache.commons.net.smtp.SMTPClient;
  39. import org.apache.commons.net.smtp.SMTPReply;
  40. import org.apache.commons.net.smtp.SimpleSMTPHeader;
  41. import org.slf4j.Logger;
  42. import org.openspcoop2.utils.UtilsException;
  43. import org.openspcoop2.utils.transport.http.SSLUtilities;

  44. /**
  45.  * CommonsNetSender
  46.  *
  47.  * @author Poli Andrea (apoli@link.it)
  48.  * @author $Author$
  49.  * @version $Rev$, $Date$
  50.  */
  51. public class CommonsNetSender extends Sender {

  52.     protected CommonsNetSender(Logger log) {
  53.         super(log);
  54.     }

  55.     @Override
  56.     public void send(Mail mail, boolean debug) throws UtilsException {

  57.         AuthenticatingSMTPClient client = null;
  58.         ByteArrayOutputStream bout = new ByteArrayOutputStream();
  59.         try {          
  60.             if(mail.getSslConfig()!=null){
  61.                 StringBuilder bf = new StringBuilder();
  62.                 SSLContext sslContext = SSLUtilities.generateSSLContext(mail.getSslConfig(), bf);
  63.                 if(debug)
  64.                     this.log.debug(bf.toString());
  65.                 //client.setSocketFactory(sslContext.getSocketFactory());
  66.                 client = new AuthenticatingSMTPClient(false, sslContext);
  67.                 client.setCharset(Charset.forName(mail.getEncoding()));
  68.             }
  69.             else {
  70.                 client = new AuthenticatingSMTPClient(mail.getEncoding());
  71.             }
  72.            
  73.            
  74.              if (debug)
  75.                  client.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(bout), true));

  76.             client.setDefaultTimeout(this.getReadTimeout());
  77.             client.setConnectTimeout(this.getConnectionTimeout());
  78.            
  79.             this.log.debug("Connect to ["+mail.getServerHost()+":"+mail.getServerPort()+"] ...");
  80.             client.connect(mail.getServerHost(), mail.getServerPort());
  81.             this.log.debug("Connected to ["+mail.getServerHost()+":"+mail.getServerPort()+"]");

  82.             boolean esito = client.login();
  83.             checkReply(client, esito, "Login failed");

  84.             client.helo("[" + client.getLocalAddress().getHostAddress() + "]");
  85.            
  86.             if(mail.isStartTls()){
  87.                 esito = client.execTLS();
  88.                 checkReply(client, esito, "STARTTLS was not accepted");
  89.             }

  90.             String replyString = client.getReplyString();
  91.             if(debug){
  92.                 this.log.debug("ReplyString: "+replyString);
  93.             }
  94.             int reply = client.getReplyCode();
  95.             if(!SMTPReply.isPositiveCompletion(reply)) {
  96.                 throw new Exception("SMTP server refused connection "+ client.getReply() + client.getReplyString());
  97.             }

  98.             if(mail.getUsername()!=null){
  99.                 if(debug){
  100.                     this.log.debug("Authenticating ["+mail.getUsername()+"] ...");
  101.                 }
  102.                 client.helo("[" + client.getLocalAddress().getHostAddress() + "]");

  103.                 esito =  client.auth(AuthenticatingSMTPClient.AUTH_METHOD.LOGIN, mail.getUsername(), mail.getPassword());
  104.                 checkReply(client, esito, "Authentication failed");
  105.                 if(debug){
  106.                     this.log.debug("Authenticating ["+mail.getUsername()+"] ok");
  107.                 }
  108.             }

  109.             if(debug){
  110.                 this.log.debug("Set sender ["+mail.getFrom()+"] ...");
  111.             }
  112.             esito = client.setSender(mail.getFrom());
  113.             checkReply(client, esito, "Set sender["+mail.getFrom()+"] failed");
  114.            
  115.             if(debug){
  116.                 this.log.debug("Set to ["+mail.getTo()+"] ...");
  117.             }
  118.             esito = client.addRecipient(mail.getTo());
  119.             checkReply(client, esito, "Set to["+mail.getTo()+"] failed");
  120.            
  121.             List<String> ccList = mail.getCc();
  122.             if(ccList!=null && ccList.size()>0){
  123.                 for (String cc : ccList) {
  124.                     if(debug){
  125.                         this.log.debug("Add cc ["+cc+"] ...");
  126.                     }
  127.                     esito = client.addRecipient(cc);
  128.                     checkReply(client, esito, "Set cc["+cc+"] failed");
  129.                 }
  130.             }

  131.             boolean attach = (mail.getBody().getAttachments()!=null && mail.getBody().getAttachments().size()>0);
  132.            
  133.             Writer writer = client.sendMessageData();
  134.             if(writer!=null){
  135.                
  136.                 if(debug){
  137.                     this.log.debug("Send ...");
  138.                 }
  139.                
  140.                 // HEADER
  141.                 if(debug){
  142.                     this.log.debug("Subject ["+mail.getSubject()+"] ...");
  143.                 }
  144.                 SimpleSMTPHeader header = new SimpleSMTPHeader(mail.getFrom(), mail.getTo(), mail.getSubject());
  145.                        
  146.                 if(debug){
  147.                     this.log.debug("Body ("+mail.getBody().getContentType()+") ["+mail.getBody().getMessage()+"] ...");
  148.                 }
  149.                
  150.                 TimeZone tz = TimeZone.getTimeZone( "GMT" );
  151.                 Date now = new Date();
  152.                 header.addHeaderField("Date", formatSMTPDate( now, tz ));
  153.                
  154.                 if(mail.getUserAgent()!=null) {
  155.                     header.addHeaderField("User-Agent", mail.getUserAgent());
  156.                 }
  157.                
  158.                 if(mail.getMessageIdDomain()!=null) {
  159.                     header.addHeaderField("Message-ID", "<"+UUID.randomUUID().toString()+"@"+mail.getMessageIdDomain()+">");
  160.                 }
  161.                
  162.                 if(mail.getContentLanguage()!=null) {
  163.                     header.addHeaderField("Content-Language", mail.getContentLanguage());
  164.                 }
  165.                            
  166.                 ccList = mail.getCc();
  167.                 if(ccList!=null && ccList.size()>0){
  168.                     for (String cc : ccList) {
  169.                         header.addCC(cc);  
  170.                     }
  171.                 }
  172.                
  173.                 Multipart multipart = null;
  174.                 if(attach){
  175.                      multipart = new MimeMultipart();
  176.                      
  177.                      if(mail.getBody().getMessage()!=null){
  178.                          MimeBodyPart messagePart = new MimeBodyPart();
  179.                          messagePart.setText(mail.getBody().getMessage());
  180.                          if(mail.getBody().getContentType()!=null)
  181.                              messagePart.setHeader("Content-Type", mail.getBody().getContentType());
  182.                          multipart.addBodyPart(messagePart);
  183.                      }
  184.                      
  185.                      for (MailAttach mailAttach : mail.getBody().getAttachments()) {
  186.                          // NOTA: funziona solo per gli attachments testuali!
  187.                          // motivo: usa un writer che corrompe poichè lavora su stringhe
  188.                          MimeBodyPart attachmentPart = new MimeBodyPart();
  189.                          if(mailAttach instanceof MailTextAttach){
  190.                              MailTextAttach text = (MailTextAttach) mailAttach;
  191.                              attachmentPart.setText(text.getContent());
  192.                          }
  193.                          else{
  194.                              String msg = "La libreria CommonsNet non funziona correttamente con gli attachments di tipo binario. Usare il sender di tipo CommonsMail";
  195.                              this.log.warn(msg);
  196.                              System.out.println(msg);
  197.                              MailBinaryAttach bin = (MailBinaryAttach) mailAttach;
  198.                              attachmentPart.setContent(bin.getContent(), mailAttach.getContentType());
  199.                          }
  200.                          attachmentPart.setFileName(mailAttach.getName());
  201.                          attachmentPart.setHeader("Content-Type", mailAttach.getContentType());
  202.                          multipart.addBodyPart(attachmentPart);
  203.                     }
  204.                      
  205.                 }
  206.                
  207.                 if(!attach){
  208.                     if(mail.getBody().getContentType()!=null){
  209.                          header.addHeaderField("Content-Type", mail.getBody().getContentType());
  210.                     }
  211.                 }
  212.                 else{
  213.                     header.addHeaderField("Content-Type", multipart.getContentType());
  214.                 }
  215.                
  216.                 writer.write(header.toString());
  217.                
  218.                 if(!attach){
  219.                     writer.write(mail.getBody().getMessage());
  220.                 }
  221.                 else{
  222.                     WriterOutputStream ww =
  223.                             WriterOutputStream.builder()
  224.                               .setWriter(writer)
  225.                               .setCharset(org.openspcoop2.utils.resources.Charset.UTF_8.getValue())
  226.                               .get();
  227.                     multipart.writeTo(ww);
  228.                     ww.flush();
  229.                     ww.close();
  230.                 }
  231.                                
  232.                 writer.close();
  233.                 if(!client.completePendingCommand()) {// failure
  234.                     throw new Exception("Failure to send the email "+ client.getReply() + client.getReplyString());
  235.                 }
  236.                
  237.             } else {
  238.                 throw new Exception("Failure to send the email "+ client.getReply() + client.getReplyString());
  239.             }
  240.            
  241.             if(debug){
  242.                 this.log.debug("Send finished");
  243.             }
  244.            
  245.         } catch (Exception e) {
  246.             throw new UtilsException(e.getMessage(),e);
  247.         } finally {
  248.             try{
  249.                 client.logout();
  250.             }catch(Exception e){}
  251.             try{
  252.                 client.disconnect();
  253.             }catch(Exception e){}
  254.             if(bout!=null && bout.size()>0) {
  255.                 this.log.debug("Messages exchanged: \n"+bout.toString());
  256.             }
  257.         }
  258.     }

  259.     private static String formatSMTPDate( Date date, TimeZone tz )
  260.             throws IllegalArgumentException
  261.         {
  262.         SimpleDateFormat dateFormat;
  263.         Locale loc = Locale.US;

  264.         dateFormat = new SimpleDateFormat( "EEE", loc );
  265.         dateFormat.setTimeZone( tz );
  266.         String day = dateFormat.format( date );
  267.         day = day.substring( 0, 3 );

  268.         dateFormat = new SimpleDateFormat( "MMM", loc );
  269.         dateFormat.setTimeZone( tz );
  270.         String month = dateFormat.format( date );
  271.         month = month.substring( 0, 3 );

  272.         dateFormat = new SimpleDateFormat( "dd", loc );
  273.         dateFormat.setTimeZone( tz );
  274.         String dayNum = dateFormat.format( date );

  275.         dateFormat = new SimpleDateFormat( "yyyy HH:mm:ss", loc );
  276.         dateFormat.setTimeZone( tz );
  277.         String rest = dateFormat.format( date );

  278.         String result = new String
  279.             ( day + ", " + dayNum + " " + month + " " + rest + " +0000" );

  280.         return result;
  281.        

  282.     }
  283.    
  284.     private static void checkReply(SMTPClient sc, boolean esito, String object) throws Exception {
  285.         if (SMTPReply.isNegativeTransient(sc.getReplyCode())) {
  286.             throw new Exception(object+", transient SMTP error " + sc.getReply() + sc.getReplyString());
  287.         } else if (SMTPReply.isNegativePermanent(sc.getReplyCode())) {
  288.             throw new Exception(object+", permanent SMTP error " + sc.getReply() + sc.getReplyString());
  289.         }
  290.         else if(!esito){
  291.             throw new Exception(object+", ["+esito+"] " + sc.getReply() + sc.getReplyString());
  292.         }
  293.     }
  294. }