View Javadoc

1   /*****************************************************************
2    * Licensed to the Apache Software Foundation (ASF) under one   *
3    * or more contributor license agreements.  See the NOTICE file *
4    * distributed with this work for additional information        *
5    * regarding copyright ownership.  The ASF licenses this file   *
6    * to you under the Apache License, Version 2.0 (the            *
7    * "License"); you may not use this file except in compliance   *
8    * with the License.  You may obtain a copy of the License at   *
9    *                                                              *
10   *   http://www.apache.org/licenses/LICENSE-2.0                 *
11   *                                                              *
12   * Unless required by applicable law or agreed to in writing,   *
13   * software distributed under the License is distributed on an  *
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
15   * KIND, either express or implied.  See the License for the    *
16   * specific language governing permissions and limitations      *
17   * under the License.                                           *
18   ****************************************************************/
19  
20  package org.apache.james.transport.mailets;
21  
22  import org.apache.mailet.RFC2822Headers;
23  import org.apache.mailet.GenericMailet;
24  import org.apache.mailet.Mail;
25  import org.apache.mailet.MailAddress;
26  import org.apache.mailet.MailetException;
27  
28  import javax.mail.Address;
29  import javax.mail.Message;
30  import javax.mail.MessagingException;
31  import javax.mail.Session;
32  import javax.mail.internet.InternetAddress;
33  import javax.mail.internet.MimeBodyPart;
34  import javax.mail.internet.MimeMessage;
35  import javax.mail.internet.MimeMultipart;
36  import java.io.IOException;
37  import java.io.PrintWriter;
38  import java.io.StringWriter;
39  import java.util.Date;
40  import java.util.HashSet;
41  import java.util.Set;
42  import java.util.Collection;
43  import java.util.Iterator;
44  import java.util.ArrayList;
45  
46  /***
47   * <P>Generates a response to the reverse-path address.
48   * Note that this is different than a mail-client's
49   * reply, which would use the Reply-To or From header.</P>
50   * <P>Bounced messages are attached in their entirety (headers and
51   * content) and the resulting MIME part type is "message/rfc822".<BR>
52   * The reverse-path and the Return-Path header of the response is set to "null" ("<>"),
53   * meaning that no reply should be sent.</P>
54   * <P>A sender of the notification message can optionally be specified.
55   * If one is not specified, the postmaster's address will be used.<BR>
56   * A notice text can be specified, and in such case will be inserted into the
57   * notification inline text.<BR>
58   * If the notified message has an "error message" set, it will be inserted into the
59   * notification inline text. If the <CODE>attachStackTrace</CODE> init parameter
60   * is set to true, such error message will be attached to the notification message.<BR>
61   * <P>Supports the <CODE>passThrough</CODE> init parameter (true if missing).</P>
62   *
63   * <P>Sample configuration:</P>
64   * <PRE><CODE>
65   * &lt;mailet match="All" class="Bounce">
66   *   &lt;sender&gt;<I>an address or postmaster or sender or unaltered, default=postmaster</I>&lt;/sender&gt;
67   *   &lt;attachError&gt;<I>true or false, default=false</I>&lt;/attachError&gt;
68   *   &lt;message&gt;<I>notice attached to the original message text (optional)</I>&lt;/message&gt;
69   *   &lt;prefix&gt;<I>optional subject prefix prepended to the original message</I>&lt;/prefix&gt;
70   *   &lt;inline&gt;<I>see {@link Resend}, default=none</I>&lt;/inline&gt;
71   *   &lt;attachment&gt;<I>see {@link Resend}, default=message</I>&lt;/attachment&gt;
72   *   &lt;passThrough&gt;<I>true or false, default=true</I>&lt;/passThrough&gt;
73   *   &lt;fakeDomainCheck&gt;<I>true or false, default=true</I>&lt;/fakeDomainCheck&gt;
74   *   &lt;debug&gt;<I>true or false, default=false</I>&lt;/debug&gt;
75   * &lt;/mailet&gt;
76   * </CODE></PRE>
77   *
78   * <P>The behaviour of this mailet is equivalent to using Resend with the following
79   * configuration:</P>
80   * <PRE><CODE>
81   * &lt;mailet match="All" class="Resend">
82   *   &lt;sender&gt;<I>an address or postmaster or sender or unaltered</I>&lt;/sender&gt;
83   *   &lt;attachError&gt;<I>true or false</I>&lt;/attachError&gt;
84   *   &lt;message&gt;<I><B>dynamically built</B></I>&lt;/message&gt;
85   *   &lt;prefix&gt;<I>a string</I>&lt;/prefix&gt;
86   *   &lt;passThrough&gt;true or false&lt;/passThrough&gt;
87   *   &lt;fakeDomainCheck&gt;<I>true or false</I>&lt;/fakeDomainCheck&gt;
88   *   &lt;recipients&gt;<B>sender</B>&lt;/recipients&gt;
89   *   &lt;reversePath&gt;null&lt;/reversePath&gt;
90   *   &lt;inline&gt;see {@link Resend}&lt;/inline&gt;
91   *   &lt;attachment&gt;see {@link Resend}&lt;/attachment&gt;
92   *   &lt;isReply&gt;true&lt;/isReply&gt;
93   *   &lt;debug&gt;<I>true or false</I>&lt;/debug&gt;
94   * &lt;/mailet&gt;
95   * </CODE></PRE>
96   * <P><I>notice</I> and <I>sendingAddress</I> can be used instead of
97   * <I>message</I> and <I>sender</I>; such names are kept for backward compatibility.</P>
98   *
99   * @version CVS $Revision: 494012 $ $Date: 2007-01-08 10:23:58 +0000 (Mon, 08 Jan 2007) $
100  * @since 2.2.0
101  */
102 public class Bounce extends AbstractNotify {
103 
104     /***
105      * Return a string describing this mailet.
106      *
107      * @return a string describing this mailet
108      */
109     public String getMailetInfo() {
110         return "Bounce Mailet";
111     }
112 
113     /*** Gets the expected init parameters. */
114     protected  String[] getAllowedInitParameters() {
115         String[] allowedArray = {
116 //            "static",
117             "debug",
118             "passThrough",
119             "fakeDomainCheck",
120             "inline",
121             "attachment",
122             "message",
123             "notice",
124             "sender",
125             "sendingAddress",
126             "prefix",
127             "attachError",
128         };
129         return allowedArray;
130     }
131     
132     /* ******************************************************************** */
133     /* ****************** Begin of getX and setX methods ****************** */
134     /* ******************************************************************** */
135 
136     /***
137      * @return <CODE>SpecialAddress.REVERSE_PATH</CODE>
138      */
139     protected Collection getRecipients() {
140         Collection newRecipients = new HashSet();
141         newRecipients.add(SpecialAddress.REVERSE_PATH);
142         return newRecipients;
143     }
144 
145     /***
146      * @return <CODE>SpecialAddress.REVERSE_PATH</CODE>
147      */
148     protected InternetAddress[] getTo() {
149         InternetAddress[] apparentlyTo = new InternetAddress[1];
150         apparentlyTo[0] = SpecialAddress.REVERSE_PATH.toInternetAddress();
151         return apparentlyTo;
152     }
153 
154     /***
155      * @return <CODE>SpecialAddress.NULL</CODE> (the meaning of bounce)
156      */
157     protected MailAddress getReversePath(Mail originalMail) {
158         return SpecialAddress.NULL;
159     }
160 
161     /* ******************************************************************** */
162     /* ******************* End of getX and setX methods ******************* */
163     /* ******************************************************************** */
164 
165     /***
166      * Service does the hard work,and redirects the originalMail in the form specified.
167      * Checks that the original return path is not empty,
168      * and then calls super.service(originalMail), otherwise just returns.
169      *
170      * @param originalMail the mail to process and redirect
171      * @throws MessagingException if a problem arises formulating the redirected mail
172      */
173     public void service(Mail originalMail) throws MessagingException {
174         if (originalMail.getSender() == null) {
175             if (isDebug)
176                 log("Processing a bounce request for a message with an empty reverse-path.  No bounce will be sent.");
177             if(!getPassThrough(originalMail)) {
178                 originalMail.setState(Mail.GHOST);
179             }
180             return;
181         }
182 
183         if (isDebug)
184             log("Processing a bounce request for a message with a reverse path.  The bounce will be sent to " + originalMail.getSender().toString());
185 
186         super.service(originalMail);
187     }
188 
189 }
190