xml| Create | templates
Sending mail is a basic function of Web application system. Generally speaking, mail has specific types, such as password reminders, welcome information, order confirmation or receipt confirmation. Although the content of different application messages varies, the process of sending messages is essentially the same. Build the message, send it to the mail server, send it.
When using Java development, we often use the JavaMail API to connect mail servers to send mail. But this approach is cumbersome (mainly due to the flexibility of the message), so when you need to send a message multiple times in this way, It's better to write a wrapper. Depending on how it is used, wrapper can send a particular message, such as a password reminder, or as a generic pattern, accept the subject, recipient, and message content as parameters.
Once you use wrapper to send a message, you need a system that constructs messages on your own. Let's use a password reminder as an example. Basically all messages contain topics, content, and recipients. When we send a password reminder email, the user address and password are extracted from the knowledge base of a log login information. The subject and content need to be merged with the data extracted by the database and stored somewhere. The biggest problem with system design is where to store this type of string. In many cases, strings are stored in the properties file, which separates the data from the source code and makes localization easier. I have used this storage mechanism in many Web application systems, but unfortunately there are many flaws in this approach.
The following are the reasons why you cannot store a message string using a property file:
• The property file uses a very simple data structure-name and value combination. This structure is not appropriate when you need a lot of values to correspond to a name. For example, a message has 4 recipients, 3 cc people, using a property file is difficult to solve this problem.
• The format of the property file is very strict. The name and value must be on the same line, so long strings are difficult to handle when you edit the file. For example, it is painful to put all the content of a message into a property file. If you want the content of the value to include a newline, you must use the
Another option is to use XML as a mail template, which is what this article is all about. XML provides a great deal of flexibility for you to build templates, and it does not have all the formatting limitations of a property file, so it's easy to handle long strings in this way. The main disadvantage of XML is that it is more complex to handle than a property file. When using a property file, it is easy to load files and access files after loading. Loading XML files and using one of the multiple XML processing libraries provided by Java to process XML files requires more work.
This article and the accompanying code provide a generic template that allows you to create templates using XML files and send emails, hoping to mitigate the pain of the process. In this template, I will use the Commons Digester package in the Jakarta project to process the XML and send the mail using the JavaMail API.
Mail templates
Let's take a look at the format of the mail template. A template is an XML file that contains a root element and a set of child elements of a series of roots. The root element is. The necessary child elements are,,, and. The optional child elements are,,, and. If you've ever used a mail system, you can deduce what these elements actually contain. There are multiple instances of an optional element, so you can specify multiple addresses for each type of receiver. I will explain the operation mechanism when describing the message processing later. The following is an example of a template file.
Rafe@rafe.us
someone@example.com
Someoneelse@example.com
Rafe@rafe.us
This is the subject
This is the "body of" email message.
Customizable templates
A useful feature of a property file is that you can use the Messageformat class to replace the specified parameter in the property file with a dynamically passed value. For example, if you need to specify errors in a property file, one of the errors is file not found, you can write this:
File.not.found.error=error, could not find file {0}.
Then, at run time, you use messageformat like this:
ResourceBundle bundle = Resourcebundle.getbundle (
"Myproperties", Currentlocale);
object[] arguments = {"Some_file.txt"};
String newstring = Messageformat.format (
Bundle.getstring ("File.not.found.error"), arguments);
Finally, NewString will contain the error, could not find file some_file.txt. I have added similar flexibility to this system. You can format all the strings, so you can embed the same tokens that are used in the properties file in the subject and body elements of the mail template.
In some cases, you want to insert personalized information when you send the message. For example, you want to include the recipient's last name in the content of the message or the content of the order. This system solves this problem by using Messageformat to deal with the content and subject of the mail template. Use only one parameter array when dealing with content and themes. This topic can contain token {0}, {2}, {3}, content can contain token {0}, {1}, {4}. I take this approach because in many cases the subject and the content use the same parameters, and this simplifies the parameters that are required to pass to the Emailsender.
Processing templates
After you create the template, the next step is to deal with it. We know that there are now a lot of XML processing packages to choose from. Commons Digester is a Jakarta public project that was originally created to quickly and easily parse struts's configuration files in a struts project. It provides mappings from elements in an XML file to data structures that use similar XPath syntax. The advantage is that in order to get an element from an XML file you don't have to use sax to parse a node, or to use the DOM to process tree data structures.
The following method reads the data from the XML file and copies the data to the Emailtemplate object.
public static Emailtemplate getemailtemplate (InputStream astream)
{
Digester digester = new Digester ();
Digester.setvalidating (FALSE);
Digester.addobjectcreate ("email", emailtemplate.class);
Digester.addbeanpropertysetter ("Email/subject", "subject");
Digester.addbeanpropertysetter ("Email/body", "body");
Digester.addbeanpropertysetter ("Email/from", "from");
Digester.addcallmethod ("Email/to", "AddTo", 0);
Digester.addcallmethod ("email/cc", "ADDCC", 0);
Digester.addcallmethod ("Email/bcc", "ADDBCC", 0);
Try
{
Return (emailtemplate) digester.parse (Astream);
}
catch (IOException E)
{
Logger.error ("Error:", e);
return null;
}
catch (Saxexception e)
{
Logger.error ("Error:", e);
return null;
}
}
Let's look at this piece of code line by row. The principle of Commons digester work is that you specify some rules for parsing files. Because there is no DTD file for the canonical mail template, I set the validating flag to false before specifying the processing rule. When I start working on the file, I instantiate the Digester object and call the method to establish the data mapping rule. First, I call the Addobjectcreate () method to establish the rules for creating the Emailtemplate object. Email is the root element of an XML template file. So the template file corresponds to the Emailtemplate object one by one.
I use Addbeanpropertysetter () to work with elements that appear only once in a template file. This method has two parameters, the path of the element, and the assignment method to invoke. On the first call, I specify that elements that conform to the email/subject pattern in the file should be assigned to the subject of the Emailtemplate class. We use "/" to trace the inline relationship of an XML file. In this example, an element that conforms to the subject pattern is an email child element. We can use wildcards to provide more flexibility. Refer to Commons Digester's Javadoc you can understand the details of how the pattern is constructed.
It is not feasible to use an assignment method to process elements that appear multiple times in a template file. We use Addcallmethod () to handle this situation, which takes a value from the element and invokes the specified method. I use this method to have three parameter versions, which are: matching pattern, calling method, calling method using the number of parameters. In the example of the three cases, the third parameter is 0, which indicates that the element conforming to the pattern is the only parameter that invokes the method. In the Emailtemplate Class I define three methods: AddTo (), ADDCC (), ADDBCC (), which adds a list of recipients in the template file to the recipient collection of the template class.
After the rules for the six types of child elements of the message element are specified, I begin parsing the file. In this example, I passed in the input parameter of the Getemailtemplate method InputStream. Parse method can parse File,sax InputSource, InputStream, Reader, URI of target file. I use InputStream. The code that invokes this method gets the XML file and converts it to InputStream. To make this method more general, I can use object as a parameter and use instanceof inside the method to determine the type of the parameter, and then handle it in the appropriate way.
Method Parse throws IOException or saxexception. Pass the exception to log4j, which is processed by it, and returns NULL. If no exception is thrown, the Emailtemplate object created by Digester is returned.
The remainder of the Emailtemplate class
The Getemailtemplate () method is the core of the class emailtemplate. The other part is some attribute values and some auxiliary methods. There are 3 string attribute values: Content, subject, sender address, 3 ArrayList property values: To, CC, BCC list, which 3 values are based on string. There is also a corresponding Get,set and a method of adding a set. There are 3 additional convenient methods: Gettoaddresses (), getccaddresses (), and getbccaddresses (). The JavaMail interface requires a internetaddress array as an argument to the address set, which converts an object's string array to the array form required by the JavaMail interface.
Class Emailsender
When the template file is parsed into a Emailtemplate object, the next step is to send the message. The Emailsender class contains a static, overloaded method-sendemail (). This method can be invoked in a number of ways, all of which are a reference to the following complete parameter method:
public static void SendEmail (
String ATo,
Emailtemplate Atemplate,
String[] Aargs)
Parameter does not require an excessive explanation. The first is the sending address of the message. You can specify a lot of recipient addresses in the mail template, but at runtime, most of the time, the system needs only one recipient. For example, if you send a message with a password reminder, you only need to specify the e-mail address of the user who requested the password. The list of recipients specified in the mail template applies in one case: as a test, the system needs to send a message to a specific list of recipients or to include a list of specific recipients when sending. For example, suppose a system needs to trigger a workflow on an email every time an order is submitted, in which case the message template's specific recipient address is meaningful.
The second parameter is the emailtemplate itself. The third parameter is the set of parameters required by Messageformat to parse the message subject and content. The array of information needed to create a personalized message template is created by the code that calls this method. There are other ways to make this method easier to call (so you can call this method without specifying the recipient or without parameters).
The internal method consists of a series of calls that are required to send a message using JavaMail. I think using javamail will cause a lot of redundancy, let's take a look at it. First, I'm going to check to determine if Emailtemplate is empty. If it is empty, nothing can be done. The first step is to create a Properties object (Hashtable) using the settings of SMTP server. I set the SMTP server settings in the file, so I read the value dependency file and put it in the Properties object I created.
Then I created a JavaMail session object to pass in the Properties object. The session object is required when creating a MimeMessage object. This is what I'm going to do later. Then I assign the value from: to the corresponding field in the Passed-in parameter Emailtemplate object. Next I set the To: value to the message I built. There are some tricks here, because the user can pass in the to: address, while the mail template also contains some to: address. The problem is that JavaMail prefers to use array stroke address lists, so it's up to me to decide how big the list of recipients is, and then build the incoming arguments.
Because CC:BCC: The address must be specified in the template, we can deal with them directly. I use the method in the Emailtemplate class to add other recipients to the message. As I started to mention, I use Messageformat to parse the set of parameters needed to resolve the subject and content of the message. When I finished, I copied the new topic to the message body. This handles the contents of the message. The rest is to call Transport.send () and pass in the MimeMessage object.
Using this system
I've just explained how the system works, and now I'm going to explain how to use it through a servlet, which is similar in other programs. Here's the code:
Grab the email template.
InputStream template =
Getservlet ()
. Getservletconfig ()
. Getservletcontext ()
. getResourceAsStream (
"/web-inf/email/registrationnotification.xml");
Emailtemplate notification = emailtemplate.getemailtemplate (template);
Create the section of the email containing the actual user data.
string[] args = {"Rafe"};
Emailsender.sendemail ("rafe@rafe.us", notification, args);
The first step in using this system is to convert your XML template files into InputStream. Because I'm using a servlet, I get this file from ServletContext. Of course there are other ways to get this file, but in a servlet environment, it works. I'll just pass the InputStream to the Emailtemplate.getemailtemplate () method just described. Next, set up an array of parameters to personalize the message, and then call Method Emailsender.sendemail ().
More
This system can also be more optimized, there are two more obvious needs to improve the place: the system should support both plain text and HTML, support attachments. Creating this type of information requires the use of type Javax.mail.MimeMultipart. There are also questions about where to store attachments and how to specify attachments. In my system, I did not process attachments in the template file because my attachment was created when the message was sent.