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    import org.apache.commons.lang.StringUtils;
024    import org.apache.commons.lang.WordUtils;
025    import org.apache.commons.logging.Log;
026    import org.apache.commons.logging.LogFactory;
027    import org.apache.commons.mail.EmailException;
028    import org.apache.commons.mail.SimpleEmail;
029    import org.apache.turbine.Turbine;
030    import org.apache.turbine.TurbineConstants;
031    import org.apache.turbine.services.velocity.TurbineVelocity;
032    import 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 1078552 2011-03-06 19:58:46Z tv $
102     */
103    public 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         */
131        public VelocityEmail(Context context)
132        {
133            this();
134            this.context = context;
135        }
136    
137        /**
138         * To: toName, toEmail
139         *
140         * @param toName A String with the TO toName.
141         * @param toEmail A String with the TO toEmail.
142         * @deprecated use addTo(email,name) instead
143         * @throws EmailException email address could not be parsed
144         * @return A VelocityEmail (self).
145         */
146        @Deprecated
147        public VelocityEmail setTo(String toName, String toEmail)
148                throws EmailException
149        {
150            addTo(toEmail,toName);
151            return this;
152        }
153    
154        /**
155         * Velocity template to execute. Path is relative to the Velocity
156         * templates directory.
157         *
158         * @param template relative path of the template to parse including the
159         *                 filename.
160         * @return A VelocityEmail (self).
161         */
162        public VelocityEmail setTemplate(String template)
163        {
164            this.template = template;
165            return this;
166        }
167    
168        /**
169         * Set the column at which long lines of text should be word-
170         * wrapped. Setting to zero turns off word-wrap (default).
171         *
172         * NOTE: don't use tabs in your email template document,
173         * or your word-wrapping will be off for the lines with tabs
174         * in them.
175         *
176         * @param wordWrap The column at which to wrap long lines.
177         * @return A VelocityEmail (self).
178         */
179        public VelocityEmail setWordWrap(int wordWrap)
180        {
181            this.wordWrap = wordWrap;
182            return this;
183        }
184    
185        /**
186         * Set the context object that will be merged with the
187         * template.
188         *
189         * @param context A Velocity context object.
190         * @return A VelocityEmail (self).
191         */
192        public VelocityEmail setContext(Context context)
193        {
194            this.context = context;
195            return this;
196        }
197    
198        /**
199         * Get the context object that will be merged with the
200         * template.
201         *
202         * @return A Context (self).
203         */
204        public Context getContext()
205        {
206            return this.context;
207        }
208    
209        /**
210         * Sets the address of the outgoing mail server.  This method
211         * should be used when you need to override the value stored in
212         * TR.props.
213         *
214         * @param serverAddress host name of your outgoing mail server
215         */
216        public void setMailServer(String serverAddress)
217        {
218            this.mailServer = serverAddress;
219        }
220    
221        /**
222         * Gets the host name of the outgoing mail server.  If the server
223         * name has not been set by calling setMailServer(), the value
224         * from TR.props for mail.server will be returned.  If TR.props
225         * has no value for mail.server, localhost will be returned.
226         *
227         * @return host name of the mail server.
228         */
229        public String getMailServer()
230        {
231            return StringUtils.isNotEmpty(mailServer) ? mailServer
232                    : Turbine.getConfiguration().getString(
233                    TurbineConstants.MAIL_SERVER_KEY,
234                    TurbineConstants.MAIL_SERVER_DEFAULT);
235        }
236    
237        /**
238         * This method sends the email.
239         * <p>If the mail server was not set by calling, setMailServer()
240         * the value of mail.server will be used from TR.props.  If that
241         * value was not set, localhost is used.
242         *
243         * @throws EmailException Failure during merging the velocity
244         * template or sending the email.
245         */
246        @Override
247        public String send() throws EmailException
248        {
249            String body = null;
250            try
251            {
252                // Process the template.
253                body = TurbineVelocity.handleRequest(context, template);
254            }
255            catch (Exception e)
256            {
257                throw new EmailException(
258                        "Could not render velocitty template", e);
259            }
260    
261            // If the caller desires word-wrapping, do it here
262            if (wordWrap > 0)
263            {
264                body = WordUtils.wrap(body, wordWrap,
265                        System.getProperty("line.separator"), false);
266            }
267    
268            setMsg(body);
269            setHostName(getMailServer());
270            return super.send();
271        }
272    
273        /**
274         * The method toString() calls send() for ease of use within a
275         * Velocity template (see example usage above).
276         *
277         * @return An empty string.
278         */
279        @Override
280        public String toString()
281        {
282            try
283            {
284                send();
285            }
286            catch (Exception e)
287            {
288                log.error("VelocityEmail error", e);
289            }
290            return "";
291        }
292    }