Java tutorial
/*! ****************************************************************************** * * Pentaho Data Integration * * Copyright (C) 2002-2013 by Pentaho : http://www.pentaho.com * ******************************************************************************* * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ package org.pentaho.di.job.entries.mail; import static org.pentaho.di.job.entry.validator.AndValidator.putValidators; import static org.pentaho.di.job.entry.validator.JobEntryValidatorUtils.andValidator; import static org.pentaho.di.job.entry.validator.JobEntryValidatorUtils.emailValidator; import static org.pentaho.di.job.entry.validator.JobEntryValidatorUtils.integerValidator; import static org.pentaho.di.job.entry.validator.JobEntryValidatorUtils.notBlankValidator; import static org.pentaho.di.job.entry.validator.JobEntryValidatorUtils.notNullValidator; import java.io.BufferedInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.Date; import java.util.List; import java.util.Properties; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import javax.activation.DataHandler; import javax.activation.FileDataSource; import javax.activation.URLDataSource; import javax.mail.Address; import javax.mail.Message; import javax.mail.MessagingException; import javax.mail.SendFailedException; import javax.mail.Session; import javax.mail.Transport; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; import org.apache.commons.vfs.FileObject; import org.apache.commons.vfs.FileType; import org.pentaho.di.cluster.SlaveServer; import org.pentaho.di.core.CheckResultInterface; import org.pentaho.di.core.Const; import org.pentaho.di.core.Result; import org.pentaho.di.core.ResultFile; import org.pentaho.di.core.database.DatabaseMeta; import org.pentaho.di.core.encryption.Encr; import org.pentaho.di.core.exception.KettleDatabaseException; import org.pentaho.di.core.exception.KettleException; import org.pentaho.di.core.exception.KettleXMLException; import org.pentaho.di.core.gui.JobTracker; import org.pentaho.di.core.variables.VariableSpace; import org.pentaho.di.core.vfs.KettleVFS; import org.pentaho.di.core.xml.XMLHandler; import org.pentaho.di.i18n.BaseMessages; import org.pentaho.di.job.JobEntryResult; import org.pentaho.di.job.JobMeta; import org.pentaho.di.job.entry.JobEntryBase; import org.pentaho.di.job.entry.JobEntryInterface; import org.pentaho.di.repository.ObjectId; import org.pentaho.di.repository.Repository; import org.pentaho.di.resource.ResourceEntry; import org.pentaho.di.resource.ResourceEntry.ResourceType; import org.pentaho.di.resource.ResourceReference; import org.pentaho.metastore.api.IMetaStore; import org.w3c.dom.Node; /** * Describes a Mail Job Entry. * * @author Matt Created on 17-06-2003 * */ public class JobEntryMail extends JobEntryBase implements Cloneable, JobEntryInterface { private static Class<?> PKG = JobEntryMail.class; // for i18n purposes, needed by Translator2!! private String server; private String destination; private String destinationCc; private String destinationBCc; /** Caution : It's sender address and NOT reply address **/ private String replyAddress; /** Caution : It's sender name name and NOT reply name **/ private String replyName; private String subject; private boolean includeDate; private String contactPerson; private String contactPhone; private String comment; private boolean includingFiles; private int[] fileType; private boolean zipFiles; private String zipFilename; private boolean usingAuthentication; private String authenticationUser; private String authenticationPassword; private boolean onlySendComment; private boolean useHTML; private boolean usingSecureAuthentication; private boolean usePriority; private String port; private String priority; private String importance; private String sensitivity; private String secureConnectionType; /** The encoding to use for reading: null or empty string means system default encoding */ private String encoding; /** The reply to addresses */ private String replyToAddresses; public String[] embeddedimages; public String[] contentids; public JobEntryMail(String n) { super(n, ""); allocate(0); } public JobEntryMail() { this(""); allocate(0); } public Object clone() { JobEntryMail je = (JobEntryMail) super.clone(); return je; } public String getXML() { StringBuffer retval = new StringBuffer(300); retval.append(super.getXML()); retval.append(" ").append(XMLHandler.addTagValue("server", server)); retval.append(" ").append(XMLHandler.addTagValue("port", port)); retval.append(" ").append(XMLHandler.addTagValue("destination", destination)); retval.append(" ").append(XMLHandler.addTagValue("destinationCc", destinationCc)); retval.append(" ").append(XMLHandler.addTagValue("destinationBCc", destinationBCc)); retval.append(" ").append(XMLHandler.addTagValue("replyto", replyAddress)); retval.append(" ").append(XMLHandler.addTagValue("replytoname", replyName)); retval.append(" ").append(XMLHandler.addTagValue("subject", subject)); retval.append(" ").append(XMLHandler.addTagValue("include_date", includeDate)); retval.append(" ").append(XMLHandler.addTagValue("contact_person", contactPerson)); retval.append(" ").append(XMLHandler.addTagValue("contact_phone", contactPhone)); retval.append(" ").append(XMLHandler.addTagValue("comment", comment)); retval.append(" ").append(XMLHandler.addTagValue("include_files", includingFiles)); retval.append(" ").append(XMLHandler.addTagValue("zip_files", zipFiles)); retval.append(" ").append(XMLHandler.addTagValue("zip_name", zipFilename)); retval.append(" ").append(XMLHandler.addTagValue("use_auth", usingAuthentication)); retval.append(" ").append(XMLHandler.addTagValue("use_secure_auth", usingSecureAuthentication)); retval.append(" ").append(XMLHandler.addTagValue("auth_user", authenticationUser)); retval.append(" ").append(XMLHandler.addTagValue("auth_password", Encr.encryptPasswordIfNotUsingVariables(authenticationPassword))); retval.append(" ").append(XMLHandler.addTagValue("only_comment", onlySendComment)); retval.append(" ").append(XMLHandler.addTagValue("use_HTML", useHTML)); retval.append(" ").append(XMLHandler.addTagValue("use_Priority", usePriority)); retval.append(" ").append(XMLHandler.addTagValue("encoding", encoding)); retval.append(" ").append(XMLHandler.addTagValue("priority", priority)); retval.append(" ").append(XMLHandler.addTagValue("importance", importance)); retval.append(" ").append(XMLHandler.addTagValue("sensitivity", sensitivity)); retval.append(" ").append(XMLHandler.addTagValue("secureconnectiontype", secureConnectionType)); retval.append(" ").append(XMLHandler.addTagValue("replyToAddresses", replyToAddresses)); retval.append(" <filetypes>"); if (fileType != null) { for (int i = 0; i < fileType.length; i++) { retval.append(" ") .append(XMLHandler.addTagValue("filetype", ResultFile.getTypeCode(fileType[i]))); } } retval.append(" </filetypes>"); retval.append(" <embeddedimages>").append(Const.CR); if (embeddedimages != null) { for (int i = 0; i < embeddedimages.length; i++) { retval.append(" <embeddedimage>").append(Const.CR); retval.append(" ").append(XMLHandler.addTagValue("image_name", embeddedimages[i])); retval.append(" ").append(XMLHandler.addTagValue("content_id", contentids[i])); retval.append(" </embeddedimage>").append(Const.CR); } } retval.append(" </embeddedimages>").append(Const.CR); return retval.toString(); } public void allocate(int nrFileTypes) { fileType = new int[nrFileTypes]; } public void loadXML(Node entrynode, List<DatabaseMeta> databases, List<SlaveServer> slaveServers, Repository rep, IMetaStore metaStore) throws KettleXMLException { try { super.loadXML(entrynode, databases, slaveServers); setServer(XMLHandler.getTagValue(entrynode, "server")); setPort(XMLHandler.getTagValue(entrynode, "port")); setDestination(XMLHandler.getTagValue(entrynode, "destination")); setDestinationCc(XMLHandler.getTagValue(entrynode, "destinationCc")); setDestinationBCc(XMLHandler.getTagValue(entrynode, "destinationBCc")); setReplyAddress(XMLHandler.getTagValue(entrynode, "replyto")); setReplyName(XMLHandler.getTagValue(entrynode, "replytoname")); setSubject(XMLHandler.getTagValue(entrynode, "subject")); setIncludeDate("Y".equalsIgnoreCase(XMLHandler.getTagValue(entrynode, "include_date"))); setContactPerson(XMLHandler.getTagValue(entrynode, "contact_person")); setContactPhone(XMLHandler.getTagValue(entrynode, "contact_phone")); setComment(XMLHandler.getTagValue(entrynode, "comment")); setIncludingFiles("Y".equalsIgnoreCase(XMLHandler.getTagValue(entrynode, "include_files"))); setUsingAuthentication("Y".equalsIgnoreCase(XMLHandler.getTagValue(entrynode, "use_auth"))); setUsingSecureAuthentication( "Y".equalsIgnoreCase(XMLHandler.getTagValue(entrynode, "use_secure_auth"))); setAuthenticationUser(XMLHandler.getTagValue(entrynode, "auth_user")); setAuthenticationPassword( Encr.decryptPasswordOptionallyEncrypted(XMLHandler.getTagValue(entrynode, "auth_password"))); setOnlySendComment("Y".equalsIgnoreCase(XMLHandler.getTagValue(entrynode, "only_comment"))); setUseHTML("Y".equalsIgnoreCase(XMLHandler.getTagValue(entrynode, "use_HTML"))); setUsePriority("Y".equalsIgnoreCase(XMLHandler.getTagValue(entrynode, "use_Priority"))); setEncoding(XMLHandler.getTagValue(entrynode, "encoding")); setPriority(XMLHandler.getTagValue(entrynode, "priority")); setImportance(XMLHandler.getTagValue(entrynode, "importance")); setSensitivity(XMLHandler.getTagValue(entrynode, "sensitivity")); setSecureConnectionType(XMLHandler.getTagValue(entrynode, "secureconnectiontype")); Node ftsnode = XMLHandler.getSubNode(entrynode, "filetypes"); int nrTypes = XMLHandler.countNodes(ftsnode, "filetype"); allocate(nrTypes); for (int i = 0; i < nrTypes; i++) { Node ftnode = XMLHandler.getSubNodeByNr(ftsnode, "filetype", i); fileType[i] = ResultFile.getType(XMLHandler.getNodeValue(ftnode)); } setZipFiles("Y".equalsIgnoreCase(XMLHandler.getTagValue(entrynode, "zip_files"))); setZipFilename(XMLHandler.getTagValue(entrynode, "zip_name")); setReplyToAddresses(XMLHandler.getTagValue(entrynode, "replyToAddresses")); Node images = XMLHandler.getSubNode(entrynode, "embeddedimages"); // How many field embedded images ? int nrImages = XMLHandler.countNodes(images, "embeddedimage"); embeddedimages = new String[nrImages]; contentids = new String[nrImages]; // Read them all... for (int i = 0; i < nrImages; i++) { Node fnode = XMLHandler.getSubNodeByNr(images, "embeddedimage", i); embeddedimages[i] = XMLHandler.getTagValue(fnode, "image_name"); contentids[i] = XMLHandler.getTagValue(fnode, "content_id"); } } catch (KettleException xe) { throw new KettleXMLException("Unable to load job entry of type 'mail' from XML node", xe); } } public void loadRep(Repository rep, IMetaStore metaStore, ObjectId id_jobentry, List<DatabaseMeta> databases, List<SlaveServer> slaveServers) throws KettleException { try { // First load the common parts like name & description, then the attributes... // server = rep.getJobEntryAttributeString(id_jobentry, "server"); port = rep.getJobEntryAttributeString(id_jobentry, "port"); destination = rep.getJobEntryAttributeString(id_jobentry, "destination"); destinationCc = rep.getJobEntryAttributeString(id_jobentry, "destinationCc"); destinationBCc = rep.getJobEntryAttributeString(id_jobentry, "destinationBCc"); replyAddress = rep.getJobEntryAttributeString(id_jobentry, "replyto"); replyName = rep.getJobEntryAttributeString(id_jobentry, "replytoname"); subject = rep.getJobEntryAttributeString(id_jobentry, "subject"); includeDate = rep.getJobEntryAttributeBoolean(id_jobentry, "include_date"); contactPerson = rep.getJobEntryAttributeString(id_jobentry, "contact_person"); contactPhone = rep.getJobEntryAttributeString(id_jobentry, "contact_phone"); comment = rep.getJobEntryAttributeString(id_jobentry, "comment"); encoding = rep.getJobEntryAttributeString(id_jobentry, "encoding"); priority = rep.getJobEntryAttributeString(id_jobentry, "priority"); importance = rep.getJobEntryAttributeString(id_jobentry, "importance"); sensitivity = rep.getJobEntryAttributeString(id_jobentry, "sensitivity"); includingFiles = rep.getJobEntryAttributeBoolean(id_jobentry, "include_files"); usingAuthentication = rep.getJobEntryAttributeBoolean(id_jobentry, "use_auth"); usingSecureAuthentication = rep.getJobEntryAttributeBoolean(id_jobentry, "use_secure_auth"); authenticationUser = rep.getJobEntryAttributeString(id_jobentry, "auth_user"); authenticationPassword = Encr.decryptPasswordOptionallyEncrypted( rep.getJobEntryAttributeString(id_jobentry, "auth_password")); onlySendComment = rep.getJobEntryAttributeBoolean(id_jobentry, "only_comment"); useHTML = rep.getJobEntryAttributeBoolean(id_jobentry, "use_HTML"); usePriority = rep.getJobEntryAttributeBoolean(id_jobentry, "use_Priority"); secureConnectionType = rep.getJobEntryAttributeString(id_jobentry, "secureconnectiontype"); int nrTypes = rep.countNrJobEntryAttributes(id_jobentry, "file_type"); allocate(nrTypes); for (int i = 0; i < nrTypes; i++) { String typeCode = rep.getJobEntryAttributeString(id_jobentry, i, "file_type"); fileType[i] = ResultFile.getType(typeCode); } zipFiles = rep.getJobEntryAttributeBoolean(id_jobentry, "zip_files"); zipFilename = rep.getJobEntryAttributeString(id_jobentry, "zip_name"); replyToAddresses = rep.getJobEntryAttributeString(id_jobentry, "replyToAddresses"); // How many arguments? int imagesnr = rep.countNrJobEntryAttributes(id_jobentry, "embeddedimage"); embeddedimages = new String[imagesnr]; contentids = new String[imagesnr]; // Read them all... for (int a = 0; a < imagesnr; a++) { embeddedimages[a] = rep.getJobEntryAttributeString(id_jobentry, a, "embeddedimage"); contentids[a] = rep.getJobEntryAttributeString(id_jobentry, a, "contentid"); } } catch (KettleDatabaseException dbe) { throw new KettleException( "Unable to load job entry of type 'mail' from the repository with id_jobentry=" + id_jobentry, dbe); } } public void saveRep(Repository rep, IMetaStore metaStore, ObjectId id_job) throws KettleException { try { rep.saveJobEntryAttribute(id_job, getObjectId(), "server", server); rep.saveJobEntryAttribute(id_job, getObjectId(), "port", port); rep.saveJobEntryAttribute(id_job, getObjectId(), "destination", destination); rep.saveJobEntryAttribute(id_job, getObjectId(), "destinationCc", destinationCc); rep.saveJobEntryAttribute(id_job, getObjectId(), "destinationBCc", destinationBCc); rep.saveJobEntryAttribute(id_job, getObjectId(), "replyto", replyAddress); rep.saveJobEntryAttribute(id_job, getObjectId(), "replytoname", replyName); rep.saveJobEntryAttribute(id_job, getObjectId(), "subject", subject); rep.saveJobEntryAttribute(id_job, getObjectId(), "include_date", includeDate); rep.saveJobEntryAttribute(id_job, getObjectId(), "contact_person", contactPerson); rep.saveJobEntryAttribute(id_job, getObjectId(), "contact_phone", contactPhone); rep.saveJobEntryAttribute(id_job, getObjectId(), "comment", comment); rep.saveJobEntryAttribute(id_job, getObjectId(), "encoding", encoding); rep.saveJobEntryAttribute(id_job, getObjectId(), "priority", priority); rep.saveJobEntryAttribute(id_job, getObjectId(), "importance", importance); rep.saveJobEntryAttribute(id_job, getObjectId(), "sensitivity", sensitivity); rep.saveJobEntryAttribute(id_job, getObjectId(), "include_files", includingFiles); rep.saveJobEntryAttribute(id_job, getObjectId(), "use_auth", usingAuthentication); rep.saveJobEntryAttribute(id_job, getObjectId(), "use_secure_auth", usingSecureAuthentication); rep.saveJobEntryAttribute(id_job, getObjectId(), "auth_user", authenticationUser); rep.saveJobEntryAttribute(id_job, getObjectId(), "auth_password", Encr.encryptPasswordIfNotUsingVariables(authenticationPassword)); rep.saveJobEntryAttribute(id_job, getObjectId(), "only_comment", onlySendComment); rep.saveJobEntryAttribute(id_job, getObjectId(), "use_HTML", useHTML); rep.saveJobEntryAttribute(id_job, getObjectId(), "use_Priority", usePriority); rep.saveJobEntryAttribute(id_job, getObjectId(), "secureconnectiontype", secureConnectionType); if (fileType != null) { for (int i = 0; i < fileType.length; i++) { rep.saveJobEntryAttribute(id_job, getObjectId(), i, "file_type", ResultFile.getTypeCode(fileType[i])); } } rep.saveJobEntryAttribute(id_job, getObjectId(), "zip_files", zipFiles); rep.saveJobEntryAttribute(id_job, getObjectId(), "zip_name", zipFilename); rep.saveJobEntryAttribute(id_job, getObjectId(), "replyToAddresses", replyToAddresses); // save the arguments... if (embeddedimages != null) { for (int i = 0; i < embeddedimages.length; i++) { rep.saveJobEntryAttribute(id_job, getObjectId(), i, "embeddedimage", embeddedimages[i]); rep.saveJobEntryAttribute(id_job, getObjectId(), i, "contentid", contentids[i]); } } } catch (KettleDatabaseException dbe) { throw new KettleException( "Unable to save job entry of type 'mail' to the repository for id_job=" + id_job, dbe); } } public void setServer(String s) { server = s; } public String getServer() { return server; } public void setDestination(String dest) { destination = dest; } public void setDestinationCc(String destCc) { destinationCc = destCc; } public void setDestinationBCc(String destBCc) { destinationBCc = destBCc; } public String getDestination() { return destination; } public String getDestinationCc() { return destinationCc; } public String getDestinationBCc() { return destinationBCc; } public void setReplyAddress(String reply) { replyAddress = reply; } public String getReplyAddress() { return replyAddress; } public void setReplyName(String replyname) { this.replyName = replyname; } public String getReplyName() { return replyName; } public void setSubject(String subj) { subject = subj; } public String getSubject() { return subject; } public void setIncludeDate(boolean incl) { includeDate = incl; } public boolean getIncludeDate() { return includeDate; } public void setContactPerson(String person) { contactPerson = person; } public String getContactPerson() { return contactPerson; } public void setContactPhone(String phone) { contactPhone = phone; } public String getContactPhone() { return contactPhone; } public void setComment(String comm) { comment = comm; } public String getComment() { return comment; } /** * @return the result file types to select for attachment </b> * @see ResultFile */ public int[] getFileType() { return fileType; } /** * @param fileType * the result file types to select for attachment * @see ResultFile */ public void setFileType(int[] fileType) { this.fileType = fileType; } public boolean isIncludingFiles() { return includingFiles; } public void setIncludingFiles(boolean includeFiles) { this.includingFiles = includeFiles; } /** * @return Returns the zipFilename. */ public String getZipFilename() { return zipFilename; } /** * @param zipFilename * The zipFilename to set. */ public void setZipFilename(String zipFilename) { this.zipFilename = zipFilename; } /** * @return Returns the zipFiles. */ public boolean isZipFiles() { return zipFiles; } /** * @param zipFiles * The zipFiles to set. */ public void setZipFiles(boolean zipFiles) { this.zipFiles = zipFiles; } /** * @return Returns the authenticationPassword. */ public String getAuthenticationPassword() { return authenticationPassword; } /** * @param authenticationPassword * The authenticationPassword to set. */ public void setAuthenticationPassword(String authenticationPassword) { this.authenticationPassword = authenticationPassword; } /** * @return Returns the authenticationUser. */ public String getAuthenticationUser() { return authenticationUser; } /** * @param authenticationUser * The authenticationUser to set. */ public void setAuthenticationUser(String authenticationUser) { this.authenticationUser = authenticationUser; } /** * @return Returns the usingAuthentication. */ public boolean isUsingAuthentication() { return usingAuthentication; } /** * @param usingAuthentication * The usingAuthentication to set. */ public void setUsingAuthentication(boolean usingAuthentication) { this.usingAuthentication = usingAuthentication; } /** * @return the onlySendComment flag */ public boolean isOnlySendComment() { return onlySendComment; } /** * @param onlySendComment * the onlySendComment flag to set */ public void setOnlySendComment(boolean onlySendComment) { this.onlySendComment = onlySendComment; } /** * @return the useHTML flag */ public boolean isUseHTML() { return useHTML; } /** * @param useHTML * the useHTML to set */ public void setUseHTML(boolean useHTML) { this.useHTML = useHTML; } /** * @return the encoding */ public String getEncoding() { return encoding; } /** * @return the secure connection type */ public String getSecureConnectionType() { return secureConnectionType; } /** * @param secureConnectionType * the secure connection type to set */ public void setSecureConnectionType(String secureConnectionType) { this.secureConnectionType = secureConnectionType; } /** * @param encoding * the encoding to set */ public void setEncoding(String encoding) { this.encoding = encoding; } /** * @param secureconnectiontype * the replayToAddresses to set */ public void setReplyToAddresses(String replyToAddresses) { this.replyToAddresses = replyToAddresses; } /** * @return replayToAddresses */ public String getReplyToAddresses() { return this.replyToAddresses; } /** * @param usePriority * the usePriority to set */ public void setUsePriority(boolean usePriority) { this.usePriority = usePriority; } /** * @return the usePriority flag */ public boolean isUsePriority() { return usePriority; } /** * @return the priority */ public String getPriority() { return priority; } /** * @param importance * the importance to set */ public void setImportance(String importance) { this.importance = importance; } /** * @return the importance */ public String getImportance() { return importance; } public String getSensitivity() { return sensitivity; } public void setSensitivity(String sensitivity) { this.sensitivity = sensitivity; } /** * @param priority * the priority to set */ public void setPriority(String priority) { this.priority = priority; } public Result execute(Result result, int nr) { File masterZipfile = null; // Send an e-mail... // create some properties and get the default Session Properties props = new Properties(); if (Const.isEmpty(server)) { logError(BaseMessages.getString(PKG, "JobMail.Error.HostNotSpecified")); result.setNrErrors(1L); result.setResult(false); return result; } String protocol = "smtp"; if (usingSecureAuthentication) { if (secureConnectionType.equals("TLS")) { // Allow TLS authentication props.put("mail.smtp.starttls.enable", "true"); } else { protocol = "smtps"; // required to get rid of a SSL exception : // nested exception is: // javax.net.ssl.SSLException: Unsupported record version Unknown props.put("mail.smtps.quitwait", "false"); } } props.put("mail." + protocol + ".host", environmentSubstitute(server)); if (!Const.isEmpty(port)) { props.put("mail." + protocol + ".port", environmentSubstitute(port)); } if (log.isDebug()) { props.put("mail.debug", "true"); } if (usingAuthentication) { props.put("mail." + protocol + ".auth", "true"); /* * authenticator = new Authenticator() { protected PasswordAuthentication getPasswordAuthentication() { return new * PasswordAuthentication( StringUtil.environmentSubstitute(Const.NVL(authenticationUser, "")), * StringUtil.environmentSubstitute(Const.NVL(authenticationPassword, "")) ); } }; */ } Session session = Session.getInstance(props); session.setDebug(log.isDebug()); try { // create a message Message msg = new MimeMessage(session); // set message priority if (usePriority) { String priority_int = "1"; if (priority.equals("low")) { priority_int = "3"; } if (priority.equals("normal")) { priority_int = "2"; } msg.setHeader("X-Priority", priority_int); // (String)int between 1= high and 3 = low. msg.setHeader("Importance", importance); // seems to be needed for MS Outlook. // where it returns a string of high /normal /low. msg.setHeader("Sensitivity", sensitivity); // Possible values are normal, personal, private, company-confidential } // Set Mail sender (From) String sender_address = environmentSubstitute(replyAddress); if (!Const.isEmpty(sender_address)) { String sender_name = environmentSubstitute(replyName); if (!Const.isEmpty(sender_name)) { sender_address = sender_name + '<' + sender_address + '>'; } msg.setFrom(new InternetAddress(sender_address)); } else { throw new MessagingException(BaseMessages.getString(PKG, "JobMail.Error.ReplyEmailNotFilled")); } // set Reply to addresses String reply_to_address = environmentSubstitute(replyToAddresses); if (!Const.isEmpty(reply_to_address)) { // Split the mail-address: space separated String[] reply_Address_List = environmentSubstitute(reply_to_address).split(" "); InternetAddress[] address = new InternetAddress[reply_Address_List.length]; for (int i = 0; i < reply_Address_List.length; i++) { address[i] = new InternetAddress(reply_Address_List[i]); } msg.setReplyTo(address); } // Split the mail-address: space separated String[] destinations = environmentSubstitute(destination).split(" "); InternetAddress[] address = new InternetAddress[destinations.length]; for (int i = 0; i < destinations.length; i++) { address[i] = new InternetAddress(destinations[i]); } msg.setRecipients(Message.RecipientType.TO, address); String realCC = environmentSubstitute(getDestinationCc()); if (!Const.isEmpty(realCC)) { // Split the mail-address Cc: space separated String[] destinationsCc = realCC.split(" "); InternetAddress[] addressCc = new InternetAddress[destinationsCc.length]; for (int i = 0; i < destinationsCc.length; i++) { addressCc[i] = new InternetAddress(destinationsCc[i]); } msg.setRecipients(Message.RecipientType.CC, addressCc); } String realBCc = environmentSubstitute(getDestinationBCc()); if (!Const.isEmpty(realBCc)) { // Split the mail-address BCc: space separated String[] destinationsBCc = realBCc.split(" "); InternetAddress[] addressBCc = new InternetAddress[destinationsBCc.length]; for (int i = 0; i < destinationsBCc.length; i++) { addressBCc[i] = new InternetAddress(destinationsBCc[i]); } msg.setRecipients(Message.RecipientType.BCC, addressBCc); } String realSubject = environmentSubstitute(subject); if (!Const.isEmpty(realSubject)) { msg.setSubject(realSubject); } msg.setSentDate(new Date()); StringBuffer messageText = new StringBuffer(); String endRow = isUseHTML() ? "<br>" : Const.CR; String realComment = environmentSubstitute(comment); if (!Const.isEmpty(realComment)) { messageText.append(realComment).append(Const.CR).append(Const.CR); } if (!onlySendComment) { messageText.append(BaseMessages.getString(PKG, "JobMail.Log.Comment.Job")).append(endRow); messageText.append("-----").append(endRow); messageText.append(BaseMessages.getString(PKG, "JobMail.Log.Comment.JobName") + " : ") .append(parentJob.getJobMeta().getName()).append(endRow); messageText.append(BaseMessages.getString(PKG, "JobMail.Log.Comment.JobDirectory") + " : ") .append(parentJob.getJobMeta().getRepositoryDirectory()).append(endRow); messageText.append(BaseMessages.getString(PKG, "JobMail.Log.Comment.JobEntry") + " : ") .append(getName()).append(endRow); messageText.append(Const.CR); } if (includeDate) { messageText.append(endRow).append(BaseMessages.getString(PKG, "JobMail.Log.Comment.MsgDate") + ": ") .append(XMLHandler.date2string(new Date())).append(endRow).append(endRow); } if (!onlySendComment && result != null) { messageText.append(BaseMessages.getString(PKG, "JobMail.Log.Comment.PreviousResult") + ":") .append(endRow); messageText.append("-----------------").append(endRow); messageText.append(BaseMessages.getString(PKG, "JobMail.Log.Comment.JobEntryNr") + " : ") .append(result.getEntryNr()).append(endRow); messageText.append(BaseMessages.getString(PKG, "JobMail.Log.Comment.Errors") + " : ") .append(result.getNrErrors()).append(endRow); messageText.append(BaseMessages.getString(PKG, "JobMail.Log.Comment.LinesRead") + " : ") .append(result.getNrLinesRead()).append(endRow); messageText.append(BaseMessages.getString(PKG, "JobMail.Log.Comment.LinesWritten") + " : ") .append(result.getNrLinesWritten()).append(endRow); messageText.append(BaseMessages.getString(PKG, "JobMail.Log.Comment.LinesInput") + " : ") .append(result.getNrLinesInput()).append(endRow); messageText.append(BaseMessages.getString(PKG, "JobMail.Log.Comment.LinesOutput") + " : ") .append(result.getNrLinesOutput()).append(endRow); messageText.append(BaseMessages.getString(PKG, "JobMail.Log.Comment.LinesUpdated") + " : ") .append(result.getNrLinesUpdated()).append(endRow); messageText.append(BaseMessages.getString(PKG, "JobMail.Log.Comment.LinesRejected") + " : ") .append(result.getNrLinesRejected()).append(endRow); messageText.append(BaseMessages.getString(PKG, "JobMail.Log.Comment.Status") + " : ") .append(result.getExitStatus()).append(endRow); messageText.append(BaseMessages.getString(PKG, "JobMail.Log.Comment.Result") + " : ") .append(result.getResult()).append(endRow); messageText.append(endRow); } if (!onlySendComment && (!Const.isEmpty(environmentSubstitute(contactPerson)) || !Const.isEmpty(environmentSubstitute(contactPhone)))) { messageText.append(BaseMessages.getString(PKG, "JobMail.Log.Comment.ContactInfo") + " :") .append(endRow); messageText.append("---------------------").append(endRow); messageText.append(BaseMessages.getString(PKG, "JobMail.Log.Comment.PersonToContact") + " : ") .append(environmentSubstitute(contactPerson)).append(endRow); messageText.append(BaseMessages.getString(PKG, "JobMail.Log.Comment.Tel") + " : ") .append(environmentSubstitute(contactPhone)).append(endRow); messageText.append(endRow); } // Include the path to this job entry... if (!onlySendComment) { JobTracker jobTracker = parentJob.getJobTracker(); if (jobTracker != null) { messageText.append(BaseMessages.getString(PKG, "JobMail.Log.Comment.PathToJobentry") + ":") .append(endRow); messageText.append("------------------------").append(endRow); addBacktracking(jobTracker, messageText); if (isUseHTML()) { messageText.replace(0, messageText.length(), messageText.toString().replace(Const.CR, endRow)); } } } MimeMultipart parts = new MimeMultipart(); MimeBodyPart part1 = new MimeBodyPart(); // put the text in the // Attached files counter int nrattachedFiles = 0; // 1st part if (useHTML) { if (!Const.isEmpty(getEncoding())) { part1.setContent(messageText.toString(), "text/html; " + "charset=" + getEncoding()); } else { part1.setContent(messageText.toString(), "text/html; " + "charset=ISO-8859-1"); } } else { part1.setText(messageText.toString()); } parts.addBodyPart(part1); if (includingFiles && result != null) { List<ResultFile> resultFiles = result.getResultFilesList(); if (resultFiles != null && !resultFiles.isEmpty()) { if (!zipFiles) { // Add all files to the message... // for (ResultFile resultFile : resultFiles) { FileObject file = resultFile.getFile(); if (file != null && file.exists()) { boolean found = false; for (int i = 0; i < fileType.length; i++) { if (fileType[i] == resultFile.getType()) { found = true; } } if (found) { // create a data source MimeBodyPart files = new MimeBodyPart(); URLDataSource fds = new URLDataSource(file.getURL()); // get a data Handler to manipulate this file type; files.setDataHandler(new DataHandler(fds)); // include the file in the data source files.setFileName(file.getName().getBaseName()); // insist on base64 to preserve line endings files.addHeader("Content-Transfer-Encoding", "base64"); // add the part with the file in the BodyPart(); parts.addBodyPart(files); nrattachedFiles++; logBasic("Added file '" + fds.getName() + "' to the mail message."); } } } } else { // create a single ZIP archive of all files masterZipfile = new File(System.getProperty("java.io.tmpdir") + Const.FILE_SEPARATOR + environmentSubstitute(zipFilename)); ZipOutputStream zipOutputStream = null; try { zipOutputStream = new ZipOutputStream(new FileOutputStream(masterZipfile)); for (ResultFile resultFile : resultFiles) { boolean found = false; for (int i = 0; i < fileType.length; i++) { if (fileType[i] == resultFile.getType()) { found = true; } } if (found) { FileObject file = resultFile.getFile(); ZipEntry zipEntry = new ZipEntry(file.getName().getBaseName()); zipOutputStream.putNextEntry(zipEntry); // Now put the content of this file into this archive... BufferedInputStream inputStream = new BufferedInputStream( KettleVFS.getInputStream(file)); try { int c; while ((c = inputStream.read()) >= 0) { zipOutputStream.write(c); } } finally { inputStream.close(); } zipOutputStream.closeEntry(); nrattachedFiles++; logBasic("Added file '" + file.getName().getURI() + "' to the mail message in a zip archive."); } } } catch (Exception e) { logError("Error zipping attachement files into file [" + masterZipfile.getPath() + "] : " + e.toString()); logError(Const.getStackTracker(e)); result.setNrErrors(1); } finally { if (zipOutputStream != null) { try { zipOutputStream.finish(); zipOutputStream.close(); } catch (IOException e) { logError("Unable to close attachement zip file archive : " + e.toString()); logError(Const.getStackTracker(e)); result.setNrErrors(1); } } } // Now attach the master zip file to the message. if (result.getNrErrors() == 0) { // create a data source MimeBodyPart files = new MimeBodyPart(); FileDataSource fds = new FileDataSource(masterZipfile); // get a data Handler to manipulate this file type; files.setDataHandler(new DataHandler(fds)); // include the file in the data source files.setFileName(fds.getName()); // add the part with the file in the BodyPart(); parts.addBodyPart(files); } } } } int nrEmbeddedImages = 0; if (embeddedimages != null && embeddedimages.length > 0) { FileObject imageFile = null; for (int i = 0; i < embeddedimages.length; i++) { String realImageFile = environmentSubstitute(embeddedimages[i]); String realcontenID = environmentSubstitute(contentids[i]); if (messageText.indexOf("cid:" + realcontenID) < 0) { if (log.isDebug()) { log.logDebug("Image [" + realImageFile + "] is not used in message body!"); } } else { try { boolean found = false; imageFile = KettleVFS.getFileObject(realImageFile, this); if (imageFile.exists() && imageFile.getType() == FileType.FILE) { found = true; } else { log.logError("We can not find [" + realImageFile + "] or it is not a file"); } if (found) { // Create part for the image MimeBodyPart messageBodyPart = new MimeBodyPart(); // Load the image URLDataSource fds = new URLDataSource(imageFile.getURL()); messageBodyPart.setDataHandler(new DataHandler(fds)); // Setting the header messageBodyPart.setHeader("Content-ID", "<" + realcontenID + ">"); // Add part to multi-part parts.addBodyPart(messageBodyPart); nrEmbeddedImages++; log.logBasic("Image '" + fds.getName() + "' was embedded in message."); } } catch (Exception e) { log.logError( "Error embedding image [" + realImageFile + "] in message : " + e.toString()); log.logError(Const.getStackTracker(e)); result.setNrErrors(1); } finally { if (imageFile != null) { try { imageFile.close(); } catch (Exception e) { /* Ignore */ } } } } } } if (nrEmbeddedImages > 0 && nrattachedFiles == 0) { // If we need to embedd images... // We need to create a "multipart/related" message. // otherwise image will appear as attached file parts.setSubType("related"); } // put all parts together msg.setContent(parts); Transport transport = null; try { transport = session.getTransport(protocol); String authPass = getPassword(authenticationPassword); if (usingAuthentication) { if (!Const.isEmpty(port)) { transport.connect(environmentSubstitute(Const.NVL(server, "")), Integer.parseInt(environmentSubstitute(Const.NVL(port, ""))), environmentSubstitute(Const.NVL(authenticationUser, "")), authPass); } else { transport.connect(environmentSubstitute(Const.NVL(server, "")), environmentSubstitute(Const.NVL(authenticationUser, "")), authPass); } } else { transport.connect(); } transport.sendMessage(msg, msg.getAllRecipients()); } finally { if (transport != null) { transport.close(); } } } catch (IOException e) { logError("Problem while sending message: " + e.toString()); result.setNrErrors(1); } catch (MessagingException mex) { logError("Problem while sending message: " + mex.toString()); result.setNrErrors(1); Exception ex = mex; do { if (ex instanceof SendFailedException) { SendFailedException sfex = (SendFailedException) ex; Address[] invalid = sfex.getInvalidAddresses(); if (invalid != null) { logError(" ** Invalid Addresses"); for (int i = 0; i < invalid.length; i++) { logError(" " + invalid[i]); result.setNrErrors(1); } } Address[] validUnsent = sfex.getValidUnsentAddresses(); if (validUnsent != null) { logError(" ** ValidUnsent Addresses"); for (int i = 0; i < validUnsent.length; i++) { logError(" " + validUnsent[i]); result.setNrErrors(1); } } Address[] validSent = sfex.getValidSentAddresses(); if (validSent != null) { // System.out.println(" ** ValidSent Addresses"); for (int i = 0; i < validSent.length; i++) { logError(" " + validSent[i]); result.setNrErrors(1); } } } if (ex instanceof MessagingException) { ex = ((MessagingException) ex).getNextException(); } else { ex = null; } } while (ex != null); } finally { if (masterZipfile != null && masterZipfile.exists()) { masterZipfile.delete(); } } if (result.getNrErrors() > 0) { result.setResult(false); } else { result.setResult(true); } return result; } private void addBacktracking(JobTracker jobTracker, StringBuffer messageText) { addBacktracking(jobTracker, messageText, 0); } private void addBacktracking(JobTracker jobTracker, StringBuffer messageText, int level) { int nr = jobTracker.nrJobTrackers(); messageText.append(Const.rightPad(" ", level * 2)); messageText.append(Const.NVL(jobTracker.getJobName(), "-")); JobEntryResult jer = jobTracker.getJobEntryResult(); if (jer != null) { messageText.append(" : "); if (jer.getJobEntryName() != null) { messageText.append(" : "); messageText.append(jer.getJobEntryName()); } if (jer.getResult() != null) { messageText.append(" : "); messageText.append("[" + jer.getResult().toString() + "]"); } if (jer.getReason() != null) { messageText.append(" : "); messageText.append(jer.getReason()); } if (jer.getComment() != null) { messageText.append(" : "); messageText.append(jer.getComment()); } if (jer.getLogDate() != null) { messageText.append(" ("); messageText.append(XMLHandler.date2string(jer.getLogDate())); messageText.append(')'); } } messageText.append(Const.CR); for (int i = 0; i < nr; i++) { JobTracker jt = jobTracker.getJobTracker(i); addBacktracking(jt, messageText, level + 1); } } public boolean evaluates() { return true; } public boolean isUnconditional() { return true; } /** * @return the usingSecureAuthentication */ public boolean isUsingSecureAuthentication() { return usingSecureAuthentication; } /** * @param usingSecureAuthentication * the usingSecureAuthentication to set */ public void setUsingSecureAuthentication(boolean usingSecureAuthentication) { this.usingSecureAuthentication = usingSecureAuthentication; } /** * @return the port */ public String getPort() { return port; } /** * @param port * the port to set */ public void setPort(String port) { this.port = port; } public List<ResourceReference> getResourceDependencies(JobMeta jobMeta) { List<ResourceReference> references = super.getResourceDependencies(jobMeta); String realServername = jobMeta.environmentSubstitute(server); ResourceReference reference = new ResourceReference(this); reference.getEntries().add(new ResourceEntry(realServername, ResourceType.SERVER)); references.add(reference); return references; } @Override public void check(List<CheckResultInterface> remarks, JobMeta jobMeta, VariableSpace space, Repository repository, IMetaStore metaStore) { andValidator().validate(this, "server", remarks, putValidators(notBlankValidator())); andValidator().validate(this, "replyAddress", remarks, putValidators(notBlankValidator(), emailValidator())); andValidator().validate(this, "destination", remarks, putValidators(notBlankValidator())); if (usingAuthentication) { andValidator().validate(this, "authenticationUser", remarks, putValidators(notBlankValidator())); andValidator().validate(this, "authenticationPassword", remarks, putValidators(notNullValidator())); } andValidator().validate(this, "port", remarks, putValidators(integerValidator())); } public String getPassword(String authPassword) { return Encr.decryptPasswordOptionallyEncrypted(environmentSubstitute(Const.NVL(authPassword, ""))); } }