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.services.TurbineServices;
035import org.apache.turbine.services.velocity.VelocityService;
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 1773378 2016-12-09 13:19:59Z 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
111     */
112    public VelocityHtmlEmail()
113    {
114        super();
115    }
116
117    /**
118     * Constructor, sets the context object.
119     *
120     * @param context A Velocity context object.
121     */
122    public VelocityHtmlEmail(Context context)
123    {
124        this();
125        this.context = context;
126        embmap = new Hashtable<String, String>();
127    }
128
129    /**
130     * Set the HTML template for the mail.  This is the Velocity
131     * template to execute for the HTML part.  Path is relative to the
132     * VM templates directory.
133     *
134     * @param template A String.
135     * @return A VelocityHtmlEmail (self).
136     */
137    public VelocityHtmlEmail setHtmlTemplate(String template)
138    {
139        this.htmlTemplate = template;
140        return this;
141    }
142
143    /**
144     * Set the text template for the mail.  This is the Velocity
145     * template to execute for the text 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 setTextTemplate(String template)
152    {
153        this.textTemplate = template;
154        return this;
155    }
156
157    /**
158     * Sets the address of the outgoing mail server.  This method
159     * should be used when you need to override the value stored in
160     * TR.props.
161     *
162     * @param serverAddress host name of your outgoing mail server
163     */
164    public void setMailServer(String serverAddress)
165    {
166        this.mailServer = serverAddress;
167    }
168
169    /**
170     * Gets the host name of the outgoing mail server.  If the server
171     * name has not been set by calling setMailServer(), the value
172     * from TR.props for mail.server will be returned.  If TR.props
173     * has no value for mail.server, localhost will be returned.
174     *
175     * @return host name of the mail server.
176     */
177    public String getMailServer()
178    {
179        return StringUtils.isNotEmpty(mailServer) ? mailServer
180                : Turbine.getConfiguration().getString(
181                TurbineConstants.MAIL_SERVER_KEY,
182                TurbineConstants.MAIL_SERVER_DEFAULT);
183    }
184
185    /**
186     * Actually send the mail.
187     *
188     * @throws EmailException thrown if mail cannot be sent.
189     */
190    @Override
191    public String send() throws EmailException
192    {
193        context.put("mail", this);
194
195        try
196        {
197            VelocityService velocityService = (VelocityService)TurbineServices.getInstance().getService(VelocityService.SERVICE_NAME);
198
199            if (htmlTemplate != null)
200            {
201                setHtmlMsg(velocityService.handleRequest(context, htmlTemplate));
202            }
203            if (textTemplate != null)
204            {
205                setTextMsg(velocityService.handleRequest(context, textTemplate));
206            }
207        }
208        catch (Exception e)
209        {
210            throw new EmailException("Cannot parse velocity template", e);
211        }
212        setHostName(getMailServer());
213        return super.send();
214    }
215
216    /**
217     * Embed a file in the mail.  The file can be referenced through
218     * its Content-ID.  This function also registers the CID in an
219     * internal map, so the embedded file can be referenced more than
220     * once by using the getCid() function.  This may be useful in a
221     * template.
222     *
223     * <p>Example of template:
224     *
225     * <pre>
226     * &lt;html&gt;
227     * &lt;!-- $mail.embed("http://server/border.gif","border.gif"); --&gt;
228     * &lt;img src=$mail.getCid("border.gif")&gt;
229     * &lt;p&gt;This is your content
230     * &lt;img src=$mail.getCid("border.gif")&gt;
231     * &lt;/html&gt;
232     * </pre>
233     *
234     * @param surl A String.
235     * @param name A String.
236     * @return A String with the cid of the embedded file.
237     *
238     * @see HtmlEmail#embed(URL surl, String name) embed.
239     */
240    @Override
241    public String embed(String surl, String name)
242    {
243        String cid = "";
244        try
245        {
246            URL url = new URL(surl);
247            cid = super.embed(url, name);
248            embmap.put(name, cid);
249        }
250        catch (Exception e)
251        {
252            log.error("cannot embed " + surl + ": ", e);
253        }
254        return cid;
255    }
256
257    /**
258     * Get the cid of an embedded file.
259     *
260     * @param filename A String.
261     * @return A String with the cid of the embedded file.
262     * @see #embed(String surl, String name) embed.
263     */
264    public String getCid(String filename)
265    {
266        String cid = embmap.get(filename);
267        return "cid:" + cid;
268    }
269
270}