    001    package org.apache.turbine.util.velocity;
    002
    003
    004    /*
    005     * Licensed to the Apache Software Foundation (ASF) under one
    006     * or more contributor license agreements.  See the NOTICE file
    007     * distributed with this work for additional information
    008     * regarding copyright ownership.  The ASF licenses this file
    009     * to you under the Apache License, Version 2.0 (the
    010     * "License"); you may not use this file except in compliance
    011     * with the License.  You may obtain a copy of the License at
    012     *
    013     *   http://www.apache.org/licenses/LICENSE-2.0
    014     *
    015     * Unless required by applicable law or agreed to in writing,
    016     * software distributed under the License is distributed on an
    017     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    018     * KIND, either express or implied.  See the License for the
    019     * specific language governing permissions and limitations
    020     * under the License.
    021     */
    022
    023
    024    import java.net.URL;
    025    import java.util.Hashtable;
    026
    027    import org.apache.commons.lang.StringUtils;
    028    import org.apache.commons.logging.Log;
    029    import org.apache.commons.logging.LogFactory;
    030    import org.apache.commons.mail.EmailException;
    031    import org.apache.commons.mail.HtmlEmail;
    032    import org.apache.turbine.Turbine;
    033    import org.apache.turbine.TurbineConstants;
    034    import org.apache.turbine.pipeline.PipelineData;
    035    import org.apache.turbine.services.velocity.TurbineVelocity;
    036    import org.apache.turbine.util.RunData;
    037    import org.apache.velocity.context.Context;
    038
    039    /**
    040     * This is a simple class for sending html email from within Velocity.
    041     * Essentially, the bodies (text and html) of the email are a Velocity
    042     * Context objects.  The beauty of this is that you can send email
    043     * from within your Velocity template or from your business logic in
    044     * your Java code.  The body of the email is just a Velocity template
    045     * so you can use all the template functionality of Velocity within
    046     * your emails!
    047     *
    048     * <p>This class allows you to send HTML email with embedded content
    049     * and/or with attachments.  You can access the VelocityHtmlEmail
    050     * instance within your templates trough the <code>$mail</code>
    051     * Velocity variable.
    052     * <p><code>VelocityHtmlEmail   myEmail= new VelocityHtmlEmail(data);<br>
    053     *                              context.put("mail", myMail);</code>
    054     * <b>or</b>
    055     *    <code>VelocityHtmlEmail   myEmail= new VelocityHtmlEmail(context);<br>
    056     *                              context.put("mail", myMail);</code>
    057     *
    058     *
    059     * <p>The templates should be located under your Template turbine
    060     * directory.
    061     *
    062     * <p>This class wraps the HtmlEmail class from commons-email.  Thus, it uses
    063     * the JavaMail API and also depends on having the mail.server property
    064     * set in the TurbineResources.properties file.  If you want to use
    065     * this class outside of Turbine for general processing that is also
    066     * possible by making sure to set the path to the
    067     * TurbineResources.properties.  See the
    068     * TurbineResourceService.setPropertiesFileName() method for more
    069     * information.
    070     *
    071     * <p>This class is basically a conversion of the WebMacroHtmlEmail
    072     * written by Regis Koenig
    073     *
    074     * <p>You can turn on debugging for the JavaMail API by calling
    075     * setDebug(true).  The debugging messages will be written to System.out.
    076     *
    077     * @author <a href="mailto:epugh@upstate.com">Eric Pugh</a>
    078     * @author <a href="mailto:A.Schild@aarboard.ch">Andre Schild</a>
    079     * @author <a href="mailto:quintonm@bellsouth.net">Quinton McCombs</a>
    080     * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
    081     * @author <a href="mailto:peter@courcoux.biz">Peter Courcoux</a>
    082     * @version $Id: VelocityHtmlEmail.java 929479 2010-03-31 11:24:21Z tv $
    083     */
    084    public class VelocityHtmlEmail extends HtmlEmail
    085    {
    086        /** Logging */
    087        private static Log log = LogFactory.getLog(VelocityHtmlEmail.class);
    088
    089        /**
    090         * The html template to process, relative to VM's template
    091         * directory.
    092         */
    093        private String htmlTemplate = null;
    094
    095        /**
    096         * The text template to process, relative to VM's template
    097         * directory.
    098         */
    099        private String textTemplate = null;
    100
    101        /** The cached context object. */
    102        private Context context = null;
    103
    104        /** The map of embedded files. */
    105        private Hashtable embmap = null;
    106
    107        /** Address of outgoing mail server */
    108        private String mailServer;
    109
    110        /**
    111         * Constructor, sets the context object from the passed RunData object
    112         * @deprecated use PipelineData version instead
    113         * @param data A Turbine RunData object.
    114         */
    115        public VelocityHtmlEmail(RunData data)
    116        {
    117            this.context = TurbineVelocity.getContext(data);
    118            embmap = new Hashtable();
    119        }
    120
    121        /**
    122         * Constructor, sets the context object from the passed RunData object
    123         *
    124         * @param data A Turbine RunData object.
    125         */
    126        public VelocityHtmlEmail(PipelineData pipelineData)
    127        {
    128            this.context = TurbineVelocity.getContext(pipelineData);
    129            embmap = new Hashtable();
    130        }
    131
    132        /**
    133         * Constructor, sets the context object.
    134         *
    135         * @param context A Velocity context object.
    136         */
    137        public VelocityHtmlEmail(Context context)
    138        {
    139            this.context = context;
    140            embmap = new Hashtable();
    141        }
    142
    143        /**
    144         * Set the HTML template for the mail.  This is the Velocity
    145         * template to execute for the HTML part.  Path is relative to the
    146         * VM templates directory.
    147         *
    148         * @param template A String.
    149         * @return A VelocityHtmlEmail (self).
    150         */
    151        public VelocityHtmlEmail setHtmlTemplate(String template)
    152        {
    153            this.htmlTemplate = template;
    154            return this;
    155        }
    156
    157        /**
    158         * Set the text template for the mail.  This is the Velocity
    159         * template to execute for the text part.  Path is relative to the
    160         * VM templates directory
    161         *
    162         * @param template A String.
    163         * @return A VelocityHtmlEmail (self).
    164         */
    165        public VelocityHtmlEmail setTextTemplate(String template)
    166        {
    167            this.textTemplate = template;
    168            return this;
    169        }
    170
    171        /**
    172         * Sets the address of the outgoing mail server.  This method
    173         * should be used when you need to override the value stored in
    174         * TR.props.
    175         *
    176         * @param serverAddress host name of your outgoing mail server
    177         */
    178        public void setMailServer(String serverAddress)
    179        {
    180            this.mailServer = serverAddress;
    181        }
    182
    183        /**
    184         * Gets the host name of the outgoing mail server.  If the server
    185         * name has not been set by calling setMailServer(), the value
    186         * from TR.props for mail.server will be returned.  If TR.props
    187         * has no value for mail.server, localhost will be returned.
    188         *
    189         * @return host name of the mail server.
    190         */
    191        public String getMailServer()
    192        {
    193            return StringUtils.isNotEmpty(mailServer) ? mailServer
    194                    : Turbine.getConfiguration().getString(
    195                    TurbineConstants.MAIL_SERVER_KEY,
    196                    TurbineConstants.MAIL_SERVER_DEFAULT);
    197        }
    198
    199        /**
    200         * Actually send the mail.
    201         *
    202         * @exception EmailException thrown if mail cannot be sent.
    203         */
    204        public String send() throws EmailException
    205        {
    206            context.put("mail", this);
    207
    208            try
    209            {
    210                if (htmlTemplate != null)
    211                {
    212                    setHtmlMsg(
    213                            TurbineVelocity.handleRequest(context, htmlTemplate));
    214                }
    215                if (textTemplate != null)
    216                {
    217                    setTextMsg(
    218                            TurbineVelocity.handleRequest(context, textTemplate));
    219                }
    220            }
    221            catch (Exception e)
    222            {
    223                throw new EmailException("Cannot parse velocity template", e);
    224            }
    225            setHostName(getMailServer());
    226            return super.send();
    227        }
    228
    229        /**
    230         * Embed a file in the mail.  The file can be referenced through
    231         * its Content-ID.  This function also registers the CID in an
    232         * internal map, so the embedded file can be referenced more than
    233         * once by using the getCid() function.  This may be useful in a
    234         * template.
    235         *
    236         * <p>Example of template:
    237         *
    238         * <code><pre width="80">
    239         * &lt;html&gt;
    240         * &lt;!-- $mail.embed("http://server/border.gif","border.gif"); --&gt;
    241         * &lt;img src=$mail.getCid("border.gif")&gt;
    242         * &lt;p&gt;This is your content
    243         * &lt;img src=$mail.getCid("border.gif")&gt;
    244         * &lt;/html&gt;
    245         * </pre></code>
    246         *
    247         * @param surl A String.
    248         * @param name A String.
    249         * @return A String with the cid of the embedded file.
    250         *
    251         * @see HtmlEmail#embed(URL surl, String name) embed.
    252         */
    253        public String embed(String surl, String name)
    254        {
    255            String cid = "";
    256            try
    257            {
    258                URL url = new URL(surl);
    259                cid = embed(url, name);
    260            }
    261            catch (Exception e)
    262            {
    263                log.error("cannot embed " + surl + ": ", e);
    264            }
    265            return cid;
    266        }
    267
    268        /**
    269         * Get the cid of an embedded file.
    270         *
    271         * @param filename A String.
    272         * @return A String with the cid of the embedded file.
    273         * @see #embed(String surl, String name) embed.
    274         */
    275        public String getCid(String filename)
    276        {
    277            String cid = (String) embmap.get(filename);
    278            return "cid:" + cid;
    279        }
    280
    281    }