/*
jBilling - The Enterprise Open Source Billing System
Copyright (C) 2003-2011 Enterprise jBilling Software Ltd. and Emiliano Conde
This file is part of jbilling.
jbilling is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
jbilling 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with jbilling. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sapienter.jbilling.server.pluggableTask;
import java.io.File;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import javax.mail.Address;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import org.apache.log4j.Logger;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import com.sapienter.jbilling.common.Util;
import com.sapienter.jbilling.server.notification.MessageDTO;
import com.sapienter.jbilling.server.notification.MessageSection;
import com.sapienter.jbilling.server.notification.NotificationBL;
import com.sapienter.jbilling.server.pluggableTask.admin.ParameterDescription;
import com.sapienter.jbilling.server.user.ContactBL;
import com.sapienter.jbilling.server.user.ContactDTOEx;
import com.sapienter.jbilling.server.user.db.UserDTO;
/*
* This will send an email to the main contant of the provided user
* It will expect two sections to compose the email message:
* 1 - The subject
* 2 - The body
*
* If the html parameter is true, then a third section will be expected
* 3 - HTML body
*/
public class BasicEmailNotificationTask extends PluggableTask
implements NotificationTask {
// pluggable task parameters names
public static final ParameterDescription PARAMETER_SMTP_SERVER =
new ParameterDescription("smtp_server", true, ParameterDescription.Type.STR);
public static final ParameterDescription PARAMETER_PORT =
new ParameterDescription("port", true, ParameterDescription.Type.STR);
public static final ParameterDescription PARAMETER_USERNAME =
new ParameterDescription("username", true, ParameterDescription.Type.STR);
public static final ParameterDescription PARAMETER_PASSWORD =
new ParameterDescription("password", true, ParameterDescription.Type.STR);
public static final ParameterDescription PARAMETER_FROM =
new ParameterDescription("from", false, ParameterDescription.Type.STR);
public static final ParameterDescription PARAMETER_FROM_NAME =
new ParameterDescription("from_name", false, ParameterDescription.Type.STR);
public static final ParameterDescription PARAMETER_REPLYTO =
new ParameterDescription("reply_to", false, ParameterDescription.Type.STR);
public static final ParameterDescription PARAMETER_BCCTO =
new ParameterDescription("bcc_to", false, ParameterDescription.Type.STR);
public static final ParameterDescription PARAMETER_HTML =
new ParameterDescription("html", false, ParameterDescription.Type.STR);
public static final ParameterDescription PARAMETER_TLS =
new ParameterDescription("tls", true, ParameterDescription.Type.STR);
public static final ParameterDescription PARAMETER_SSL_AUTH =
new ParameterDescription("ssl_auth", true, ParameterDescription.Type.STR);
//initializer for pluggable params
{
descriptions.add(PARAMETER_BCCTO);
descriptions.add(PARAMETER_FROM);
descriptions.add(PARAMETER_FROM_NAME);
descriptions.add(PARAMETER_HTML);
descriptions.add(PARAMETER_PASSWORD);
descriptions.add(PARAMETER_PORT);
descriptions.add(PARAMETER_REPLYTO);
descriptions.add(PARAMETER_SMTP_SERVER);
descriptions.add(PARAMETER_SSL_AUTH);
descriptions.add(PARAMETER_TLS);
descriptions.add(PARAMETER_USERNAME);
}
private static final Logger LOG = Logger.getLogger(BasicEmailNotificationTask.class);
// local variables
private JavaMailSenderImpl sender = new JavaMailSenderImpl();
private String server;
private int port;
private String username;
private String password;
private String replyTo;
private boolean doHTML;
private boolean tls;
private boolean sslAuth;
private void init() {
// set some parameters
server = (String) parameters.get(PARAMETER_SMTP_SERVER.getName());
if (server == null || server.length() == 0) {
server = Util.getSysProp("smtp_server");
}
port = Integer.parseInt(Util.getSysProp("smtp_port"));
String strPort = String.valueOf(parameters.get(PARAMETER_PORT.getName()));
if (strPort != null && strPort.trim().length() > 0) {
try {
port = Integer.valueOf(strPort).intValue();
} catch (NumberFormatException e) {
LOG.error("The port is not a number", e);
}
}
username = (String) parameters.get(PARAMETER_USERNAME.getName());
if (username == null || username.length() == 0) {
username = Util.getSysProp("smtp_username");
}
password = (String) parameters.get(PARAMETER_PASSWORD.getName());
if (password == null || password.length() == 0) {
password = Util.getSysProp("smtp_password");
}
replyTo = (String) parameters.get(PARAMETER_REPLYTO.getName());
doHTML = Boolean.parseBoolean((String) parameters.get(PARAMETER_HTML.getName()));
tls = Boolean.parseBoolean((String) parameters.get(PARAMETER_TLS.getName()));
sslAuth = Boolean.parseBoolean((String) parameters.get(PARAMETER_SSL_AUTH.getName()));
}
public void deliver(UserDTO user, MessageDTO message)
throws TaskException {
// do not process paper invoices. So far, all the rest are emails
// This if is necessary because an entity can have some customers
// with paper invoices and others with emal invoices.
if (message.getTypeId().compareTo(
MessageDTO.TYPE_INVOICE_PAPER) == 0) {
return;
}
// verify that we've got the right number of sections
MessageSection[] sections = message.getContent();
if (sections.length < getSections()) {
throw new TaskException("This task takes " + getSections() + " sections." +
sections.length + " found.");
}
// create the session & message
init();
sender.setHost(server);
sender.setUsername(username);
sender.setPassword(password);
sender.setPort(port);
if (username != null && username.length() > 0) {
sender.getJavaMailProperties().setProperty("mail.smtp.auth", "true");
}
if (tls) {
sender.getJavaMailProperties().setProperty("mail.smtp.starttls.enable", "true");
}
if (sslAuth) {
// required for SMTP servers that use SSL authentication,
// e.g., Gmail's SMTP servers
sender.getJavaMailProperties().setProperty(
"mail.smtp.socketFactory.class",
"javax.net.ssl.SSLSocketFactory");
}
MimeMessage mimeMsg = sender.createMimeMessage();
MimeMessageHelper msg = null;
// set the message's fields
// the to address/es
try {
msg = new MimeMessageHelper(mimeMsg, doHTML || message.getAttachmentFile() != null);
ContactBL contact = new ContactBL();
List contacts = contact.getAll(user.getUserId());
List addresses = new ArrayList<InternetAddress>();
boolean atLeastOne = false;
for (int f = 0; f < contacts.size(); f++) {
ContactDTOEx record = (ContactDTOEx) contacts.get(f);
String address = record.getEmail();
if (record.getInclude() != null &&
record.getInclude().intValue() == 1 &&
address != null && address.trim().length() > 0) {
addresses.add(new InternetAddress(address, false));
atLeastOne = true;
}
}
if (!atLeastOne) {
// not a huge deal, but no way I can send anything
LOG.info("User without email address " +
user.getUserId());
return;
} else {
msg.setTo((InternetAddress[])addresses.toArray(new InternetAddress[addresses.size()]));
}
} catch (Exception e) {
LOG.debug("Exception setting addresses ", e);
throw new TaskException("Setting addresses");
}
// the from address
String from = (String) parameters.get(PARAMETER_FROM.getName());
if (from == null || from.length() == 0) {
from = Util.getSysProp("email_from");
}
String fromName = (String) parameters.get(PARAMETER_FROM_NAME.getName());
try {
if (fromName == null || fromName.length() == 0) {
msg.setFrom(new InternetAddress(from));
} else {
msg.setFrom(new InternetAddress(from, fromName));
}
} catch (Exception e1) {
throw new TaskException("Invalid from address:" + from +
"." + e1.getMessage());
}
// the reply to
if (replyTo != null && replyTo.length() > 0) {
try {
msg.setReplyTo(replyTo);
} catch (Exception e5) {
LOG.error("Exception when setting the replyTo address: " +
replyTo, e5);
}
}
// the bcc if specified
String bcc = (String) parameters.get(PARAMETER_BCCTO.getName());
if (bcc != null && bcc.length() > 0) {
try {
msg.setBcc(new InternetAddress(bcc, false));
} catch (AddressException e5) {
LOG.warn("The bcc address " + bcc + " is not valid. " +
"Sending without bcc", e5);
} catch (MessagingException e5) {
throw new TaskException("Exception setting bcc " +
e5.getMessage());
}
}
// the subject and body
try {
msg.setSubject(sections[0].getContent());
if (doHTML) {
// both are sent as alternatives
msg.setText(sections[1].getContent(), sections[2].getContent());
} else {
// only plain text
msg.setText(sections[1].getContent());
}
if (message.getAttachmentFile() != null) {
File file = (File) new File(message.getAttachmentFile());
msg.addAttachment(file.getName(), new FileSystemResource(file));
LOG.debug("added attachment " + file.getName());
}
} catch (MessagingException e2) {
throw new TaskException("Exception setting up the subject and/or" +
" body." + e2.getMessage());
}
// the date
try {
msg.setSentDate(Calendar.getInstance().getTime());
} catch (MessagingException e3) {
throw new TaskException("Exception setting up the date" +
"." + e3.getMessage());
}
// send the message
try {
String allEmails = "";
for (Address address : msg.getMimeMessage().getRecipients(Message.RecipientType.TO)) {
allEmails = allEmails + " " + address.toString();
}
LOG.debug(
"Sending email to " + allEmails + " bcc " + bcc + " server=" + server +
" port=" + port + " username=" + username + " password=" +
password);
sender.send(mimeMsg);
//if there was an attachment, remove the file
if (message.getAttachmentFile() != null) {
File file = new File(message.getAttachmentFile());
if (!file.delete()) {
LOG.debug("Could not delete attachment file " +
file.getName());
}
}
} catch (Throwable e4) { // need to catch a messaging exception plus spring's runtimes
LOG.warn("Error sending email", e4);
// send an emial to the entity to let it know about the failure
try {
String params[] = new String[6]; // five parameters for this message;
params[0] = (e4.getMessage() == null ? "No detailed exception message" : e4.getMessage());
params[1] = "";
for (Address address : msg.getMimeMessage().getAllRecipients()) {
params[1] = params[1] + " " + address.toString();
}
params[2] = server;
params[3] = port + " ";
params[4] = username;
params[5] = password;
NotificationBL.sendSapienterEmail(user.getEntity().getId(),
"notification.email.error", null, params);
} catch (Exception e5) {
LOG.warn("Exception sending error message to entity", e5);
}
throw new TaskException("Exception sending the message" +
"." + e4.getMessage());
}
}
public int getSections() {
init();
return doHTML ? 3 : 2;
}
}