package org.apache.velocity.tools.email;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.swing.border.EtchedBorder;
import org.apache.commons.collections.ExtendedProperties;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.context.Context;
/**
* This class is used to execute velocity templates and send the result via
* email.
* <p/>
* <b>Usage: <b><br/>
* To control the operation of VelocityMail you need to create a configuration file
* called 'velocity.mail.properties'. The file MUST
* be on your class path.
* <i>Config file </i><br/>
* <pre>
*
* ## TEST CONFIGURATION
* #From Name & Address
* #The values of these properties are also velocity templates
* test.from.name=$name
* test.from.address=test@localhost
*
* #Subject
* #Can contain velocity template language
* test.subject=Test to $name
*
* #SMTP Host
* test.host=127.0.0.1
*
* #Different Mime type templates
* test.message.text/plain=/mail/test.text.vm
* test.message.text/html=/mail/test.html.vm
*
* </pre>
*
* <p/>
* <i>Source Coude </i> <br/>
* <pre>
* context.put("name", "John Doe");
* VelocityMail vmail = VelocityMail.getDefaultInstance();
* InternetAddress address = new InternetAddress("test@localhost");
* vmail.send("test", address, context);
* </pre>
*
* @author <a href="mailto:leon@psybergate.com">Leon Messerschmidt </a>
* @version $revision$
*
*/
public class VelocityMail
{
/**
* The default instance for the Velocity Mail class
*/
private static VelocityMail defaultInstance;
/**
* The configuration for Velocity Mail
*/
private ExtendedProperties properties;
/**
* The list of email configurations that are available.
*/
private Map configurations;
/**
* Create a new Velocity Mail object with a properties object
*
* @param properties
*/
public VelocityMail(ExtendedProperties properties)
{
this.configurations = new HashMap();
this.properties = properties;
}
/**
* Return the default instance for VelocityMail. It attempts to load the
* resources "velocity.mail.properties" from the classpath.
*
* @return @throws
* IOException
*/
public static VelocityMail getDefaultInstance() throws IOException
{
if (defaultInstance == null)
{
ClassLoader classLoader = VelocityMail.class.getClassLoader();
InputStream inputStream = classLoader
.getResourceAsStream("velocity.mail.properties");
ExtendedProperties extendedProperties = new ExtendedProperties();
extendedProperties.load(inputStream);
defaultInstance = new VelocityMail(extendedProperties);
}
return defaultInstance;
}
/**
* Send an email message to a single address using the default
* configuration.
*
* @param address
* The receiver of the email
* @param context
* The velocity context used to merge the email template
*
* @throws Exception
*/
public void send(InternetAddress address, Context context) throws Exception
{
InternetAddress[] addresses = new InternetAddress[1];
addresses[0] = address;
send(addresses, context);
}
/**
* Send an email message to a single address
*
* @param config
* The configuration to use (specified in the email properties)
* @param address
* The receiver of the email
* @param context
* The velocity context used to merge the email template
* @throws Exception
*/
public void send(String config, InternetAddress address, Context context)
throws Exception
{
InternetAddress[] addresses = new InternetAddress[1];
addresses[0] = address;
send(config, addresses, context);
}
/**
* Send an email message to a list of addresses using the default
* configuration.
*
* @param address
* The receivers of the email
* @param context
* The velocity context used to merge the email template
*
* @throws Exception
*/
public void send(InternetAddress[] addresses, Context context)
throws Exception
{
send("default", addresses, context);
}
/**
* Send an email message to a list of addresses
*
* @param config
* The configuration to use (specified in the email properties)
* @param address
* The receivers of the email
* @param context
* The velocity context used to merge the email template
* @throws Exception
*/
public void send(String config, InternetAddress[] addresses, Context context)
throws Exception
{
ExtendedProperties configuration = getConfiguration(config);
Message message = createMessage(configuration, context);
setMessageContent(message, configuration, context);
message.setRecipients(Message.RecipientType.TO, addresses);
Transport.send(message);
}
/**
* Create a JavaMail message object from a specified configuration
*
* @param configuration
* A configuration object that was created from VelocityMail
* properties
*
* @param context
* The velocity context to use to merge the email template
*
* @throws Exception
*/
protected Message createMessage(ExtendedProperties configuration,
Context context) throws Exception
{
String host = configuration.getString("host");
Properties properties = new Properties();
properties.put("mail.smtp.host", host);
Session session = Session.getInstance(properties);
MimeMessage result = new MimeMessage(session);
String subject = evaluate(configuration, "subject", context);
result.setSubject(subject);
String fromAddr = evaluate(configuration, "from.address", context);
String fromName = evaluate(configuration, "from.name", context);
InternetAddress fromAddress = new InternetAddress(fromAddr, fromName);
result.setFrom(fromAddress);
return result;
}
/**
* Merge the email template(s) using the velocity context and add the
* content to the JavaMail message object
*
* @param message
* The message that will receive the message content
*
* @param configuration
* The configuration to use
*
* @param context
* The velocity context that will be used to merge the mail
* templates
*
* @throws Exception
*/
protected void setMessageContent(Message message,
ExtendedProperties configuration, Context context) throws Exception
{
ExtendedProperties content = configuration.subset("message");
Enumeration keys = content.keys();
Multipart multipart = new MimeMultipart();
while (keys.hasMoreElements())
{
String key = (String) keys.nextElement();
String templateName = content.getString(key);
Template template = Velocity.getTemplate(templateName);
StringWriter writer = new StringWriter();
template.merge(context, writer);
writer.close();
BodyPart bodyPart = new MimeBodyPart();
bodyPart.setContent(writer.toString(), key);
multipart.addBodyPart(bodyPart);
}
message.setContent(multipart);
}
/**
* Helper method to evaluate a string
*
* @param configuration
* @param property
* @param context
* @return @throws
* Exception
*/
protected String evaluate(ExtendedProperties configuration,
String property, Context context) throws Exception
{
Velocity.init();
String subjectTemplate = configuration.getString(property);
StringWriter stringWriter = new StringWriter();
Velocity.evaluate(context, stringWriter, "email", subjectTemplate);
stringWriter.close();
return stringWriter.toString();
}
/**
* Get the configuration for a given configuration name
*
* @param name
* @return
*/
protected ExtendedProperties getConfiguration(String name)
{
ExtendedProperties config = (ExtendedProperties) configurations
.get(name);
if (config == null)
{
config = properties.subset(name);
configurations.put(name, config);
}
return config;
}
}