You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by cz...@apache.org on 2003/08/08 13:35:03 UTC

cvs commit: cocoon-2.1/src/blocks/mail/java/org/apache/cocoon/mail/transformation SendMailTransformer.java

cziegeler    2003/08/08 04:35:03

  Modified:    src/blocks/mail/mocks/javax/mail Session.java Message.java
                        BodyPart.java Transport.java
  Added:       src/blocks/mail/mocks/javax/mail SendFailedException.java
               src/blocks/mail/mocks/javax/activation URLDataSource.java
               src/blocks/mail/java/org/apache/cocoon/mail/transformation
                        SendMailTransformer.java
  Log:
  New sendmail transformer that can also send attachments contributed by Peter Klassen (pklassen@s-und-n.de)
  
  Revision  Changes    Path
  1.3       +5 -1      cocoon-2.1/src/blocks/mail/mocks/javax/mail/Session.java
  
  Index: Session.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/blocks/mail/mocks/javax/mail/Session.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- Session.java	10 Mar 2003 16:35:45 -0000	1.2
  +++ Session.java	8 Aug 2003 11:35:03 -0000	1.3
  @@ -26,4 +26,8 @@
   	public Provider[] getProviders() {
   		throw new NoSuchMethodError("This is a mock object");
   	}
  +
  +    public Transport getTransport(String name) {
  +        throw new NoSuchMethodError("This is a mock object");
  +    }
   }
  
  
  
  1.3       +17 -2     cocoon-2.1/src/blocks/mail/mocks/javax/mail/Message.java
  
  Index: Message.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/blocks/mail/mocks/javax/mail/Message.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- Message.java	10 Mar 2003 16:35:45 -0000	1.2
  +++ Message.java	8 Aug 2003 11:35:03 -0000	1.3
  @@ -77,4 +77,19 @@
   	public Flags getFlags() throws MessagingException {
   		throw new NoSuchMethodError("This is a mock object");
   	}
  -}
  +    
  +    public void setRecipients(Message.RecipientType type, Address[] addresses) 
  +    throws MessagingException {     
  +       throw new NoSuchMethodError("This is a mock object");
  +    }
  +
  +    public void setContent(Multipart mp)
  +    throws MessagingException {     
  +       throw new NoSuchMethodError("This is a mock object");
  +    }
  +
  +    public void saveChanges()
  +    throws MessagingException {     
  +       throw new NoSuchMethodError("This is a mock object");
  +    }
  +}
  \ No newline at end of file
  
  
  
  1.3       +4 -0      cocoon-2.1/src/blocks/mail/mocks/javax/mail/BodyPart.java
  
  Index: BodyPart.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/blocks/mail/mocks/javax/mail/BodyPart.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- BodyPart.java	17 Apr 2003 20:27:03 -0000	1.2
  +++ BodyPart.java	8 Aug 2003 11:35:03 -0000	1.3
  @@ -8,4 +8,8 @@
    */
   public abstract class BodyPart implements Part {
   
  +    public void setContent(String a, String b) {
  +        throw new NoSuchMethodError("This is a mock object");
  +    }
  +
   }
  
  
  
  1.4       +13 -1     cocoon-2.1/src/blocks/mail/mocks/javax/mail/Transport.java
  
  Index: Transport.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/blocks/mail/mocks/javax/mail/Transport.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- Transport.java	17 Apr 2003 20:27:03 -0000	1.3
  +++ Transport.java	8 Aug 2003 11:35:03 -0000	1.4
  @@ -11,4 +11,16 @@
   	public static void send(Message message) throws MessagingException {
           throw new NoSuchMethodError("This is a mock object");
   	}
  +    
  +    public void connect() {
  +        throw new NoSuchMethodError("This is a mock object");        
  +    }
  +
  +    public void close() {
  +        throw new NoSuchMethodError("This is a mock object");        
  +    }
  +
  +    public abstract void sendMessage(Message msg,
  +                                     Address[] addresses)
  +    throws MessagingException;
   }
  
  
  
  1.1                  cocoon-2.1/src/blocks/mail/mocks/javax/mail/SendFailedException.java
  
  Index: SendFailedException.java
  ===================================================================
  package javax.mail;
  
  /**
   * Mock class providing the declarations required to compile the Cocoon code when
   * the actual library is not present.
   * 
   * @version CVS $Id: SendFailedException.java,v 1.1 2003/08/08 11:35:03 cziegeler Exp $
   */
  public class SendFailedException extends MessagingException {
  
  	public SendFailedException() {
  		throw new NoSuchMethodError("This is a mock object");
  	}
  
      public SendFailedException(String s) {
          throw new NoSuchMethodError("This is a mock object");
      }
  	
  	public SendFailedException(String message, java.io.IOException ioe) {
  		throw new NoSuchMethodError("This is a mock object");
  	}
      
      public Address[] getInvalidAddresses() {
          throw new NoSuchMethodError("This is a mock object");
      }
  
      public Address[] getValidUnsentAddresses() {
          throw new NoSuchMethodError("This is a mock object");
      }
  }
  
  
  
  1.1                  cocoon-2.1/src/blocks/mail/mocks/javax/activation/URLDataSource.java
  
  Index: URLDataSource.java
  ===================================================================
  package javax.activation;
  
  import java.net.URL;
  
  /**
   * Mock class providing the declarations required to compile the Cocoon code when
   * the actual library is not present.
   * 
   * @version CVS $Id: URLDataSource.java,v 1.1 2003/08/08 11:35:03 cziegeler Exp $
   */
  
  public class URLDataSource implements DataSource {
  
      public URLDataSource(URL url) {
          throw new NoSuchMethodError("This is a mock object");
      }
      
      public String getName() {
          throw new NoSuchMethodError("This is a mock object");
      }
  }
  
  
  1.1                  cocoon-2.1/src/blocks/mail/java/org/apache/cocoon/mail/transformation/SendMailTransformer.java
  
  Index: SendMailTransformer.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, are permitted provided that the following conditions are met:
  
   1. Redistributions of  source code must  retain the above copyright  notice,
      this list of conditions and the following disclaimer.
  
   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
  
   3. The end-user documentation included with the redistribution, if any, must
      include  the following  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Apache Cocoon" and  "Apache Software Foundation" must  not  be
      used to  endorse or promote  products derived from  this software without
      prior written permission. For written permission, please contact
      apache@apache.org.
  
   5. Products  derived from this software may not  be called "Apache", nor may
      "Apache" appear  in their name,  without prior written permission  of the
      Apache Software Foundation.
  
   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
   This software  consists of voluntary contributions made  by many individuals
   on  behalf of the Apache Software  Foundation and was  originally created by
   Stefano Mazzocchi  <st...@apache.org>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.mail.transformation;
  
  import java.io.IOException;
  import java.io.InputStream;
  import java.net.URL;
  import java.util.Enumeration;
  import java.util.Map;
  import java.util.Properties;
  import java.util.StringTokenizer;
  import java.util.Vector;
  
  import javax.activation.DataHandler;
  import javax.activation.DataSource;
  import javax.activation.URLDataSource;
  import javax.mail.Address;
  import javax.mail.BodyPart;
  import javax.mail.Message;
  import javax.mail.Multipart;
  import javax.mail.SendFailedException;
  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 org.apache.avalon.excalibur.pool.Recyclable;
  import org.apache.avalon.framework.parameters.ParameterException;
  import org.apache.avalon.framework.parameters.Parameterizable;
  import org.apache.avalon.framework.parameters.Parameters;
  import org.apache.cocoon.ProcessingException;
  import org.apache.cocoon.environment.SourceResolver;
  import org.apache.cocoon.transformation.AbstractSAXTransformer;
  import org.apache.excalibur.source.Source;
  import org.xml.sax.Attributes;
  import org.xml.sax.SAXException;
  import org.xml.sax.helpers.AttributesImpl;
  
  
  /**
   * The SendMailTransformer send mails using SMTP including attachments with
   * the specific parameters read from a configuration-file and delivers
   * furthermore a report, where a state to each sent mail can bee seen.
   *
   * <p>
   *         The SendMailTransformer requires classes of the mail api from sun which comes
   *  with the mail.jar and activation.jar.
   * </p>
   * <p>
   *    These two parameters can be defined already in the components-secion of the sitemap:
   *  <ul>
   *   <li>
   *     smtphost - the name of the host, e.g. "smtphost.company.com"
   *   </li>
   *   <li>
   *     from - email-adress of mail sender
   *   </li>
   *  </ul>
   * </p>
   * <p>
   * Furthermore, these parameters can be defined in the pipeline-section:
   *  <ul>
   *   <li>
   *     smtphost, from - If these values are available in the pipeline-section,
   *     values from the component-section will be overwritten
   *   </li>
   *   <li>
   *     to - email-addresses of recipients
   *     e.g.: name="to" value="customer1@target.com,customer2@target.com"
   *   </li>
   *   <li>
   *     subject - a string-value, can also come from a request-parameter
   *     e.g.; name="subject" value="{request-param:subject}"
   *   </li>
   *   <li>
   *     body - a string-value, can also come from a request-parameter
   *     e.g.; name="body" value="{request-param:body}"
   *   </li>
   *   <li>
   *     sendpartial - define, if to send the mails partial or together; the value can
   *     be true or false. The default is true.
   *     ( Note: if you send your mail to more than one recipient and you configure
   *       this parameter with false, all email-addresses will appear concatenated
   *       in the address-field at the mail-client of the recipient )
   *   </li>
   *  </ul>
   * </p>
   * <p>
   *   More configurations can be made in a specific configuration-file, which
   *   can be retrieved with a file-generator as an input document.
   * </p>
   * <p>
   *  The input document should define the following configuration entities:
   *  <ul>
   *   <li>
   *     email:smtphost, email:from and email:subject can be set to overwrite
   *     values from the sitemap
   *   </li>
   *   <li>
   *     email:to - each entry will be append to the list of email-adresses
   *   </li>
   *   <li>
   *     email:body - will overwrite the value from the sitemap
   *     if there is a "src"-attribute, the transformer will try to retrieve
   *     the file and place it instead of a text-string as the mail-body
   *   </li>
   *   <li>
   *     email:attachment - define the attachement
   *     The attribute name defines the name of the attachement. The mime-type
   *     defines the content of the attachment.
   *     If there is a nested <email:content> - tag, text can be included and the
   *     attachement will then be a plain text-file.
   *     Is there a url-attribute, the SendMailTransformer tries to retrieve the
   *     appropriate file and handle it as an attachment.
   *            To use a file as an attachment, retrieved over a protocol like http or
   *     cocoon, use the src-attribute.
   *   </li>
   *  </ul>
   * </p>
   * <p>
   *  Example:
   *
   *   &lt;?xml version="1.0" encoding="UTF-8"?&gt;
   *   &lt;document xmlns:email="http://apache.org/cocoon/transformation/sendmail"&gt;
   *     &lt;email:sendmail&gt;
   *       &lt;email:smtphost&gt;hostname.company.com&lt;/email:smtphost&gt;
   *       &lt;email:from&gt;info@company.com&lt;/email:from&gt;
   *       &lt;email:to&gt;customer3@target.com&lt;/email:to&gt;
   *       &lt;email:to&gt;customer4@target.com&lt;/email:to&gt;
   *       &lt;email:to&gt;customer5@target.com&lt;/email:to&gt;
   *       &lt;email:to&gt;customer6@target.com&lt;/email:to&gt;
   *       &lt;email:subject&gt;subject-content&lt;/email:subject&gt;
   *       &lt;email:body src="cocoon:/softwareupdate.html?locale=en&amp;country=UK"/&gt;
   *       &lt;!-- &lt;email:body&gt;some Text&lt;/email:body&gt; --&gt;
   *       &lt;email:attachment name="hello.html" mime-type="text/html"&gt;
   *         &lt;email:content&gt;
   *           Dear Customer, please visit out new Product-Shop.
   *         &lt;/email:content&gt;
   *       &lt;/email:attachment&gt;
   *       &lt;email:attachment name="hello2.html" mime-type="text/html" src="cocoon:/src1"/&gt;
   *       &lt;email:attachment name="hello3.html" mime-type="text/html"
   *          url="C:\path\softwareupdate.html"/&gt;
   *       &lt;email:attachment name="hello.gif" mime- type="image/gif"
   *          url="c:\path\powered.gif"/&gt;
   *     &lt;/email:sendmail&gt;
   *   &lt;/document&gt;
   * </p>
   * <p>
   *   After the transformation a report will be generated, where the state for each sent mail can be seen.
   *   In case of an exception, the exception-message and a stacktrace will be reported.
   * </p>
   *
   * @author <a href="mailto:pklassen@s-und-n.de">Peter Klassen</a>
   * @version CVS $Id: SendMailTransformer.java,v 1.1 2003/08/08 11:35:03 cziegeler Exp $
   *
   */
  public class SendMailTransformer extends AbstractSAXTransformer
      implements Parameterizable, Recyclable {
      /*
       * constants, related to elements in configuration-file
       */
      public static final String NAMESPACE                  = "http://apache.org/cocoon/transformation/sendmail";
      public static final String ELEMENT_SENDMAIL           = "sendmail";
      public static final String ELEMENT_SMTPHOST           = "smtphost";
      public static final String ELEMENT_MAILFROM           = "from";
      public static final String ELEMENT_MAILTO             = "to";
      public static final String ELEMENT_MAILSUBJECT        = "subject";
      public static final String ELEMENT_MAILBODY           = "body";
      public static final String ELEMENT_ATTACHMENT         = "attachment";
      public static final String ELEMENT_ATTACHMENT_CONTENT = "content";
      public static final String ELEMENT_EMAIL_PREFIX       = "email";
      public static final String ELEMENT_EMAIL_SUCCESS      = ELEMENT_EMAIL_PREFIX +
                                                              ":success";
      public static final String ELEMENT_EMAIL_FAILURE      = ELEMENT_EMAIL_PREFIX +
                                                              ":failure";
  
      /*
       * mode-constants
       */
      protected static final int MODE_NONE               = 0;
      protected static final int MODE_SMTPHOST           = 1;
      protected static final int MODE_FROM               = 2;
      protected static final int MODE_TO                 = 3;
      protected static final int MODE_SUBJECT            = 4;
      protected static final int MODE_BODY               = 5;
      protected static final int MODE_ATTACHMENT         = 6;
      protected static final int MODE_ATTACHMENT_CONTENT = 7;
  
      /*
       * constants, related to parameter from request
       */
      public final static String PARAM_SMTPHOST    = "smtphost";
      public final static String PARAM_FROM        = "from";
      public final static String PARAM_TO          = "to";
      public final static String PARAM_SUBJECT     = "subject";
      public final static String PARAM_BODY        = "body";
      public final static String PARAM_SENDPARTIAL = "sendpartial";
      protected int              mode;
  
      /*
       * communication parameters, which will be used to send mails
       */
      protected Vector               toAddresses;
      protected Vector               attachments;
      protected StringBuffer         subject;
      protected StringBuffer         body;
      protected String               bodyURI;
      protected String               mailHost;
      protected String               fromAddress;
      protected AttachmentDescriptor attachmentDescriptor;
      protected int                  port;
      protected String               contextPath;
      protected boolean              sendPartial;
      protected Message              smtpMessage = null;
  
      /**
       * create a new Transformer
       */
      public SendMailTransformer() {
          this.defaultNamespaceURI = NAMESPACE;
      }
  
      /**
       * invoked every time when the transformer is triggered by the pipeline
       */
      public void setup(SourceResolver resolver, Map objectModel, String src,
                        Parameters par)
                 throws ProcessingException, SAXException, IOException {
          super.setup(resolver, objectModel, src, par);
          this.mailHost    = par.getParameter(PARAM_SMTPHOST, "");
          this.fromAddress = par.getParameter(PARAM_FROM, "");
          this.port        = this.request.getServerPort();
          this.contextPath = this.request.getContextPath();
          this.sendPartial = par.getParameterAsBoolean(PARAM_SENDPARTIAL, true);
  
          if (this.getLogger().isDebugEnabled() == true) {
              this.getLogger().debug("overwritten by Transformer-Parameters in Pipeline");
              this.getLogger().debug("overwritten Parameters=" + mailHost + ":" +
                                     fromAddress);
          }
  
          String s = par.getParameter(PARAM_TO, "");
          this.toAddresses = new Vector();
          this.attachments = new Vector();
          this.appendToAddress(s, ";");
  
          try {
              this.subject = new StringBuffer(par.getParameter(PARAM_SUBJECT));
              this.body    = new StringBuffer(par.getParameter(PARAM_BODY));
          } catch (Exception e) {
              this.getLogger().error("Error while retrieving Parameter", e);
          }
  
          this.defaultNamespaceURI = NAMESPACE;
      }
  
      /**
       * invoked initially
       */
      public void parameterize(Parameters parameters) throws ParameterException {
          // nothing to do by now
      }
  
      /**
       * overwritten method of AbstractSAXTransformer
       */
      public void startTransformingElement(String uri, String name, String raw,
                                           Attributes attr)
                                    throws SAXException {
          if (this.getLogger().isDebugEnabled() == true) {
              this.getLogger().debug("BEGIN startElement uri=" + uri + ", name=" +
                                     name + ", raw=" + raw + ", attr=" + attr);
          }
  
          if (name.equals(ELEMENT_SENDMAIL) == true) {
              // No need to do anything here
          } else if (name.equals(ELEMENT_SMTPHOST) == true) {
              this.startTextRecording();
              this.mode = MODE_SMTPHOST;
          } else if (name.equals(ELEMENT_MAILFROM) == true) {
              //this.fromAddress = attr.getValue(ELEMENT_MAILFROM);
              this.startTextRecording();
              this.mode = MODE_FROM;
          } else if (name.equals(ELEMENT_MAILTO) == true) {
              this.startTextRecording();
              this.mode = MODE_TO;
          } else if (name.equals(ELEMENT_MAILSUBJECT) == true) {
              this.startTextRecording();
              this.mode = MODE_SUBJECT;
          } else if (name.equals(ELEMENT_MAILBODY) == true) {
              String strBody = attr.getValue("src");
  
              if (strBody != null) {
                  this.bodyURI = new String(strBody);
              }
  
              this.startTextRecording();
              this.mode = MODE_BODY;
          } else if (name.equals(ELEMENT_ATTACHMENT) == true) {
              this.attachmentDescriptor = new AttachmentDescriptor(attr.getValue("name"),
                                                                   attr.getValue("mime-type"),
                                                                   attr.getValue("src"),
                                                                   attr.getValue("url"));
              this.mode = MODE_ATTACHMENT;
          } else if (name.equals(ELEMENT_ATTACHMENT_CONTENT) == true) {
              this.startSerializedXMLRecording(new Properties());
              this.mode = MODE_ATTACHMENT_CONTENT;
          } else {
              throw new SAXException("Unknown element " + name);
          }
  
          if (this.getLogger().isDebugEnabled() == true) {
              this.getLogger().debug("END startElement");
          }
      }
  
      /**
       * overwritten method of AbstractSAXTransformer
       */
      public void endTransformingElement(String uri, String name, String raw)
                                  throws SAXException, ProcessingException {
          if (this.getLogger().isDebugEnabled() == true) {
              this.getLogger().debug("BEGIN endTransformingElement uri=" + uri +
                                     ", name=" + name + ", raw=" + raw);
          }
  
          if (name.equals(ELEMENT_SENDMAIL) == true) {
              if (this.getLogger().isInfoEnabled() == true) {
                  this.getLogger().info("Mail contents- Subject: " +
                                        this.subject + "\n" + "Body: " +
                                        this.body);
              }
  
              sendMail();
          } else if (name.equals(ELEMENT_SMTPHOST) == true) {
              this.mailHost = this.endTextRecording();
              this.mode     = MODE_NONE;
          } else if (name.equals(ELEMENT_MAILFROM) == true) {
              this.fromAddress = this.endTextRecording();
              this.mode        = MODE_NONE;
          } else if (name.equals(ELEMENT_MAILTO) == true) {
              this.toAddresses.add(this.endTextRecording());
              this.mode = MODE_NONE;
          } else if (name.equals(ELEMENT_MAILSUBJECT) == true) {
              String strSubject = this.endTextRecording();
  
              if (strSubject != null) {
                  this.subject = new StringBuffer(strSubject);
              } else {
                  this.getLogger().debug("Mail-Subject not available");
              }
  
              this.mode = MODE_NONE;
          } else if (name.equals(ELEMENT_ATTACHMENT) == true) {
              this.attachments.add(this.attachmentDescriptor.copy());
              this.attachmentDescriptor = null;
              this.mode                 = MODE_NONE;
          } else if (name.equals(ELEMENT_ATTACHMENT_CONTENT) == true) {
              this.attachmentDescriptor.setContent(new StringBuffer(this.endSerializedXMLRecording()));
              this.mode = MODE_NONE;
          } else if (name.equals(ELEMENT_MAILBODY) == true) {
              String strB = null;
  
              try {
                  strB = new String(this.endTextRecording());
              } catch (Exception e) {
                  if (this.getLogger().isDebugEnabled()) {
                      this.getLogger().debug("No Body as String in config-file available");
                  }
              }
  
              if (strB != null) {
                  this.body = new StringBuffer(strB);
              }
  
              this.mode = MODE_NONE;
          } else {
              throw new SAXException("Unknown element " + name);
          }
  
          if (this.getLogger().isDebugEnabled() == true) {
              this.getLogger().debug("END endElement");
          }
      }
  
      private void appendToAddress(String s, String delim) {
          StringTokenizer t = null;
          t = new StringTokenizer(s.trim(), delim);
  
          int i = 0;
  
          while (t.hasMoreElements()) {
              this.toAddresses.add(t.nextToken());
          }
      }
  
      /**
       *
       * @throws SAXException
       */
      private void sendMail() throws SAXException {
          try {
              Properties props = new Properties();
              props.put("mail.smtp.host", this.mailHost);
  
              if (this.subject == null) {
                  super.sendStartElementEvent("email:error");
                  super.sendTextEvent("Subject not available - sending mail aborted");
                  super.sendEndElementEvent("email:error");
  
                  return;
              }
  
              if ((this.body == null) && (this.bodyURI == null)) {
                  super.sendStartElementEvent("email:error");
                  super.sendTextEvent("Mailbody not available - sending mail aborted");
                  super.sendEndElementEvent("email:error");
  
                  return;
              }
  
              Session   session = Session.getDefaultInstance(props, null);
              Transport trans = null;
  
              trans = session.getTransport("smtp");
              trans.connect();
  
              if (this.smtpMessage == null) {
                  this.smtpMessage = setUpMessage(session);
              }
  
              super.sendStartElementEvent("email:result");
  
              if (this.sendPartial == true) {
                  for (int i = 0; i < this.toAddresses.size(); i++) {
                      Vector v = new Vector(1);
                      v.add(this.toAddresses.elementAt(i));
                      sendMail(v, trans);
                  }
              } else {
                  sendMail(this.toAddresses, trans);
              }
  
              trans.close();
              super.sendEndElementEvent("email:result");
          } catch (Exception sE) {
              this.getLogger().error("sendMail-Error", sE);
              this.sendExceptionElement(sE);
          }
      }
  
      /**
       * @see http://java.sun.com/products/javamail/1.3/docs/javadocs/com/sun/mail/smtp/package-summary.html
       * @throws Exception
       */
      private void sendMail(Vector newAddresses, Transport trans)
                     throws Exception {
          AddressHandler[] iA = new AddressHandler[newAddresses.size()];
  
          for (int i = 0; i < newAddresses.size(); i++) {
              InternetAddress inA = new InternetAddress((String) newAddresses.elementAt(i));
              iA[i] = new AddressHandler(inA);
          }
  
          try {
              InternetAddress[] iaArr = SendMailTransformer.getAddresses(iA);
              this.smtpMessage.setRecipients(Message.RecipientType.TO, iaArr);
              trans.sendMessage(this.smtpMessage, iaArr);
          } catch (SendFailedException sfEx) {
              this.getLogger().error("Exception during sending of mail", sfEx);
  
              Address[] adr = sfEx.getInvalidAddresses();
  
              for (int isfEx = 0; isfEx < iA.length; isfEx++) {
                  String tmpAddress = iA[isfEx].getAddress().getAddress();
  
                  for (int sei = 0; sei < adr.length; sei++) {
                      if (((InternetAddress) adr[sei]).getAddress()
                               .equalsIgnoreCase(tmpAddress)) {
                          iA[isfEx].setSendMailResult("Invalid address");
                      }
                  }
              }
  
              Address[] ad = sfEx.getValidUnsentAddresses();
  
              for (int isfEx = 0; isfEx < iA.length; isfEx++) {
                  String tmpAddress = iA[isfEx].getAddress().getAddress();
  
                  for (int sei = 0; sei < ad.length; sei++) {
                      if (((InternetAddress) ad[sei]).getAddress()
                               .equalsIgnoreCase(tmpAddress)) {
                          iA[isfEx].setSendMailResult("Recipient not found");
                      }
                  }
              }
          } catch (Exception e) {
              this.getLogger().error("Exception during sending of mail", e);
              this.sendExceptionElement(e);
  
              return;
          }
  
          generateSAXReportStatements(iA);
      }
  
      private Message setUpMessage(Session session) throws Exception {
          Message sm = new MimeMessage(session);
  
          //sm.setAllow8bitMIME(true);
          sm.setFrom(new InternetAddress(this.fromAddress));
          sm.setSubject(this.subject.toString());
  
          // process mail-body 					
          BodyPart messageBodyPart = new MimeBodyPart();
  
          // decide, if to take content from source or plain text 
          // from variable to build mailbody
          if (this.bodyURI != null) {
              Source      inSrc   = resolver.resolveURI(this.bodyURI);
              InputStream inStr   = inSrc.getInputStream();
              byte[]      byteArr = new byte[inStr.available()];
              inStr.read(byteArr);
  
              String mailBody = new String(byteArr);
              messageBodyPart.setContent(mailBody, "text/html");
          } else {
              messageBodyPart.setContent(this.body.toString(), "text/html");
          }
  
          Multipart multipart = new MimeMultipart();
          multipart.addBodyPart(messageBodyPart);
  
          // process attachments				
          Enumeration enumAtt = this.attachments.elements();
  
          while (enumAtt.hasMoreElements()) {
              AttachmentDescriptor aD = (AttachmentDescriptor) enumAtt.nextElement();
              messageBodyPart = new MimeBodyPart();
  
              if (!aD.isTextContent()) {
                  Source     inputSource = null;
                  DataSource dataSource = null;
  
                  if (aD.isURLSource()) {
                      inputSource = resolver.resolveURI(aD.strAttrSrc);
  
                      String iSS = new String(inputSource.getURI());
  
                      if (iSS.startsWith("cocoon:")) {
                          iSS = iSS.substring(7, iSS.length());
  
                          if (this.contextPath != null) {
                              iSS = "http://localhost:" + this.port +
                                    this.contextPath + iSS;
                          } else {
                              iSS = "http://localhost:" + this.port + iSS;
                          }
  
                          if (this.getLogger().isDebugEnabled() == true) {
                              this.getLogger().debug("cocoon-URI changed to " +
                                                     iSS);
                          }
  
                          dataSource = new URLDataSource(new URL(iSS));
                      } else {
                          dataSource = new URLDataSource(new URL(inputSource.getURI()));
                      }
  
                      messageBodyPart.setDataHandler(new DataHandler(dataSource));
                  } else if (aD.isFileSource()) {
                      inputSource = resolver.resolveURI(aD.strAttrFile);
                      dataSource  = new URLDataSource(new URL(inputSource.getURI()));
                      messageBodyPart.setDataHandler(new DataHandler(dataSource));
                  }
              } else {
                  messageBodyPart.setContent(aD.strBufContent.toString(),
                                             aD.strAttrMimeType);
              }
  
              messageBodyPart.setFileName(aD.strAttrName);
              multipart.addBodyPart(messageBodyPart);
          }
  
          sm.setContent(multipart);
  
          //sm.setReturnOption(SMTPMessage.RETURN_FULL);
          sm.saveChanges();
  
          return sm;
      }
  
      private void generateSAXReportStatements(AddressHandler[] addressArr)
                                        throws SAXException {
          AttributesImpl impl = new AttributesImpl();
  
          for (int i = 0; i < addressArr.length; i++) {
              String tmpAddress = addressArr[i].getAddress().getAddress();
  
              if (addressArr[i].getSendMailResult() == null) {
                  impl.addAttribute(NAMESPACE, ELEMENT_EMAIL_SUCCESS, "to",
                                    "CDATA", tmpAddress);
                  super.sendStartElementEvent(ELEMENT_EMAIL_SUCCESS, impl);
                  super.sendTextEvent("Mail sent");
                  super.sendEndElementEvent(ELEMENT_EMAIL_SUCCESS);
              } else {
                  impl.addAttribute(NAMESPACE, ELEMENT_EMAIL_FAILURE, "to",
                                    "CDATA", tmpAddress);
                  super.sendStartElementEvent(ELEMENT_EMAIL_FAILURE, impl);
                  super.sendTextEvent(addressArr[i].getSendMailResult());
                  super.sendEndElementEvent(ELEMENT_EMAIL_FAILURE);
              }
          }
      }
  
      private void sendExceptionElement(Exception ex) {
          try {
              super.sendStartElementEvent("email:exception");
              super.sendStartElementEvent("email:message");
              super.sendTextEvent(ex.getMessage());
              super.sendEndElementEvent("email:message");
              super.sendStartElementEvent("email:stacktrace");
  
              for (int i = 0; i < ex.getStackTrace().length; i++) {
                  String s = ((StackTraceElement) ex.getStackTrace()[i]).toString();
                  super.sendTextEvent(s + "\n");
              }
  
              super.sendEndElementEvent("email:stacktrace");
              super.sendEndElementEvent("email:exception");
          } catch (SAXException e) {
              this.getLogger().error("Error while sending a SAX-Event", e);
          }
      }
  
      public static InternetAddress[] getAddresses(AddressHandler[] handlerArr) {
          InternetAddress[] iaArr = new InternetAddress[handlerArr.length];
  
          for (int i = 0; i < handlerArr.length; i++) {
              iaArr[i] = handlerArr[i].getAddress();
          }
  
          return iaArr;
      }
  
      class AttachmentDescriptor {
          String       strAttrName     = null;
          String       strAttrMimeType = null;
          String       strAttrSrc      = null;
          String       strAttrFile     = null;
          StringBuffer strBufContent   = null;
  
          protected AttachmentDescriptor(String newAttrName,
                                         String newAttrMimeType,
                                         String newAttrSrc, String newAttrFile) {
              this.strAttrName     = newAttrName;
              this.strAttrMimeType = newAttrMimeType;
              this.strAttrSrc      = newAttrSrc;
              this.strAttrFile     = newAttrFile;
          }
  
          protected void setContent(StringBuffer newContent) {
              strBufContent = newContent;
          }
  
          protected AttachmentDescriptor copy() {
              AttachmentDescriptor aD = new AttachmentDescriptor(this.strAttrName,
                                                                 this.strAttrMimeType,
                                                                 this.strAttrSrc,
                                                                 this.strAttrFile);
              aD.setContent(this.strBufContent);
  
              return aD;
          }
  
          protected boolean isURLSource() {
              return (this.strAttrSrc != null) ? true : false;
          }
  
          protected boolean isFileSource() {
              return (this.strAttrFile != null) ? true : false;
          }
  
          protected boolean isTextContent() {
              return (this.strBufContent != null) ? true : false;
          }
      }
  
      class AddressHandler {
          private InternetAddress address        = null;
          private String          sendMailResult = null;
  
          protected AddressHandler(InternetAddress newAddress) {
              this.address = newAddress;
          }
  
          protected void setSendMailResult(String newSendMailResult) {
              this.sendMailResult = newSendMailResult;
          }
  
          /**
           * @return mail-address
           */
          public InternetAddress getAddress() {
              return address;
          }
  
          /**
           * @return sendMailResult as String
           */
          public String getSendMailResult() {
              return sendMailResult;
          }
      }
  }