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    }