org.pentaho.di.trans.steps.mail.Mail.java Source code

Java tutorial

Introduction

Here is the source code for org.pentaho.di.trans.steps.mail.Mail.java

Source

/*! ******************************************************************************
 *
 * 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.trans.steps.mail;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.activation.DataHandler;
import javax.activation.URLDataSource;
import javax.mail.Message;
import javax.mail.MessagingException;
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 javax.mail.util.ByteArrayDataSource;

import org.apache.commons.vfs.FileObject;
import org.apache.commons.vfs.FileSelectInfo;
import org.apache.commons.vfs.FileSelector;
import org.apache.commons.vfs.FileType;
import org.pentaho.di.core.Const;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.core.logging.LogChannelInterface;
import org.pentaho.di.core.vfs.KettleVFS;
import org.pentaho.di.core.xml.XMLHandler;
import org.pentaho.di.i18n.BaseMessages;
import org.pentaho.di.trans.Trans;
import org.pentaho.di.trans.TransMeta;
import org.pentaho.di.trans.step.BaseStep;
import org.pentaho.di.trans.step.StepDataInterface;
import org.pentaho.di.trans.step.StepInterface;
import org.pentaho.di.trans.step.StepMeta;
import org.pentaho.di.trans.step.StepMetaInterface;

/**
 * Send mail step. based on Mail job entry
 *
 * @author Samatar
 * @since 28-07-2008
 */

public class Mail extends BaseStep implements StepInterface {
    private static Class<?> PKG = MailMeta.class; // for i18n purposes, needed by Translator2!!

    private MailMeta meta;
    private MailData data;

    public Mail(StepMeta stepMeta, StepDataInterface stepDataInterface, int copyNr, TransMeta transMeta,
            Trans trans) {
        super(stepMeta, stepDataInterface, copyNr, transMeta, trans);
    }

