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