View Javadoc
1   /*
2    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
3    * The software in this package is published under the terms of the CPAL v1.0
4    * license, a copy of which has been included with this distribution in the
5    * LICENSE.txt file.
6    */
7   package org.mule.transport.email;
8   
9   import org.mule.DefaultMuleMessage;
10  import org.mule.api.MuleEvent;
11  import org.mule.api.MuleMessage;
12  import org.mule.api.endpoint.EndpointException;
13  import org.mule.api.endpoint.EndpointURI;
14  import org.mule.api.endpoint.OutboundEndpoint;
15  import org.mule.api.transport.DispatchException;
16  import org.mule.config.i18n.CoreMessages;
17  import org.mule.config.i18n.MessageFactory;
18  import org.mule.transport.AbstractMessageDispatcher;
19  import org.mule.transport.NullPayload;
20  
21  import com.sun.mail.smtp.SMTPTransport;
22  
23  import java.net.URLDecoder;
24  import java.util.Calendar;
25  
26  import javax.mail.Message;
27  import javax.mail.MessagingException;
28  import javax.mail.Transport;
29  
30  /**
31   * <code>SmtpMessageDispatcher</code> will dispatch Mule events as Mime email
32   * messages over an SMTP gateway.
33   * 
34   * This contains a reference to a transport (and endpoint and connector, via superclasses)
35   */
36  public class SmtpMessageDispatcher extends AbstractMessageDispatcher
37  {
38      private volatile Transport transport;
39  
40      public SmtpMessageDispatcher(OutboundEndpoint endpoint)
41      {
42          super(endpoint);
43      }
44  
45      private SmtpConnector castConnector()
46      {
47          return (SmtpConnector) getConnector();
48      }
49  
50      @Override
51      protected void doConnect() throws Exception
52      {
53          if (transport == null)
54          {
55              try
56              {
57  
58                  transport = castConnector().getSessionDetails(endpoint).newTransport();
59                  EndpointURI uri = endpoint.getEndpointURI();
60                  String encoding = endpoint.getEncoding();
61                  String user = (uri.getUser()!=null ? URLDecoder.decode(uri.getUser(), encoding) : null);
62                  String pass = (uri.getPassword()!=null ? URLDecoder.decode(uri.getPassword(), encoding) : null);
63                  transport.connect(uri.getHost(), uri.getPort(),  user, pass);
64              }
65              catch (Exception e)
66              {
67                  throw new EndpointException(
68                      MessageFactory.createStaticMessage("Unable to connect to mail transport."), e);
69              }
70          }
71      }
72  
73      @Override
74      protected void doDisconnect() throws Exception
75      {
76          if (null != transport)
77          {
78              try
79              {
80                  transport.close();
81              }
82              finally
83              {
84                  transport = null;
85              }
86          }
87      }
88  
89      @Override
90      protected void doDispatch(MuleEvent event) throws Exception
91      {
92          Object data = event.getMessage().getPayload();
93  
94          if (!(data instanceof Message))
95          {
96              throw new DispatchException(
97                  CoreMessages.transformUnexpectedType(data.getClass(), Message.class),
98                  event, this);
99          }
100         else
101         {
102             // Check the message for any unset data and use defaults
103             sendMailMessage((Message) data);
104         }
105     }
106 
107     @Override
108     protected MuleMessage doSend(MuleEvent event) throws Exception
109     {
110         doDispatch(event);
111         return new DefaultMuleMessage(NullPayload.getInstance(), connector.getMuleContext());
112     }
113 
114     protected void sendMailMessage(Message message) throws MessagingException
115     {
116         // sent date
117         message.setSentDate(Calendar.getInstance().getTime());
118 
119          // Double check that the transport is still connected as some SMTP servers may 
120          // disconnect idle connections.
121         if (isTransportConnected() == false)
122         {
123             EndpointURI uri = endpoint.getEndpointURI();
124             if (logger.isInfoEnabled())
125             {
126                 logger.info("Connection closed by remote server. Reconnecting.");
127             }
128             transport.connect(uri.getHost(), uri.getPort(), uri.getUser(), uri.getPassword());
129         }
130 
131         transport.sendMessage(message, message.getAllRecipients());
132 
133         if (logger.isDebugEnabled())
134         {
135             StringBuffer msg = new StringBuffer();
136             msg.append("Email message sent with subject'").append(message.getSubject()).append("' sent- ");
137             msg.append(", From: ").append(MailUtils.mailAddressesToString(message.getFrom())).append(" ");
138             msg.append(", To: ").append(
139                 MailUtils.mailAddressesToString(message.getRecipients(Message.RecipientType.TO))).append(" ");
140             msg.append(", Cc: ").append(
141                 MailUtils.mailAddressesToString(message.getRecipients(Message.RecipientType.CC))).append(" ");
142             msg.append(", Bcc: ")
143             .append(MailUtils.mailAddressesToString(message.getRecipients(Message.RecipientType.BCC)))
144             .append(" ");
145             msg.append(", ReplyTo: ").append(MailUtils.mailAddressesToString(message.getReplyTo()));
146 
147             logger.debug(msg.toString());
148         }
149 
150     }
151     
152     // Fix incompatibility between JavaMail and Exchange 
153     // see http://forums.sun.com/thread.jspa?threadID=5409031&tstart=1
154     protected boolean isTransportConnected()
155     {
156         boolean isConnected = false;
157         
158         isConnected = transport.isConnected();
159         if (isConnected)
160         {
161             SMTPTransport smtpTransport = (SMTPTransport) transport;
162             
163             String lastServerResponse = smtpTransport.getLastServerResponse();
164             if (lastServerResponse.startsWith("250") == false) 
165             {
166                 isConnected = false;
167                 try
168                 {
169                     smtpTransport.close();
170                 }
171                 catch (MessagingException me)
172                 {
173                     if (logger.isInfoEnabled())
174                     {
175                         logger.info("Unable to close SMTP Transport", me);
176                     }
177                 }
178             }
179         }
180         
181         return isConnected;
182     }
183 
184     @Override
185     protected void doDispose()
186     {
187         // nothing doing
188     }
189 
190 }