    public boolean processRow(StepMetaInterface smi, StepDataInterface sdi) throws KettleException {
        meta = (MailMeta) smi;
        data = (MailData) sdi;

        Object[] r = getRow(); // get row, set busy!
        if (r == null) { // no more input to be expected...

            setOutputDone();
            return false;
        }

        if (first) {
            first = false;

            // get the RowMeta
            data.previousRowMeta = getInputRowMeta().clone();

            // Check is filename field is provided
            if (Const.isEmpty(meta.getDestination())) {
                throw new KettleException(BaseMessages.getString(PKG, "Mail.Log.DestinationFieldEmpty"));
            }

            // Check is replyname field is provided
            if (Const.isEmpty(meta.getReplyAddress())) {
                throw new KettleException(BaseMessages.getString(PKG, "Mail.Log.ReplyFieldEmpty"));
            }

            // Check is SMTP server is provided
            if (Const.isEmpty(meta.getServer())) {
                throw new KettleException(BaseMessages.getString(PKG, "Mail.Log.ServerFieldEmpty"));
            }

            // Check Attached filenames when dynamic
            if (meta.isDynamicFilename() && Const.isEmpty(meta.getDynamicFieldname())) {
                throw new KettleException(BaseMessages.getString(PKG, "Mail.Log.DynamicFilenameFielddEmpty"));
            }

            // Check Attached zipfilename when dynamic
            if (meta.isZipFilenameDynamic() && Const.isEmpty(meta.getDynamicZipFilenameField())) {
                throw new KettleException(BaseMessages.getString(PKG, "Mail.Log.DynamicZipFilenameFieldEmpty"));
            }

            if (meta.isZipFiles() && Const.isEmpty(meta.getZipFilename())) {
                throw new KettleException(BaseMessages.getString(PKG, "Mail.Log.ZipFilenameEmpty"));
            }

            // check authentication
            if (meta.isUsingAuthentication()) {
                // check authentication user
                if (Const.isEmpty(meta.getAuthenticationUser())) {
                    throw new KettleException(BaseMessages.getString(PKG, "Mail.Log.AuthenticationUserFieldEmpty"));
                }

                // check authentication pass
                if (Const.isEmpty(meta.getAuthenticationPassword())) {
                    throw new KettleException(
                            BaseMessages.getString(PKG, "Mail.Log.AuthenticationPasswordFieldEmpty"));
                }
            }

            // cache the position of the destination field
            if (data.indexOfDestination < 0) {
                String realDestinationFieldname = meta.getDestination();
                data.indexOfDestination = data.previousRowMeta.indexOfValue(realDestinationFieldname);
                if (data.indexOfDestination < 0) {
                    throw new KettleException(BaseMessages.getString(PKG,
                            "Mail.Exception.CouldnotFindDestinationField", realDestinationFieldname));
                }
            }

            // Cc
            if (!Const.isEmpty(meta.getDestinationCc())) {
                // cache the position of the Cc field
                if (data.indexOfDestinationCc < 0) {
                    String realDestinationCcFieldname = meta.getDestinationCc();
                    data.indexOfDestinationCc = data.previousRowMeta.indexOfValue(realDestinationCcFieldname);
                    if (data.indexOfDestinationCc < 0) {
                        throw new KettleException(BaseMessages.getString(PKG,
                                "Mail.Exception.CouldnotFindDestinationCcField", realDestinationCcFieldname));
                    }
                }
            }
            // BCc
            if (!Const.isEmpty(meta.getDestinationBCc())) {
                // cache the position of the BCc field
                if (data.indexOfDestinationBCc < 0) {
                    String realDestinationBCcFieldname = meta.getDestinationBCc();
                    data.indexOfDestinationBCc = data.previousRowMeta.indexOfValue(realDestinationBCcFieldname);
                    if (data.indexOfDestinationBCc < 0) {
                        throw new KettleException(BaseMessages.getString(PKG,
                                "Mail.Exception.CouldnotFindDestinationBCcField", realDestinationBCcFieldname));
                    }
                }
            }
            // Sender Name
            if (!Const.isEmpty(meta.getReplyName())) {
                // cache the position of the sender field
                if (data.indexOfSenderName < 0) {
                    String realSenderName = meta.getReplyName();
                    data.indexOfSenderName = data.previousRowMeta.indexOfValue(realSenderName);
                    if (data.indexOfSenderName < 0) {
                        throw new KettleException(BaseMessages.getString(PKG,
                                "Mail.Exception.CouldnotFindReplyNameField", realSenderName));
                    }
                }
            }
            // Sender address
            // cache the position of the sender field
            if (data.indexOfSenderAddress < 0) {
                String realSenderAddress = meta.getReplyAddress();
                data.indexOfSenderAddress = data.previousRowMeta.indexOfValue(realSenderAddress);
                if (data.indexOfSenderAddress < 0) {
                    throw new KettleException(BaseMessages.getString(PKG,
                            "Mail.Exception.CouldnotFindReplyAddressField", realSenderAddress));
                }
            }

            // Reply to
            if (!Const.isEmpty(meta.getReplyToAddresses())) {
                // cache the position of the reply to field
                if (data.indexOfReplyToAddresses < 0) {
                    String realReplyToAddresses = meta.getReplyToAddresses();
                    data.indexOfReplyToAddresses = data.previousRowMeta.indexOfValue(realReplyToAddresses);
                    if (data.indexOfReplyToAddresses < 0) {
                        throw new KettleException(BaseMessages.getString(PKG,
                                "Mail.Exception.CouldnotFindReplyToAddressesField", realReplyToAddresses));
                    }
                }
            }

            // Contact Person
            if (!Const.isEmpty(meta.getContactPerson())) {
                // cache the position of the destination field
                if (data.indexOfContactPerson < 0) {
                    String realContactPerson = meta.getContactPerson();
                    data.indexOfContactPerson = data.previousRowMeta.indexOfValue(realContactPerson);
                    if (data.indexOfContactPerson < 0) {
                        throw new KettleException(BaseMessages.getString(PKG,
                                "Mail.Exception.CouldnotFindContactPersonField", realContactPerson));
                    }
                }
            }
            // Contact Phone
            if (!Const.isEmpty(meta.getContactPhone())) {
                // cache the position of the destination field
                if (data.indexOfContactPhone < 0) {
                    String realContactPhone = meta.getContactPhone();
                    data.indexOfContactPhone = data.previousRowMeta.indexOfValue(realContactPhone);
                    if (data.indexOfContactPhone < 0) {
                        throw new KettleException(BaseMessages.getString(PKG,
                                "Mail.Exception.CouldnotFindContactPhoneField", realContactPhone));
                    }
                }
            }
            // cache the position of the Server field
            if (data.indexOfServer < 0) {
                String realServer = meta.getServer();
                data.indexOfServer = data.previousRowMeta.indexOfValue(realServer);
                if (data.indexOfServer < 0) {
                    throw new KettleException(
                            BaseMessages.getString(PKG, "Mail.Exception.CouldnotFindServerField", realServer));
                }
            }
            // Port
            if (!Const.isEmpty(meta.getPort())) {
                // cache the position of the port field
                if (data.indexOfPort < 0) {
                    String realPort = meta.getPort();
                    data.indexOfPort = data.previousRowMeta.indexOfValue(realPort);
                    if (data.indexOfPort < 0) {
                        throw new KettleException(
                                BaseMessages.getString(PKG, "Mail.Exception.CouldnotFindPortField", realPort));
                    }
                }
            }
            // Authentication
            if (meta.isUsingAuthentication()) {
                // cache the position of the Authentication user field
                if (data.indexOfAuthenticationUser < 0) {
                    String realAuthenticationUser = meta.getAuthenticationUser();
                    data.indexOfAuthenticationUser = data.previousRowMeta.indexOfValue(realAuthenticationUser);
                    if (data.indexOfAuthenticationUser < 0) {
                        throw new KettleException(BaseMessages.getString(PKG,
                                "Mail.Exception.CouldnotFindAuthenticationUserField", realAuthenticationUser));
                    }
                }

                // cache the position of the Authentication password field
                if (data.indexOfAuthenticationPass < 0) {
                    String realAuthenticationPassword = meta.getAuthenticationPassword();
                    data.indexOfAuthenticationPass = data.previousRowMeta.indexOfValue(realAuthenticationPassword);
                    if (data.indexOfAuthenticationPass < 0) {
                        throw new KettleException(BaseMessages.getString(PKG,
                                "Mail.Exception.CouldnotFindAuthenticationPassField", realAuthenticationPassword));
                    }
                }
            }
            // Mail Subject
            if (!Const.isEmpty(meta.getSubject())) {
                // cache the position of the subject field
                if (data.indexOfSubject < 0) {
                    String realSubject = meta.getSubject();
                    data.indexOfSubject = data.previousRowMeta.indexOfValue(realSubject);
                    if (data.indexOfSubject < 0) {
                        throw new KettleException(BaseMessages.getString(PKG,
                                "Mail.Exception.CouldnotFindSubjectField", realSubject));
                    }
                }
            }
            // Mail Comment
            if (!Const.isEmpty(meta.getComment())) {
                // cache the position of the comment field
                if (data.indexOfComment < 0) {
                    String realComment = meta.getComment();
                    data.indexOfComment = data.previousRowMeta.indexOfValue(realComment);
                    if (data.indexOfComment < 0) {
                        throw new KettleException(BaseMessages.getString(PKG,
                                "Mail.Exception.CouldnotFindCommentField", realComment));
                    }
                }
            }

            if (meta.isAttachContentFromField()) {
                // We are dealing with file content directly loaded from file
                // and not physical file
                String attachedContentField = meta.getAttachContentField();
                if (Const.isEmpty(attachedContentField)) {
                    // Empty Field
                    throw new KettleException(
                            BaseMessages.getString(PKG, "Mail.Exception.AttachedContentFieldEmpty"));
                }
                data.indexOfAttachedContent = data.previousRowMeta.indexOfValue(attachedContentField);
                if (data.indexOfComment < 0) {
                    throw new KettleException(BaseMessages.getString(PKG,
                            "Mail.Exception.CouldnotFindAttachedContentField", attachedContentField));
                }
                // Attached content filename
                String attachedContentFileNameField = meta.getAttachContentFileNameField();
                if (Const.isEmpty(attachedContentFileNameField)) {
                    // Empty Field
                    throw new KettleException(
                            BaseMessages.getString(PKG, "Mail.Exception.AttachedContentFileNameFieldEmpty"));
                }
                data.IndexOfAttachedFilename = data.previousRowMeta.indexOfValue(attachedContentFileNameField);
                if (data.indexOfComment < 0) {
                    throw new KettleException(
                            BaseMessages.getString(PKG, "Mail.Exception.CouldnotFindAttachedContentFileNameField",
                                    attachedContentFileNameField));
                }

            } else {

                // Dynamic Zipfilename
                if (meta.isZipFilenameDynamic()) {
                    // cache the position of the attached source filename field
                    if (data.indexOfDynamicZipFilename < 0) {
                        String realZipFilename = meta.getDynamicZipFilenameField();
                        data.indexOfDynamicZipFilename = data.previousRowMeta.indexOfValue(realZipFilename);
                        if (data.indexOfDynamicZipFilename < 0) {
                            throw new KettleException(BaseMessages.getString(PKG,
                                    "Mail.Exception.CouldnotSourceAttachedZipFilenameField", realZipFilename));
                        }
                    }
                }
                data.zipFileLimit = Const.toLong(environmentSubstitute(meta.getZipLimitSize()), 0);
                if (data.zipFileLimit > 0) {
                    data.zipFileLimit = data.zipFileLimit * 1048576; // Mo
                }

                if (!meta.isZipFilenameDynamic()) {
                    data.ZipFilename = environmentSubstitute(meta.getZipFilename());
                }

                // Attached files
                if (meta.isDynamicFilename()) {
                    // cache the position of the attached source filename field
                    if (data.indexOfSourceFilename < 0) {
                        String realSourceattachedFilename = meta.getDynamicFieldname();
                        data.indexOfSourceFilename = data.previousRowMeta.indexOfValue(realSourceattachedFilename);
                        if (data.indexOfSourceFilename < 0) {
                            throw new KettleException(BaseMessages.getString(PKG,
                                    "Mail.Exception.CouldnotSourceAttachedFilenameField",
                                    realSourceattachedFilename));
                        }
                    }

                    // cache the position of the attached wildcard field
                    if (!Const.isEmpty(meta.getSourceWildcard())) {
                        if (data.indexOfSourceWildcard < 0) {
                            String realSourceattachedWildcard = meta.getDynamicWildcard();
                            data.indexOfSourceWildcard = data.previousRowMeta
                                    .indexOfValue(realSourceattachedWildcard);
                            if (data.indexOfSourceWildcard < 0) {
                                throw new KettleException(
                                        BaseMessages.getString(PKG, "Mail.Exception.CouldnotSourceAttachedWildcard",
                                                realSourceattachedWildcard));
                            }
                        }
                    }
                } else {
                    // static attached filenames
                    data.realSourceFileFoldername = environmentSubstitute(meta.getSourceFileFoldername());
                    data.realSourceWildcard = environmentSubstitute(meta.getSourceWildcard());
                }
            }

            // check embedded images
            if (meta.getEmbeddedImages() != null && meta.getEmbeddedImages().length > 0) {
                FileObject image = null;
                data.embeddedMimePart = new HashSet<MimeBodyPart>();
                try {
                    for (int i = 0; i < meta.getEmbeddedImages().length; i++) {
                        String imageFile = environmentSubstitute(meta.getEmbeddedImages()[i]);
                        String contentID = environmentSubstitute(meta.getContentIds()[i]);
                        image = KettleVFS.getFileObject(imageFile);

                        if (image.exists() && image.getType() == FileType.FILE) {
                            // Create part for the image
                            MimeBodyPart imagePart = new MimeBodyPart();
                            // Load the image
                            URLDataSource fds = new URLDataSource(image.getURL());
                            imagePart.setDataHandler(new DataHandler(fds));
                            // Setting the header
                            imagePart.setHeader("Content-ID", "<" + contentID + ">");
                            // keep this part for further user
                            data.embeddedMimePart.add(imagePart);
                            logBasic(BaseMessages.getString(PKG, "Mail.Log.ImageAdded", imageFile));

                        } else {
                            logError(BaseMessages.getString(PKG, "Mail.Log.WrongImage", imageFile));
                        }
                    }
                } catch (Exception e) {
                    logError(BaseMessages.getString(PKG, "Mail.Error.AddingImage", e.getMessage()));
                } finally {
                    if (image != null) {
                        try {
                            image.close();
                        } catch (Exception e) { /* Ignore */
                        }
                    }
                }
            }

        } // end if first

        boolean sendToErrorRow = false;
        String errorMessage = null;

        try {
            // get values
            String maildestination = data.previousRowMeta.getString(r, data.indexOfDestination);
            if (Const.isEmpty(maildestination)) {
                throw new KettleException("Mail.Error.MailDestinationEmpty");
            }
            String maildestinationCc = null;
            if (data.indexOfDestinationCc > -1) {
                maildestinationCc = data.previousRowMeta.getString(r, data.indexOfDestinationCc);
            }
            String maildestinationBCc = null;
            if (data.indexOfDestinationBCc > -1) {
                maildestinationBCc = data.previousRowMeta.getString(r, data.indexOfDestinationBCc);
            }

            String mailsendername = null;
            if (data.indexOfSenderName > -1) {
                mailsendername = data.previousRowMeta.getString(r, data.indexOfSenderName);
            }
            String mailsenderaddress = data.previousRowMeta.getString(r, data.indexOfSenderAddress);

            // reply addresses
            String mailreplyToAddresses = null;
            if (data.indexOfReplyToAddresses > -1) {
                mailreplyToAddresses = data.previousRowMeta.getString(r, data.indexOfReplyToAddresses);
            }

            String contactperson = null;
            if (data.indexOfContactPerson > -1) {
                contactperson = data.previousRowMeta.getString(r, data.indexOfContactPerson);
            }
            String contactphone = null;
            if (data.indexOfContactPhone > -1) {
                contactphone = data.previousRowMeta.getString(r, data.indexOfContactPhone);
            }

            String servername = data.previousRowMeta.getString(r, data.indexOfServer);
            if (Const.isEmpty(servername)) {
                throw new KettleException("Mail.Error.MailServerEmpty");
            }
            int port = -1;
            if (data.indexOfPort > -1) {
                port = Const.toInt("" + data.previousRowMeta.getInteger(r, data.indexOfPort), -1);
            }

            String authuser = null;
            if (data.indexOfAuthenticationUser > -1) {
                authuser = data.previousRowMeta.getString(r, data.indexOfAuthenticationUser);
            }
            String authpass = null;
            if (data.indexOfAuthenticationPass > -1) {
                authpass = data.previousRowMeta.getString(r, data.indexOfAuthenticationPass);
            }

            String subject = null;
            if (data.indexOfSubject > -1) {
                subject = data.previousRowMeta.getString(r, data.indexOfSubject);
            }

            String comment = null;
            if (data.indexOfComment > -1) {
                comment = data.previousRowMeta.getString(r, data.indexOfComment);
            }

            // send email...
            sendMail(r, servername, port, mailsenderaddress, mailsendername, maildestination, maildestinationCc,
                    maildestinationBCc, contactperson, contactphone, authuser, authpass, subject, comment,
                    mailreplyToAddresses);

            putRow(getInputRowMeta(), r); // copy row to possible alternate rowset(s).); // copy row to output rowset(s);

            if (log.isRowLevel()) {
                logRowlevel(BaseMessages.getString(PKG, "Mail.Log.LineNumber",
                        getLinesRead() + " : " + getInputRowMeta().getString(r)));
            }

        } catch (Exception e) {
            if (getStepMeta().isDoingErrorHandling()) {
                sendToErrorRow = true;
                errorMessage = e.toString();
            } else {
                throw new KettleException(BaseMessages.getString(PKG, "Mail.Error.General"), e);
            }
            if (sendToErrorRow) {
                // Simply add this row to the error row
                putError(getInputRowMeta(), r, 1, errorMessage, null, "MAIL001");
            }
        }

        return true;
    }

