org.apache.synapse.transport.mail.MailTransportSender.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.synapse.transport.mail.MailTransportSender.java

Source

/*
 *  Licensed to the Apache Software Foundation (ASF) under one
 *  or more contributor license agreements.  See the NOTICE file
 *  distributed with this work for additional information
 *  regarding copyright ownership.  The ASF licenses this file
 *  to you 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.apache.synapse.transport.mail;

import org.apache.synapse.transport.base.AbstractTransportSender;
import org.apache.synapse.transport.base.BaseConstants;
import org.apache.synapse.transport.base.BaseUtils;
import org.apache.synapse.transport.base.BaseTransportException;
import org.apache.commons.logging.LogFactory;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.description.TransportOutDescription;
import org.apache.axis2.description.Parameter;
import org.apache.axis2.AxisFault;
import org.apache.axis2.addressing.AddressingConstants;
import org.apache.axis2.transport.OutTransportInfo;
import org.apache.axis2.transport.MessageFormatter;
import org.apache.axis2.transport.TransportUtils;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMOutputFormat;
import org.apache.axiom.om.OMNode;
import org.apache.axiom.om.OMText;
import org.apache.axiom.om.impl.llom.OMSourcedElementImpl;

import javax.mail.*;
import javax.mail.util.ByteArrayDataSource;
import javax.mail.internet.*;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.MailcapCommandMap;
import javax.activation.CommandMap;
import javax.xml.stream.XMLStreamException;
import java.util.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

/**
 * The mail transport sender sends mail using an SMTP server configuration defined
 * in the axis2.xml's transport sender definition
 */
public class MailTransportSender extends AbstractTransportSender {

    private String smtpUsername = null;
    private String smtpPassword = null;
    /** Default from address for outgoing messages */
    private InternetAddress smtpFromAddress = null;
    /** A set of custom Bcc address for all outgoing messages */
    private InternetAddress[] smtpBccAddresses = null;
    /** Default mail format */
    private String defaultMailFormat = "Text";
    /** The default Session which can be safely shared */
    private Session session = null;

    /**
     * The public constructor
     */
    public MailTransportSender() {
        log = LogFactory.getLog(MailTransportSender.class);
    }

    /**
     * Initialize the Mail sender and be ready to send messages
     * @param cfgCtx the axis2 configuration context
     * @param transportOut the transport-out description
     * @throws org.apache.axis2.AxisFault on error
     */
    public void init(ConfigurationContext cfgCtx, TransportOutDescription transportOut) throws AxisFault {
        setTransportName(MailConstants.TRANSPORT_NAME);
        super.init(cfgCtx, transportOut);

        // initialize SMTP session
        Properties props = new Properties();
        List<Parameter> params = transportOut.getParameters();
        for (Parameter p : params) {
            props.put(p.getName(), p.getValue());
        }

        if (props.containsKey(MailConstants.MAIL_SMTP_FROM)) {
            try {
                smtpFromAddress = new InternetAddress((String) props.get(MailConstants.MAIL_SMTP_FROM));
            } catch (AddressException e) {
                handleException("Invalid default 'From' address : " + props.get(MailConstants.MAIL_SMTP_FROM), e);
            }
        }

        if (props.containsKey(MailConstants.MAIL_SMTP_BCC)) {
            try {
                smtpBccAddresses = InternetAddress.parse((String) props.get(MailConstants.MAIL_SMTP_BCC));
            } catch (AddressException e) {
                handleException("Invalid default 'Bcc' address : " + props.get(MailConstants.MAIL_SMTP_BCC), e);
            }
        }

        if (props.containsKey(MailConstants.TRANSPORT_MAIL_FORMAT)) {
            defaultMailFormat = (String) props.get(MailConstants.TRANSPORT_MAIL_FORMAT);
        }

        smtpUsername = (String) props.get(MailConstants.MAIL_SMTP_USERNAME);
        smtpPassword = (String) props.get(MailConstants.MAIL_SMTP_PASSWORD);

        if (smtpUsername != null && smtpPassword != null) {
            session = Session.getInstance(props, new Authenticator() {
                public PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication(smtpUsername, smtpPassword);
                }
            });
        } else {
            session = Session.getInstance(props, null);
        }

