Bug 38462 - Allow direct File Upload in mailer2
Summary: Allow direct File Upload in mailer2
Alias: None
Product: Taglibs
Classification: Unclassified
Component: Sandbox Taglibs (show other bugs)
Version: 1.0
Hardware: All All
: P2 normal (vote)
Target Milestone: ---
Assignee: Tomcat Developers Mailing List
Depends on:
Reported: 2006-01-31 15:30 UTC by Karl-Heinz Sergel
Modified: 2009-07-10 00:41 UTC (History)
0 users


Note You need to log in before you can comment on or make changes to this bug.
Description Karl-Heinz Sergel 2006-01-31 15:30:04 UTC
This nearly addresses the same issue as report #31869.
We 'd like to have the possibility to upload files and directly send them with 
mailer2, without including scriptlets.
We build a solution and ask if it would be a benefit to others.
What we've done is:
Expose the content of a multipart upload to the jsp via a tag 'upload' using 
the commons-fileupload library, wrapping the 'FileItem' to a DataSource.
Adding a new attribute 'upload' to the append-tag, which accepts a DataSource.
So sending a mail with an uploaded file is done by the lines:

<mt:upload var="upl"/>
<c:if test="${upl.file1Ok}"> 
  <mt:attach upload="${upl.file1Data}" />

We've tested the build with the sandbox mailer2 build and it works.

I add the new classes, changes, example-jsp and requirements here:
1. Two new classes
package org.apache.taglibs.mailer2;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Logger;

import javax.activation.DataSource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.BodyTagSupport;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUpload;
import org.apache.commons.fileupload.disk.DiskFileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.servlet.ServletRequestContext;

 * JSP tag <b>mt:upload</b> is used to construct the list of the FileItems from
 * the multipart response to be used for preparing the mail.
 * @author Karl-Heinz Sergel
 * @version 2.0
 * @jsp.tag name="upload" body-content="JSP" display-name="mt:upload"
 *          description="JSP tag <mt:pload> is used to extract uploaded file
 *          information to be included in an e-mail message. It is a standalone
 *          element.

public class UploadTag extends BodyTagSupport {
  private static final String UPLOAD = "upload";
  private Logger  log       = Logger.getLogger(this.getClass().getName());
   * Default attributename for exposing upload multipart-values to the jsp.
  private String  var       = UPLOAD;

   * indicates kind of upload
  private boolean multipart = false;

