    001package 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
    023import org.apache.commons.lang.StringUtils;
    024import org.apache.commons.lang.WordUtils;
    025import org.apache.commons.logging.Log;
    026import org.apache.commons.logging.LogFactory;
    027import org.apache.commons.mail.EmailException;
    028import org.apache.commons.mail.SimpleEmail;
    029import org.apache.turbine.Turbine;
    030import org.apache.turbine.TurbineConstants;
    031import org.apache.turbine.services.TurbineServices;
    032import org.apache.turbine.services.velocity.VelocityService;
    033import org.apache.velocity.context.Context;
    034
    035/**
    036 * This is a simple class for sending email from within Velocity.
    037 * Essentially, the body of the email is processed with a
    038 * Velocity Context object.
    039 * The beauty of this is that you can send email from within your
    040 * Velocity template or from your business logic in your Java code.
    041 * The body of the email is just a Velocity template so you can use
    042 * all the template functionality of Velocity within your emails!
    043 *
    044 * <p>Example Usage (This all needs to be on one line in your
    045 * template):
    046 *
    047 * <p>Setup your context:
    048 *
    049 * <p><code>context.put ("VelocityEmail", new VelocityEmail() );</code>
    050 *
    051 * <p>Then, in your template:
    052 *
    053 * <pre>
    054 * $VelocityEmail.setTo("Jon Stevens", "jon@latchkey.com")
    055 *     .setFrom("Mom", "mom@mom.com").setSubject("Eat dinner")
    056 *     .setTemplate("email/momEmail.vm")
    057 *     .setContext($context)
    058 * </pre>
    059 *
    060 * The email/momEmail.wm template will then be parsed with the
    061 * Context that was defined with setContext().
    062 *
    063 * <p>If you want to use this class from within your Java code all you
    064 * have to do is something like this:
    065 *
    066 * <pre>
    067 * VelocityEmail ve = new VelocityEmail();
    068 * ve.setTo("Jon Stevens", "jon@latchkey.com");
    069 * ve.setFrom("Mom", "mom@mom.com").setSubject("Eat dinner");
    070 * ve.setContext(context);
    071 * ve.setTemplate("email/momEmail.vm")
    072 * ve.send();
    073 * </pre>
    074 *
    075 * <p>(Note that when used within a Velocity template, the send method
    076 * will be called for you when Velocity tries to convert the
    077 * VelocityEmail to a string by calling toString()).</p>
    078 *
    079 * <p>If you need your email to be word-wrapped, you can add the
    080 * following call to those above:
    081 *
    082 * <pre>
    083 * ve.setWordWrap (60);
    084 * </pre>
    085 *
    086 * <p>This class is just a wrapper around the SimpleEmail class from
    087 * commons-mail using the JavaMail API.
    088 * Thus, it depends on having the
    089 * mail.server property set in the TurbineResources.properties file.
    090 * If you want to use this class outside of Turbine for general
    091 * processing that is also possible by making sure to set the path to
    092 * the TurbineResources.properties.  See the
    093 * TurbineConfig class for more information.</p>
    094 *
    095 * <p>You can turn on debugging for the JavaMail API by calling
    096 * setDebug(true).  The debugging messages will be written to System.out.
    097 *
    098 * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
    099 * @author <a href="mailto:gcoladonato@yahoo.com">Greg Coladonato</a>
    100 * @author <a href="mailto:quintonm@bellsouth.net">Quinton McCombs</a>
    101 * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
    102 * @version $Id: VelocityEmail.java 1723699 2016-01-08 11:29:21Z tv $
    103 */
    104public class VelocityEmail extends SimpleEmail
    105{
    106    /** Logging */
    107    private static Log log = LogFactory.getLog(VelocityEmail.class);
    108
    109    /** The column to word-wrap at.  <code>0</code> indicates no wrap. */
    110    private int wordWrap = 0;
    111
    112    /** Address of outgoing mail server */
    113    private String mailServer;
    114
    115    /** The template to process, relative to Velocity template directory. */
    116    private String template = null;
    117
    118    /** Velocity context */
    119    private Context context = null;
    120
    121    /**
    122     * Constructor
    123     */
    124    public VelocityEmail()
    125    {
    126        super();
    127    }
    128
    129    /**
    130     * Constructor
    131     * @param context the velocity context to use
    132     */
    133    public VelocityEmail(Context context)
    134    {
    135        this();
    136        this.context = context;
    137    }
    138
    139    /**
    140     * To: toName, toEmail
    141     *
    142     * @param toName A String with the TO toName.
    143     * @param toEmail A String with the TO toEmail.
    144     * @deprecated use addTo(email,name) instead
    145     * @throws EmailException email address could not be parsed
    146     * @return A VelocityEmail (self).
    147     */
    148    @Deprecated
    149    public VelocityEmail setTo(String toName, String toEmail)
    150            throws EmailException
    151    {
    152        addTo(toEmail,toName);
    153        return this;
    154    }
    155
    156    /**
    157     * Velocity template to execute. Path is relative to the Velocity
    158     * templates directory.
    159     *
    160     * @param template relative path of the template to parse including the
    161     *                 filename.
    162     * @return A VelocityEmail (self).
    163     */
    164    public VelocityEmail setTemplate(String template)
    165    {
    166        this.template = template;
    167        return this;
    168    }
    169
    170    /**
    171     * Set the column at which long lines of text should be word-
    172     * wrapped. Setting to zero turns off word-wrap (default).
    173     *
    174     * NOTE: don't use tabs in your email template document,
    175     * or your word-wrapping will be off for the lines with tabs
    176     * in them.
    177     *
    178     * @param wordWrap The column at which to wrap long lines.
    179     * @return A VelocityEmail (self).
    180     */
    181    public VelocityEmail setWordWrap(int wordWrap)
    182    {
    183        this.wordWrap = wordWrap;
    184        return this;
    185    }
    186
    187    /**
    188     * Set the context object that will be merged with the
    189     * template.
    190     *
    191     * @param context A Velocity context object.
    192     * @return A VelocityEmail (self).
    193     */
    194    public VelocityEmail setContext(Context context)
    195    {
    196        this.context = context;
    197        return this;
    198    }
    199
    200    /**
    201     * Get the context object that will be merged with the
    202     * template.
    203     *
    204     * @return A Context (self).
    205     */
    206    public Context getContext()
    207    {
    208        return this.context;
    209    }
    210
    211    /**
    212     * Sets the address of the outgoing mail server.  This method
    213     * should be used when you need to override the value stored in
    214     * TR.props.
    215     *
    216     * @param serverAddress host name of your outgoing mail server
    217     */
    218    public void setMailServer(String serverAddress)
    219    {
    220        this.mailServer = serverAddress;
    221    }
    222
    223    /**
    224     * Gets the host name of the outgoing mail server.  If the server
    225     * name has not been set by calling setMailServer(), the value
    226     * from TR.props for mail.server will be returned.  If TR.props
    227     * has no value for mail.server, localhost will be returned.
    228     *
    229     * @return host name of the mail server.
    230     */
    231    public String getMailServer()
    232    {
    233        return StringUtils.isNotEmpty(mailServer) ? mailServer
    234                : Turbine.getConfiguration().getString(
    235                TurbineConstants.MAIL_SERVER_KEY,
    236                TurbineConstants.MAIL_SERVER_DEFAULT);
    237    }
    238
    239    /**
    240     * This method sends the email.
    241     * <p>If the mail server was not set by calling, setMailServer()
    242     * the value of mail.server will be used from TR.props.  If that
    243     * value was not set, localhost is used.
    244     *
    245     * @throws EmailException Failure during merging the velocity
    246     * template or sending the email.
    247     */
    248    @Override
    249    public String send() throws EmailException
    250    {
    251        String body = null;
    252        try
    253        {
    254            // Process the template.
    255            VelocityService velocityService = (VelocityService)TurbineServices.getInstance().getService(VelocityService.SERVICE_NAME);
    256            body = velocityService.handleRequest(context, template);
    257        }
    258        catch (Exception e)
    259        {
    260            throw new EmailException(
    261                    "Could not render velocity template", e);
    262        }
    263
    264        // If the caller desires word-wrapping, do it here
    265        if (wordWrap > 0)
    266        {
    267            body = WordUtils.wrap(body, wordWrap,
    268                    System.getProperty("line.separator"), false);
    269        }
    270
    271        setMsg(body);
    272        setHostName(getMailServer());
    273        return super.send();
    274    }
    275
    276    /**
    277     * The method toString() calls send() for ease of use within a
    278     * Velocity template (see example usage above).
    279     *
    280     * @return An empty string.
    281     */
    282    @Override
    283    public String toString()
    284    {
    285        try
    286        {
    287            send();
    288        }
    289        catch (Exception e)
    290        {
    291            log.error("VelocityEmail error", e);
    292        }
    293        return "";
    294    }
    295}