        // add handlers for main MIME types
        MailcapCommandMap mc = (MailcapCommandMap) CommandMap.getDefaultCommandMap();
        mc.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html");
        mc.addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml");
        mc.addMailcap("application/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml");
        mc.addMailcap("application/soap+xml;; x-java-content-handler=com.sun.mail.handlers.text_xml");
        mc.addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain");
        mc.addMailcap("multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed");
        mc.addMailcap("message/rfc822;; x-java-content-handler=com.sun.mail.handlers.message_rfc822");
        CommandMap.setDefaultCommandMap(mc);

        session.setDebug(log.isTraceEnabled());
    }

    /**
     * Send the given message over the Mail transport
     *
     * @param msgCtx the axis2 message context
     * @throws AxisFault on error
     */
    public void sendMessage(MessageContext msgCtx, String targetAddress, OutTransportInfo outTransportInfo)
            throws AxisFault {

        MailOutTransportInfo mailOutInfo = null;

        if (targetAddress != null) {
            if (targetAddress.startsWith(MailConstants.TRANSPORT_NAME)) {
                targetAddress = targetAddress.substring(MailConstants.TRANSPORT_NAME.length() + 1);
            }

            if (msgCtx.getReplyTo() != null
                    && !AddressingConstants.Final.WSA_NONE_URI.equals(msgCtx.getReplyTo().getAddress())
                    && !AddressingConstants.Final.WSA_ANONYMOUS_URL.equals(msgCtx.getReplyTo().getAddress())) {

                String replyTo = msgCtx.getReplyTo().getAddress();
                if (replyTo.startsWith(MailConstants.TRANSPORT_NAME)) {
                    replyTo = replyTo.substring(MailConstants.TRANSPORT_NAME.length() + 1);
                }
                try {
                    mailOutInfo = new MailOutTransportInfo(new InternetAddress(replyTo));
                } catch (AddressException e) {
                    handleException("Invalid reply address/es : " + replyTo, e);
                }
            } else {
                mailOutInfo = new MailOutTransportInfo(smtpFromAddress);
            }

            try {
                mailOutInfo.setTargetAddresses(InternetAddress.parse(targetAddress));
            } catch (AddressException e) {
                handleException("Invalid target address/es : " + targetAddress, e);
            }
        } else if (outTransportInfo != null && outTransportInfo instanceof MailOutTransportInfo) {
            mailOutInfo = (MailOutTransportInfo) outTransportInfo;
        }

        if (mailOutInfo != null) {
            try {
                sendMail(mailOutInfo, msgCtx);
            } catch (MessagingException e) {
                handleException("Error generating mail message", e);
            } catch (IOException e) {
                handleException("Error generating mail message", e);
            }
        } else {
            handleException("Unable to determine out transport information to send message");
        }
    }

    /**
     * Populate email with a SOAP formatted message
     * @param outInfo the out transport information holder
     * @param msgContext the message context that holds the message to be written
     * @throws AxisFault on error
     */
    private void sendMail(MailOutTransportInfo outInfo, MessageContext msgContext)
            throws AxisFault, MessagingException, IOException {

        OMOutputFormat format = BaseUtils.getOMOutputFormat(msgContext);
        MessageFormatter messageFormatter = null;

        try {
            messageFormatter = TransportUtils.getMessageFormatter(msgContext);
        } catch (AxisFault axisFault) {
            throw new BaseTransportException("Unable to get the message formatter to use");
        }

        WSMimeMessage message = new WSMimeMessage(session);
        Map trpHeaders = (Map) msgContext.getProperty(MessageContext.TRANSPORT_HEADERS);

        // set From address - first check if this is a reply, then use from address from the
        // transport out, else if any custom transport headers set on this message, or default
        // to the transport senders default From address        
        if (outInfo.getTargetAddresses() != null && outInfo.getFromAddress() != null) {
            message.setFrom(outInfo.getFromAddress());
            message.setReplyTo((new Address[] { outInfo.getFromAddress() }));
        } else if (trpHeaders != null && trpHeaders.containsKey(MailConstants.MAIL_HEADER_FROM)) {
            message.setFrom(new InternetAddress((String) trpHeaders.get(MailConstants.MAIL_HEADER_FROM)));
            message.setReplyTo(InternetAddress.parse((String) trpHeaders.get(MailConstants.MAIL_HEADER_FROM)));
        } else {
            if (smtpFromAddress != null) {
                message.setFrom(smtpFromAddress);
                message.setReplyTo(new Address[] { smtpFromAddress });
            } else {
                handleException("From address for outgoing message cannot be determined");
            }
        }

        // set To address/es to any custom transport header set on the message, else use the reply
        // address from the out transport information
        if (trpHeaders != null && trpHeaders.containsKey(MailConstants.MAIL_HEADER_TO)) {
            message.setRecipients(Message.RecipientType.TO,
                    InternetAddress.parse((String) trpHeaders.get(MailConstants.MAIL_HEADER_TO)));
        } else if (outInfo.getTargetAddresses() != null) {
            message.setRecipients(Message.RecipientType.TO, outInfo.getTargetAddresses());
        } else {
            handleException("To address for outgoing message cannot be determined");
        }

        // set Cc address/es to any custom transport header set on the message, else use the
        // Cc list from original request message
        if (trpHeaders != null && trpHeaders.containsKey(MailConstants.MAIL_HEADER_CC)) {
            message.setRecipients(Message.RecipientType.CC,
                    InternetAddress.parse((String) trpHeaders.get(MailConstants.MAIL_HEADER_CC)));
        } else if (outInfo.getTargetAddresses() != null) {
            message.setRecipients(Message.RecipientType.CC, outInfo.getCcAddresses());
        }

        // set Bcc address/es to any custom addresses set at the transport sender level + any
        // custom transport header
        InternetAddress[] trpBccArr = null;
        if (trpHeaders != null && trpHeaders.containsKey(MailConstants.MAIL_HEADER_BCC)) {
            trpBccArr = InternetAddress.parse((String) trpHeaders.get(MailConstants.MAIL_HEADER_BCC));
        }

        InternetAddress[] mergedBcc = new InternetAddress[(trpBccArr != null ? trpBccArr.length : 0)
                + (smtpBccAddresses != null ? smtpBccAddresses.length : 0)];
        if (trpBccArr != null) {
            System.arraycopy(trpBccArr, 0, mergedBcc, 0, trpBccArr.length);
        }
        if (smtpBccAddresses != null) {
            System.arraycopy(smtpBccAddresses, 0, mergedBcc, mergedBcc.length, smtpBccAddresses.length);
        }
        if (mergedBcc != null) {
            message.setRecipients(Message.RecipientType.BCC, mergedBcc);
        }

        // set subject
        if (trpHeaders != null && trpHeaders.containsKey(MailConstants.MAIL_HEADER_SUBJECT)) {
            message.setSubject((String) trpHeaders.get(MailConstants.MAIL_HEADER_SUBJECT));
        } else if (outInfo.getSubject() != null) {
            message.setSubject(outInfo.getSubject());
        } else {
            message.setSubject(BaseConstants.SOAPACTION + ": " + msgContext.getSoapAction());
        }

        // if a custom message id is set, use it
        if (msgContext.getMessageID() != null) {
            message.setHeader(MailConstants.MAIL_HEADER_MESSAGE_ID, msgContext.getMessageID());
            message.setHeader(MailConstants.MAIL_HEADER_X_MESSAGE_ID, msgContext.getMessageID());
        }

        // if this is a reply, set reference to original message
        if (outInfo.getRequestMessageID() != null) {
            message.setHeader(MailConstants.MAIL_HEADER_IN_REPLY_TO, outInfo.getRequestMessageID());
            message.setHeader(MailConstants.MAIL_HEADER_REFERENCES, outInfo.getRequestMessageID());

        } else {
            if (trpHeaders != null && trpHeaders.containsKey(MailConstants.MAIL_HEADER_IN_REPLY_TO)) {
                message.setHeader(MailConstants.MAIL_HEADER_IN_REPLY_TO,
                        (String) trpHeaders.get(MailConstants.MAIL_HEADER_IN_REPLY_TO));
            }
            if (trpHeaders != null && trpHeaders.containsKey(MailConstants.MAIL_HEADER_REFERENCES)) {
                message.setHeader(MailConstants.MAIL_HEADER_REFERENCES,
                        (String) trpHeaders.get(MailConstants.MAIL_HEADER_REFERENCES));
            }
        }

        // set Date
        message.setSentDate(new Date());

        // set SOAPAction header
        message.setHeader(BaseConstants.SOAPACTION, msgContext.getSoapAction());

        // write body
        ByteArrayOutputStream baos = null;
        String contentType = messageFormatter.getContentType(msgContext, format, msgContext.getSoapAction());
        DataHandler dataHandler = null;
        MimeMultipart mimeMultiPart = null;

        OMElement firstChild = msgContext.getEnvelope().getBody().getFirstElement();
        if (firstChild != null) {

            if (BaseConstants.DEFAULT_BINARY_WRAPPER.equals(firstChild.getQName())) {
                baos = new ByteArrayOutputStream();
                OMNode omNode = firstChild.getFirstOMChild();

                if (omNode != null && omNode instanceof OMText) {
                    Object dh = ((OMText) omNode).getDataHandler();
                    if (dh != null && dh instanceof DataHandler) {
                        dataHandler = (DataHandler) dh;
                    }
                }
            } else if (BaseConstants.DEFAULT_TEXT_WRAPPER.equals(firstChild.getQName())) {
                if (firstChild instanceof OMSourcedElementImpl) {
                    baos = new ByteArrayOutputStream();
                    try {
                        firstChild.serializeAndConsume(baos);
                    } catch (XMLStreamException e) {
                        handleException("Error serializing 'text' payload from OMSourcedElement", e);
                    }
                    dataHandler = new DataHandler(new String(baos.toByteArray(), format.getCharSetEncoding()),
                            MailConstants.TEXT_PLAIN);
                } else {
                    dataHandler = new DataHandler(firstChild.getText(), MailConstants.TEXT_PLAIN);
                }
            } else {

                baos = new ByteArrayOutputStream();
                messageFormatter.writeTo(msgContext, format, baos, true);

                // create the data handler
                dataHandler = new DataHandler(new String(baos.toByteArray(), format.getCharSetEncoding()),
                        contentType);

                String mFormat = (String) msgContext.getProperty(MailConstants.TRANSPORT_MAIL_FORMAT);
                if (mFormat == null) {
                    mFormat = defaultMailFormat;
                }

                if (MailConstants.TRANSPORT_FORMAT_MP.equals(mFormat)) {
                    mimeMultiPart = new MimeMultipart();
                    MimeBodyPart mimeBodyPart1 = new MimeBodyPart();
                    mimeBodyPart1.setContent("Web Service Message Attached", "text/plain");
                    MimeBodyPart mimeBodyPart2 = new MimeBodyPart();
                    mimeBodyPart2.setDataHandler(dataHandler);
                    mimeBodyPart2.setHeader(BaseConstants.SOAPACTION, msgContext.getSoapAction());
                    mimeMultiPart.addBodyPart(mimeBodyPart1);
                    mimeMultiPart.addBodyPart(mimeBodyPart2);

                } else {
                    message.setHeader(BaseConstants.SOAPACTION, msgContext.getSoapAction());
                }
            }
        }

        try {
            if (mimeMultiPart == null) {
                message.setDataHandler(dataHandler);
            } else {
                message.setContent(mimeMultiPart);
            }
            Transport.send(message);

        } catch (MessagingException e) {
            handleException("Error creating mail message or sending it to the configured server", e);

        } finally {
            try {
                if (baos != null) {
                    baos.close();
                }
            } catch (IOException ignore) {
            }
        }
    }
}