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