    public void sendMail(Object[] r, String server, int port, String senderAddress, String senderName,
            String destination, String destinationCc, String destinationBCc, String contactPerson,
            String contactPhone, String authenticationUser, String authenticationPassword, String mailsubject,
            String comment, String replyToAddresses) throws Exception {

        // Send an e-mail...
        // create some properties and get the default Session

        String protocol = "smtp";
        if (meta.isUsingSecureAuthentication()) { // PDI-2955
            // if (meta.isUsingAuthentication()) {
            if (meta.getSecureConnectionType().equals("TLS")) {
                // Allow TLS authentication
                data.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
                data.props.put("mail.smtps.quitwait", "false");
            }
        }
        data.props.put("mail." + protocol + ".host", server);
        if (port != -1) {
            data.props.put("mail." + protocol + ".port", "" + port); // needs to be supplied as a string, not as an integer
        }

        if (isDebug()) {
            data.props.put("mail.debug", "true");
        }

        if (meta.isUsingAuthentication()) {
            data.props.put("mail." + protocol + ".auth", "true");
        }

        Session session = Session.getInstance(data.props);
        session.setDebug(isDebug());

        // create a message
        Message msg = new MimeMessage(session);

        // set message priority
        if (meta.isUsePriority()) {
            String priority_int = "1";
            if (meta.getPriority().equals("low")) {
                priority_int = "3";
            }
            if (meta.getPriority().equals("normal")) {
                priority_int = "2";
            }

            msg.setHeader("X-Priority", priority_int); // (String)int between 1= high and 3 = low.
            msg.setHeader("Importance", meta.getImportance());
            // seems to be needed for MS Outlook.
            // where it returns a string of high /normal /low.
            msg.setHeader("Sensitivity", meta.getSensitivity());
            // Possible values are normal, personal, private, company-confidential
        }

        // set Email sender
        String email_address = senderAddress;
        if (!Const.isEmpty(email_address)) {
            // get sender name
            if (!Const.isEmpty(senderName)) {
                email_address = senderName + '<' + email_address + '>';
            }
            msg.setFrom(new InternetAddress(email_address));
        } else {
            throw new MessagingException(BaseMessages.getString(PKG, "Mail.Error.ReplyEmailNotFilled"));
        }

        // Set reply to
        if (!Const.isEmpty(replyToAddresses)) {
            // get replay to
            // Split the mail-address: space separated
            String[] reply_Address_List = replyToAddresses.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]);
            }

            // To add the real reply-to
            msg.setReplyTo(address);
        }

        // Split the mail-address: space separated
        String[] destinations = 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 realdestinationCc = destinationCc;
        if (!Const.isEmpty(realdestinationCc)) {
            // Split the mail-address Cc: space separated
            String[] destinationsCc = realdestinationCc.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 realdestinationBCc = destinationBCc;
        if (!Const.isEmpty(realdestinationBCc)) {
            // Split the mail-address BCc: space separated
            String[] destinationsBCc = realdestinationBCc.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);
        }

        if (mailsubject != null) {
            msg.setSubject(mailsubject);
        }

        msg.setSentDate(new Date());
        StringBuffer messageText = new StringBuffer();

        if (comment != null) {
            messageText.append(comment).append(Const.CR).append(Const.CR);
        }

        if (meta.getIncludeDate()) {
            messageText.append(BaseMessages.getString(PKG, "Mail.Log.Comment.MsgDate") + ": ")
                    .append(XMLHandler.date2string(new Date())).append(Const.CR).append(Const.CR);
        }

        if (!meta.isOnlySendComment() && (!Const.isEmpty(contactPerson) || !Const.isEmpty(contactPhone))) {
            messageText.append(BaseMessages.getString(PKG, "Mail.Log.Comment.ContactInfo") + " :").append(Const.CR);
            messageText.append("---------------------").append(Const.CR);
            messageText.append(BaseMessages.getString(PKG, "Mail.Log.Comment.PersonToContact") + " : ")
                    .append(contactPerson).append(Const.CR);
            messageText.append(BaseMessages.getString(PKG, "Mail.Log.Comment.Tel") + "  : ").append(contactPhone)
                    .append(Const.CR);
            messageText.append(Const.CR);
        }
        data.parts = new MimeMultipart();

        MimeBodyPart part1 = new MimeBodyPart(); // put the text in the
        // 1st part

        if (meta.isUseHTML()) {
            if (!Const.isEmpty(meta.getEncoding())) {
                part1.setContent(messageText.toString(), "text/html; " + "charset=" + meta.getEncoding());
            } else {
                part1.setContent(messageText.toString(), "text/html; " + "charset=ISO-8859-1");
            }
        } else {
            part1.setText(messageText.toString());
        }

        data.parts.addBodyPart(part1);

        if (meta.isAttachContentFromField()) {
            // attache file content
            addAttachedContent(data.previousRowMeta.getString(r, data.IndexOfAttachedFilename),
                    data.previousRowMeta.getString(r, data.indexOfAttachedContent));
        } else {
            // attached files
            if (meta.isDynamicFilename()) {
                setAttachedFilesList(r, log);
            } else {
                setAttachedFilesList(null, log);
            }
        }

        // add embedded images
        addImagePart();

        if (data.nrEmbeddedImages > 0 && data.nrattachedFiles == 0) {
            // If we need to embedd images...
            // We need to create a "multipart/related" message.
            // otherwise image will appear as attached file
            data.parts.setSubType("related");
        }

        msg.setContent(data.parts);

        Transport transport = null;
        try {
            transport = session.getTransport(protocol);
            if (meta.isUsingAuthentication()) {
                if (port != -1) {
                    transport.connect(Const.NVL(server, ""), port, Const.NVL(authenticationUser, ""),
                            Const.NVL(authenticationPassword, ""));
                } else {
                    transport.connect(Const.NVL(server, ""), Const.NVL(authenticationUser, ""),
                            Const.NVL(authenticationPassword, ""));
                }
            } else {
                transport.connect();
            }
            transport.sendMessage(msg, msg.getAllRecipients());
        } finally {
            if (transport != null) {
                transport.close();
            }
        }

    }

    private void setAttachedFilesList(Object[] r, LogChannelInterface log) throws Exception {
        String realSourceFileFoldername = null;
        String realSourceWildcard = null;
        FileObject sourcefile = null;
        FileObject file = null;

        ZipOutputStream zipOutputStream = null;
        File masterZipfile = null;

        if (meta.isZipFilenameDynamic()) {
            data.ZipFilename = data.previousRowMeta.getString(r, data.indexOfDynamicZipFilename);
        }

        try {

            if (meta.isDynamicFilename()) {
                // dynamic attached filenames
                if (data.indexOfSourceFilename > -1) {
                    realSourceFileFoldername = data.previousRowMeta.getString(r, data.indexOfSourceFilename);
                }

                if (data.indexOfSourceWildcard > -1) {
                    realSourceWildcard = data.previousRowMeta.getString(r, data.indexOfSourceWildcard);
                }

            } else {
                // static attached filenames
                realSourceFileFoldername = data.realSourceFileFoldername;
                realSourceWildcard = data.realSourceWildcard;
            }

            if (!Const.isEmpty(realSourceFileFoldername)) {
                sourcefile = KettleVFS.getFileObject(realSourceFileFoldername, getTransMeta());
                if (sourcefile.exists()) {
                    long FileSize = 0;
                    FileObject[] list = null;
                    if (sourcefile.getType() == FileType.FILE) {
                        list = new FileObject[1];
                        list[0] = sourcefile;
                    } else {
                        list = sourcefile
                                .findFiles(new TextFileSelector(sourcefile.toString(), realSourceWildcard));
                    }
                    if (list.length > 0) {

                        boolean zipFiles = meta.isZipFiles();
                        if (zipFiles && data.zipFileLimit == 0) {
                            masterZipfile = new File(
                                    System.getProperty("java.io.tmpdir") + Const.FILE_SEPARATOR + data.ZipFilename);

                            zipOutputStream = new ZipOutputStream(new FileOutputStream(masterZipfile));
                        }

                        for (int i = 0; i < list.length; i++) {

                            file = KettleVFS.getFileObject(KettleVFS.getFilename(list[i]), getTransMeta());

                            if (zipFiles) {

                                if (data.zipFileLimit == 0) {
                                    ZipEntry zipEntry = new ZipEntry(file.getName().getBaseName());
                                    zipOutputStream.putNextEntry(zipEntry);

                                    // Now put the content of this file into this archive...
                                    BufferedInputStream inputStream = new BufferedInputStream(
                                            file.getContent().getInputStream());
                                    int c;
                                    while ((c = inputStream.read()) >= 0) {
                                        zipOutputStream.write(c);
                                    }
                                    inputStream.close();
                                    zipOutputStream.closeEntry();
                                } else {
                                    FileSize += file.getContent().getSize();
                                }
                            } else {
                                addAttachedFilePart(file);
                            }
                        } // end for
                        if (zipFiles) {
                            if (isDebug()) {
                                logDebug(BaseMessages.getString(PKG, "Mail.Log.FileSize", "" + FileSize));
                            }
                            if (isDebug()) {
                                logDebug(BaseMessages.getString(PKG, "Mail.Log.LimitSize", "" + data.zipFileLimit));
                            }

                            if (data.zipFileLimit > 0 && FileSize > data.zipFileLimit) {

                                masterZipfile = new File(System.getProperty("java.io.tmpdir") + Const.FILE_SEPARATOR
                                        + data.ZipFilename);

                                zipOutputStream = new ZipOutputStream(new FileOutputStream(masterZipfile));

                                for (int i = 0; i < list.length; i++) {

                                    file = KettleVFS.getFileObject(KettleVFS.getFilename(list[i]), getTransMeta());

                                    ZipEntry zipEntry = new ZipEntry(file.getName().getBaseName());
                                    zipOutputStream.putNextEntry(zipEntry);

                                    // Now put the content of this file into this archive...
                                    BufferedInputStream inputStream = new BufferedInputStream(
                                            file.getContent().getInputStream());
                                    int c;
                                    while ((c = inputStream.read()) >= 0) {
                                        zipOutputStream.write(c);
                                    }
                                    inputStream.close();
                                    zipOutputStream.closeEntry();

                                }

                            }
                            if (data.zipFileLimit > 0 && FileSize > data.zipFileLimit || data.zipFileLimit == 0) {
                                file = KettleVFS.getFileObject(masterZipfile.getAbsolutePath(), getTransMeta());
                                addAttachedFilePart(file);
                            }
                        }
                    }
                } else {
                    logError(BaseMessages.getString(PKG, "Mail.Error.SourceFileFolderNotExists",
                            realSourceFileFoldername));
                }
            }
        } catch (Exception e) {
            logError(e.getMessage());
        } finally {
            if (sourcefile != null) {
                try {
                    sourcefile.close();
                } catch (Exception e) {
                    // Ignore errors
                }
            }
            if (file != null) {
                try {
                    file.close();
                } catch (Exception e) {
                    // Ignore errors
                }
            }

            if (zipOutputStream != null) {
                try {
                    zipOutputStream.finish();
                    zipOutputStream.close();
                } catch (IOException e) {
                    logError("Unable to close attachement zip file archive : " + e.toString());
                }
            }
        }

    }

    private void addAttachedFilePart(FileObject file) throws Exception {
        // create a data source

        MimeBodyPart files = new MimeBodyPart();
        // create a data source
        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();
        data.parts.addBodyPart(files);
        if (isDetailed()) {
            logDetailed(BaseMessages.getString(PKG, "Mail.Log.AttachedFile", fds.getName()));
        }

    }

    private void addAttachedContent(String filename, String fileContent) throws Exception {
        // create a data source

        MimeBodyPart mbp = new MimeBodyPart();
        // get a data Handler to manipulate this file type;
        mbp.setDataHandler(new DataHandler(new ByteArrayDataSource(fileContent.getBytes(), "application/x-any")));
        // include the file in the data source
        mbp.setFileName(filename);
        // add the part with the file in the BodyPart();
        data.parts.addBodyPart(mbp);

    }

    private void addImagePart() throws Exception {
        data.nrEmbeddedImages = 0;
        if (data.embeddedMimePart != null && data.embeddedMimePart.size() > 0) {
            for (Iterator<MimeBodyPart> i = data.embeddedMimePart.iterator(); i.hasNext();) {
                MimeBodyPart part = i.next();
                data.parts.addBodyPart(part);
                data.nrEmbeddedImages++;
            }
        }
    }

    private class TextFileSelector implements FileSelector {
        String fileWildcard = null;
        String sourceFolder = null;

        public TextFileSelector(String sourcefolderin, String filewildcard) {
            if (!Const.isEmpty(sourcefolderin)) {
                sourceFolder = sourcefolderin;
            }

            if (!Const.isEmpty(filewildcard)) {
                fileWildcard = filewildcard;
            }
        }

        public boolean includeFile(FileSelectInfo info) {
            boolean returncode = false;
            try {
                if (!info.getFile().toString().equals(sourceFolder)) {
                    // Pass over the Base folder itself
                    String short_filename = info.getFile().getName().getBaseName();

                    if (info.getFile().getParent().equals(info.getBaseFolder())
                            || ((!info.getFile().getParent().equals(info.getBaseFolder())
                                    && meta.isIncludeSubFolders()))) {
                        if ((info.getFile().getType() == FileType.FILE && fileWildcard == null)
                                || (info.getFile().getType() == FileType.FILE && fileWildcard != null
                                        && GetFileWildcard(short_filename, fileWildcard))) {
                            returncode = true;
                        }
                    }
                }
            } catch (Exception e) {
                logError(BaseMessages.getString(PKG, "Mail.Error.FindingFiles", info.getFile().toString(),
                        e.getMessage()));
                returncode = false;
            }
            return returncode;
        }

        public boolean traverseDescendents(FileSelectInfo info) {
            return true;
        }
    }

    /**********************************************************
     *
     * @param selectedfile
     * @param wildcard
     * @return True if the selectedfile matches the wildcard
     **********************************************************/
    private boolean GetFileWildcard(String selectedfile, String wildcard) {
        Pattern pattern = null;
        boolean getIt = true;

        if (!Const.isEmpty(wildcard)) {
            pattern = Pattern.compile(wildcard);
            // First see if the file matches the regular expression!
            if (pattern != null) {
                Matcher matcher = pattern.matcher(selectedfile);
                getIt = matcher.matches();
            }
        }

        return getIt;
    }

    public boolean init(StepMetaInterface smi, StepDataInterface sdi) {
        meta = (MailMeta) smi;
        data = (MailData) sdi;

        if (super.init(smi, sdi)) {
            // Add init code here.
            return true;
        }
        return false;
    }

    public void dispose(StepMetaInterface smi, StepDataInterface sdi) {
        meta = (MailMeta) smi;
        data = (MailData) sdi;

        if (data.embeddedMimePart != null) {
            data.embeddedMimePart.clear();
        }
        data.parts = null;
        super.dispose(meta, data);
    }

}