CommonsNetSender.java
/*
* GovWay - A customizable API Gateway
* https://govway.org
*
* Copyright (c) 2005-2024 Link.it srl (https://link.it).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3, as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.openspcoop2.utils.mail;
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.io.Writer;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
import java.util.UUID;
import javax.mail.Multipart;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMultipart;
import javax.net.ssl.SSLContext;
import org.apache.commons.io.output.WriterOutputStream;
import org.apache.commons.net.PrintCommandListener;
import org.apache.commons.net.smtp.AuthenticatingSMTPClient;
import org.apache.commons.net.smtp.SMTPClient;
import org.apache.commons.net.smtp.SMTPReply;
import org.apache.commons.net.smtp.SimpleSMTPHeader;
import org.slf4j.Logger;
import org.openspcoop2.utils.UtilsException;
import org.openspcoop2.utils.transport.http.SSLUtilities;
/**
* CommonsNetSender
*
* @author Poli Andrea (apoli@link.it)
* @author $Author$
* @version $Rev$, $Date$
*/
public class CommonsNetSender extends Sender {
protected CommonsNetSender(Logger log) {
super(log);
}
@Override
public void send(Mail mail, boolean debug) throws UtilsException {
AuthenticatingSMTPClient client = null;
ByteArrayOutputStream bout = new ByteArrayOutputStream();
try {
if(mail.getSslConfig()!=null){
StringBuilder bf = new StringBuilder();
SSLContext sslContext = SSLUtilities.generateSSLContext(mail.getSslConfig(), bf);
if(debug)
this.log.debug(bf.toString());
//client.setSocketFactory(sslContext.getSocketFactory());
client = new AuthenticatingSMTPClient(false, sslContext);
client.setCharset(Charset.forName(mail.getEncoding()));
}
else {
client = new AuthenticatingSMTPClient(mail.getEncoding());
}
if (debug)
client.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(bout), true));
client.setDefaultTimeout(this.getReadTimeout());
client.setConnectTimeout(this.getConnectionTimeout());
this.log.debug("Connect to ["+mail.getServerHost()+":"+mail.getServerPort()+"] ...");
client.connect(mail.getServerHost(), mail.getServerPort());
this.log.debug("Connected to ["+mail.getServerHost()+":"+mail.getServerPort()+"]");
boolean esito = client.login();
checkReply(client, esito, "Login failed");
client.helo("[" + client.getLocalAddress().getHostAddress() + "]");
if(mail.isStartTls()){
esito = client.execTLS();
checkReply(client, esito, "STARTTLS was not accepted");
}
String replyString = client.getReplyString();
if(debug){
this.log.debug("ReplyString: "+replyString);
}
int reply = client.getReplyCode();
if(!SMTPReply.isPositiveCompletion(reply)) {
throw new Exception("SMTP server refused connection "+ client.getReply() + client.getReplyString());
}
if(mail.getUsername()!=null){
if(debug){
this.log.debug("Authenticating ["+mail.getUsername()+"] ...");
}
client.helo("[" + client.getLocalAddress().getHostAddress() + "]");
esito = client.auth(AuthenticatingSMTPClient.AUTH_METHOD.LOGIN, mail.getUsername(), mail.getPassword());
checkReply(client, esito, "Authentication failed");
if(debug){
this.log.debug("Authenticating ["+mail.getUsername()+"] ok");
}
}
if(debug){
this.log.debug("Set sender ["+mail.getFrom()+"] ...");
}
esito = client.setSender(mail.getFrom());
checkReply(client, esito, "Set sender["+mail.getFrom()+"] failed");
if(debug){
this.log.debug("Set to ["+mail.getTo()+"] ...");
}
esito = client.addRecipient(mail.getTo());
checkReply(client, esito, "Set to["+mail.getTo()+"] failed");
List<String> ccList = mail.getCc();
if(ccList!=null && ccList.size()>0){
for (String cc : ccList) {
if(debug){
this.log.debug("Add cc ["+cc+"] ...");
}
esito = client.addRecipient(cc);
checkReply(client, esito, "Set cc["+cc+"] failed");
}
}
boolean attach = (mail.getBody().getAttachments()!=null && mail.getBody().getAttachments().size()>0);
Writer writer = client.sendMessageData();
if(writer!=null){
if(debug){
this.log.debug("Send ...");
}
// HEADER
if(debug){
this.log.debug("Subject ["+mail.getSubject()+"] ...");
}
SimpleSMTPHeader header = new SimpleSMTPHeader(mail.getFrom(), mail.getTo(), mail.getSubject());
if(debug){
this.log.debug("Body ("+mail.getBody().getContentType()+") ["+mail.getBody().getMessage()+"] ...");
}
TimeZone tz = TimeZone.getTimeZone( "GMT" );
Date now = new Date();
header.addHeaderField("Date", formatSMTPDate( now, tz ));
if(mail.getUserAgent()!=null) {
header.addHeaderField("User-Agent", mail.getUserAgent());
}
if(mail.getMessageIdDomain()!=null) {
header.addHeaderField("Message-ID", "<"+UUID.randomUUID().toString()+"@"+mail.getMessageIdDomain()+">");
}
if(mail.getContentLanguage()!=null) {
header.addHeaderField("Content-Language", mail.getContentLanguage());
}
ccList = mail.getCc();
if(ccList!=null && ccList.size()>0){
for (String cc : ccList) {
header.addCC(cc);
}
}
Multipart multipart = null;
if(attach){
multipart = new MimeMultipart();
if(mail.getBody().getMessage()!=null){
MimeBodyPart messagePart = new MimeBodyPart();
messagePart.setText(mail.getBody().getMessage());
if(mail.getBody().getContentType()!=null)
messagePart.setHeader("Content-Type", mail.getBody().getContentType());
multipart.addBodyPart(messagePart);
}
for (MailAttach mailAttach : mail.getBody().getAttachments()) {
// NOTA: funziona solo per gli attachments testuali!
// motivo: usa un writer che corrompe poichè lavora su stringhe
MimeBodyPart attachmentPart = new MimeBodyPart();
if(mailAttach instanceof MailTextAttach){
MailTextAttach text = (MailTextAttach) mailAttach;
attachmentPart.setText(text.getContent());
}
else{
String msg = "La libreria CommonsNet non funziona correttamente con gli attachments di tipo binario. Usare il sender di tipo CommonsMail";
this.log.warn(msg);
System.out.println(msg);
MailBinaryAttach bin = (MailBinaryAttach) mailAttach;
attachmentPart.setContent(bin.getContent(), mailAttach.getContentType());
}
attachmentPart.setFileName(mailAttach.getName());
attachmentPart.setHeader("Content-Type", mailAttach.getContentType());
multipart.addBodyPart(attachmentPart);
}
}
if(!attach){
if(mail.getBody().getContentType()!=null){
header.addHeaderField("Content-Type", mail.getBody().getContentType());
}
}
else{
header.addHeaderField("Content-Type", multipart.getContentType());
}
writer.write(header.toString());
if(!attach){
writer.write(mail.getBody().getMessage());
}
else{
WriterOutputStream ww =
WriterOutputStream.builder()
.setWriter(writer)
.setCharset(org.openspcoop2.utils.resources.Charset.UTF_8.getValue())
.get();
multipart.writeTo(ww);
ww.flush();
ww.close();
}
writer.close();
if(!client.completePendingCommand()) {// failure
throw new Exception("Failure to send the email "+ client.getReply() + client.getReplyString());
}
} else {
throw new Exception("Failure to send the email "+ client.getReply() + client.getReplyString());
}
if(debug){
this.log.debug("Send finished");
}
} catch (Exception e) {
throw new UtilsException(e.getMessage(),e);
} finally {
try{
client.logout();
}catch(Exception e){}
try{
client.disconnect();
}catch(Exception e){}
if(bout!=null && bout.size()>0) {
this.log.debug("Messages exchanged: \n"+bout.toString());
}
}
}
private static String formatSMTPDate( Date date, TimeZone tz )
throws IllegalArgumentException
{
SimpleDateFormat dateFormat;
Locale loc = Locale.US;
dateFormat = new SimpleDateFormat( "EEE", loc );
dateFormat.setTimeZone( tz );
String day = dateFormat.format( date );
day = day.substring( 0, 3 );
dateFormat = new SimpleDateFormat( "MMM", loc );
dateFormat.setTimeZone( tz );
String month = dateFormat.format( date );
month = month.substring( 0, 3 );
dateFormat = new SimpleDateFormat( "dd", loc );
dateFormat.setTimeZone( tz );
String dayNum = dateFormat.format( date );
dateFormat = new SimpleDateFormat( "yyyy HH:mm:ss", loc );
dateFormat.setTimeZone( tz );
String rest = dateFormat.format( date );
String result = new String
( day + ", " + dayNum + " " + month + " " + rest + " +0000" );
return result;
}
private static void checkReply(SMTPClient sc, boolean esito, String object) throws Exception {
if (SMTPReply.isNegativeTransient(sc.getReplyCode())) {
throw new Exception(object+", transient SMTP error " + sc.getReply() + sc.getReplyString());
} else if (SMTPReply.isNegativePermanent(sc.getReplyCode())) {
throw new Exception(object+", permanent SMTP error " + sc.getReply() + sc.getReplyString());
}
else if(!esito){
throw new Exception(object+", ["+esito+"] " + sc.getReply() + sc.getReplyString());
}
}
}