  public UploadTag() {

  public void init() {
    var = UPLOAD;
    multipart = false;

  public int doEndTag() throws JspException {
    HashMap map = new HashMap();
    try {
      ServletRequestContext psrc = new ServletRequestContext(
          (HttpServletRequest) pageContext.getRequest());
      boolean isMultipart = FileUpload.isMultipartContent(psrc);
      if (isMultipart) {
        FileItemFactory factory = new DiskFileItemFactory();
        ServletFileUpload upload = new ServletFileUpload(factory);
        List items = upload.parseRequest(psrc);
        for (Iterator it = items.iterator(); it.hasNext();) {
          FileItem item = (FileItem) it.next();
          if (item.isFormField()) {
            map.put(item.getFieldName(), item.getString());
          } else {
            String baseName = item.getFieldName();
            map.put(baseName, item.getName());
            if (item.getSize() > 0) {
              DataSource wds = new WrappedFileItem(item);
              map.put(baseName + "Data", wds);
              map.put(baseName + "Ok", new Boolean(true));
              map.put(baseName + "Size", new Long(item.getSize()));
            } else {
              map.put(baseName + "Ok", new Boolean(false));
      if (var == null)
        var = UPLOAD;
      map.put("isMultipart", new Boolean(isMultipart));
      pageContext.setAttribute(var, map, PageContext.PAGE_SCOPE);
    } catch (Exception ex) {
      throw new JspException("ml:upload: error processing upload: ", ex);
    return EVAL_PAGE;

  public boolean isMultipart() {
    return multipart;

  public void setMultipart(boolean multipart) {
    this.multipart = multipart;

  public String getVar() {
    return var;

  public void setVar(String var) {
    this.var = var;

package org.apache.taglibs.mailer2;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.activation.DataSource;

import org.apache.commons.fileupload.FileItem;

public class WrappedFileItem implements DataSource {
    private FileItem fileItem;

    public WrappedFileItem(FileItem fileItem) {
      this.fileItem = fileItem;
    public String getContentType() {
      return fileItem.getContentType();

    public InputStream getInputStream() throws IOException {
      return fileItem.getInputStream();

     * this is nessessary because of the different behavier of the brousers. IE
     * returns the full pathname as filename, whereas firefox returns the
     * filename only, as needed.
    public String getName() {
      File file = new File(fileItem.getName());
      return file.getName();

    public OutputStream getOutputStream() throws IOException {
      return fileItem.getOutputStream();

2. Changes to AttachTag
add Attribute
    private DataSource upload     = null;

add Getter/Setter
   public DataSource getUpload() {
        return upload;
     * Set the DataSource for this  attachment.
     * @param DataSource of uploaded file to attach
    public void setUpload(DataSource upload) {
        this.upload = upload;

insert into doEndTag.java
        try {
          // This is to support the uploaded files khs 2006/01/31
          if (upload != null) {
            mbp.setDataHandler(new DataHandler(upload));
            localName = upload.getName();
            mbp.setHeader("Content-Type", upload.getContentType());
          else if (filename != null) {

insert new tag into xml/mailer2.xml
                <description><![CDATA[JSP tag <mt:upload> is used to expose the 
uploaded content of the mulripart message to the jsp-page. <mt:upload> does not 
have any child tags.]]></description>
                    <description>The prefix of the exposed content. Defaults 
to 'upload'</description>
                        <comment>Example usage of the &lt;mt:upload&gt; 
The multipart content is exposed in two differnt forms.
${upl.upl.isMultipart} return true, if multipart content is exposed.
Ff false is returned, the fields are to be accessed via param.<filedname>

The content of normal form-fields can be accessed with
(given <mt:upload var="upl"/>)
${upl.<name of the field>}
The content of a file-filed be accessed with
${upl.<name of the field>} = browser retured name of the uploaded file,
${upl.<name of the field>Ok} = the DataSource is ready,
${upl.<name of the field>Size} = size in byte of the uploaded file,
${upl.<name of the field>Data} = a DataSource representation of the uploaded 
${upl.<name of the field>Data.name} = the filename of the uploaded file,
${upl.<name of the field>Data.contentType} = the contentType of the uploaded 

<mt:upload var="upl"/>
<c:if test="${upl.isMultipart == true}">
	<mt:attach upload="${upl.file1Data}"/>


add new attribute for tag append into xml/mailer2.xml
                    <description>A upload file exposed with a previous 
&lt;mt:upload var="..."&gt;</description>

add sendUpload.jsp to examples
<!doctype html PUBLIC "-//W3C//DTD XHTML 1.0 
Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<%@ taglib prefix="mt" uri="http://jakarta.apache.org/taglibs/mailer2" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<!-- ## expose the multipart content -->
<mt:upload var="upl"/>

<title>simple mail with upload file example using mt:send and mt:upload</title>
<link rel="stylesheet" type="text/css" href="mailer2.css"/>
<link rel="home" href="index.jsp"/>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>

<h1>simple mail with Upload example using mt:send and mt:upload</h1>
sending to "${email}" via "${server}".<br>

<!-- ## if we have an multipart upload, all must be set from var defined in the 
upload-tag -->
	<c:when test="${upl.isMultipart == true}">
		<c:set var="feld1"  value="${upl.feld1}" scope="session"/>
		<c:set var="feld2"  value="${upl.feld2}" scope="session"/>
		<c:set var="email"  value="${upl.email}" scope="session"/>	
		<c:set var="server" value="${upl.server}" scope="session"/>
		<c:if test="${upl.file1Ok == true}" >
			<c:set var="file1" value="${upl.file1}" scope="page"/>
		<c:set var="feld1"  value="${param.feld1}" scope="session"/>
		<c:set var="feld2"  value="${param.feld2}" scope="session"/>
		<c:set var="email"  value="${param.email}" scope="session"/>	
		<c:set var="server" value="${param.server}" scope="session"/>

<!-- ## for test purpose only -->
feld1 = ${feld1} <br>
feld2 = ${feld2} <br>
file1 = ${upl.file1} <br>
content = ${upl.file1Data} <br>
size = ${upl.file1Size} Byte <br>

<!-- ## test whatever seems nessessary -->
<c:if test="${not empty feld1}">
	var="message" from="${email}" 
	subject="upload File example using mt:send and mt:upload" 
        <mt:addrecipient type="to" name="The User">${email}</mt:addrecipient>
        Hello World,
	<c:if test="${not empty file1}"> 
		<!-- access the name of the DataSource direct -->
		Der Inhalt des Uploads "${upl.file1Data.name}" als attachement 
(via DataSource)!<br>
        	<mt:attach upload="${upl.file1Data}" />

    <mt:send message="${message}"/>

    <p>Mail sent to ${email}
	<c:if test="${not empty file1}">
		, attaching ${upl.file1}


<form method="post" action="#" enctype="multipart/form-data">
	to be send:</br>	
    Email to:<input type="text" name="email" value="${sessionScope.email}" 
    local Server: <input type="text" name="server" 
value="${sessionScope.server}" size="30"/><br>
    Feld1:: <input type="text" name="feld1" value="${feld1}" size="30"/></br>
    Feld2:: <input type="text" name="feld2" value="${feld2}" size="30"/></br>
    File1:: <input type="file" name="file1" value=""/></br>
    <input class="button" type="submit" value="Send"/>

<a href="index.jsp">Back</a>


don't forget, we need new libs.
so add to build.properties at sandbox level
# commons-upload required by mailer2
# commons-io required by mailer2

and check that at mailer2-level
add in build.xml at mailer2-level
first the classpath
  <property name="classpath" 

then at target 'examples.pre'
    <copy todir="${build.examples}/WEB-INF/lib" file="${fileupload.jar}"/>
    <copy todir="${build.examples}/WEB-INF/lib" file="${commonsio.jar}"/>

then at target 'checkRequirements.pre' add

    <antcall target="checkRequiredFile">
       <param name="file" value="${fileupload.jar}"/>
       <param name="fail.message" value="Property fileupload.jar is not set in 
build.properties. This library is required to send upload file via mail 
attachments. get fileupload.jar from 
    <antcall target="checkRequiredFile">
       <param name="file" value="${commonsio.jar}"/>
       <param name="fail.message" value="Property commonsio.jar is not set in 
build.properties. This library is required to send upload file via mail 
attachments. get commonsio.jar from http://jakarta.apache.org/commons/io/"/>
Comment 1 Henri Yandell 2009-07-10 00:41:12 UTC
This taglib has been deprecated, so I don't expect to see this worked on.