1
2 package com.atlassian.mail.server.impl;
3
4 import com.atlassian.mail.Email;
5 import com.atlassian.mail.MailConstants;
6 import com.atlassian.mail.MailException;
7 import com.atlassian.mail.MailFactory;
8 import com.atlassian.mail.MailProtocol;
9 import com.atlassian.mail.server.AbstractMailServer;
10 import com.atlassian.mail.server.MailServerManager;
11 import com.atlassian.mail.server.SMTPMailServer;
12 import com.atlassian.mail.server.impl.util.MessageCreator;
13 import org.apache.commons.lang.builder.ToStringBuilder;
14
15 import javax.mail.Authenticator;
16 import javax.mail.MessagingException;
17 import javax.mail.PasswordAuthentication;
18 import javax.mail.Session;
19 import javax.mail.Transport;
20 import javax.mail.URLName;
21 import javax.mail.internet.MimeMessage;
22 import javax.naming.Context;
23 import javax.naming.InitialContext;
24 import javax.naming.NamingException;
25 import java.io.UnsupportedEncodingException;
26 import java.util.Properties;
27
28 import static com.atlassian.mail.MailConstants.DEFAULT_SMTP_PROTOCOL;
29 import static com.atlassian.mail.MailConstants.DEFAULT_TIMEOUT;
30
31 public class SMTPMailServerImpl extends AbstractMailServer implements SMTPMailServer
32 {
33 private boolean isSessionServer;
34 private String defaultFrom;
35 private String prefix;
36 private String jndiLocation;
37 private boolean removePrecedence;
38 private transient Session session;
39
40 public SMTPMailServerImpl()
41 {
42 }
43
44 public SMTPMailServerImpl(Long id, String name, String description, String from, String prefix, boolean isSession, String location, String username, String password)
45 {
46 this(id, name, description, from, prefix, isSession, DEFAULT_SMTP_PROTOCOL, location, MailConstants.DEFAULT_SMTP_PORT, false, username, password);
47 }
48
49 public SMTPMailServerImpl(Long id, String name, String description, String from, String prefix, boolean isSession, MailProtocol protocol, String location, String smtpPort, boolean tlsRequired, String username, String password)
50 {
51 this(id, name, description, from, prefix, isSession, false, protocol, location, smtpPort, tlsRequired, username, password, DEFAULT_TIMEOUT);
52 }
53
54 public SMTPMailServerImpl(Long id, String name, String description, String from, String prefix, boolean isSession, MailProtocol protocol, String location, String smtpPort, boolean tlsRequired, String username, String password, long timeout)
55 {
56 this(id, name, description, from, prefix, isSession, false, protocol, location, smtpPort, tlsRequired, username, password, timeout);
57 }
58
59 public SMTPMailServerImpl(Long id, String name, String description, String from, String prefix, boolean isSession, boolean removePrecedence, MailProtocol protocol, String location, String smtpPort, boolean tlsRequired, String username, String password, long timeout)
60 {
61 super(id, name, description, protocol, location, smtpPort, username, password, timeout);
62 setDefaultFrom(from);
63 setPrefix(prefix);
64 setSessionServer(isSession);
65 setRemovePrecedence(removePrecedence);
66 setTlsRequired(tlsRequired);
67
68 if (isSession)
69 {
70 setJndiLocation(location);
71 setHostname(null);
72 }
73 }
74
75 public String getJndiLocation()
76 {
77 return jndiLocation;
78 }
79
80 public void setJndiLocation(String jndiLocation)
81 {
82 this.jndiLocation = jndiLocation;
83 propertyChanged();
84 }
85
86 protected Authenticator getAuthenticator()
87 {
88 return new MyAuthenticator();
89 }
90
91
92
93
94 public Session getSession() throws NamingException, MailException
95 {
96 if (session == null)
97
98 {
99 if (isSessionServer())
100 {
101 log.debug("Getting session from JNDI");
102 Object jndiSession = getJndiSession();
103 if (jndiSession instanceof javax.mail.Session)
104 {
105 session = (Session) jndiSession;
106 }
107 else
108 {
109 log.error("Mail server at location [" + getJndiLocation() + "] is not of required type javax.mail.Session, or is in different classloader. " +
110 "It is of type '" + (jndiSession != null ? jndiSession.getClass().getName() : null) + "' in classloader '"+jndiSession.getClass().getClassLoader()+"' instead");
111 throw new IllegalArgumentException("Mail server at location [" + getJndiLocation() + "] is not of required type javax.mail.Session. ");
112 }
113 }
114 else
115 {
116 final Properties props = loadSystemProperties(getProperties());
117 final Authenticator auth = isAuthenticating ? getAuthenticator() : null;
118 session = getSessionFromServerManager(props, auth);
119 if (auth != null)
120 {
121 session.setPasswordAuthentication(new URLName(getMailProtocol().getProtocol(), getHostname(), Integer.parseInt(getPort()),null, null, null), new PasswordAuthentication(getUsername(),getPassword()));
122 }
123 }
124 }
125 return session;
126 }
127
128 protected Object getJndiSession() throws NamingException
129 {
130 Context ctx = new InitialContext();
131 Object jndiSession = ctx.lookup(getJndiLocation());
132 return jndiSession;
133 }
134
135 public void send(Email email) throws MailException
136 {
137 try
138 {
139 Session thisSession = getSession();
140
141 MimeMessage message = new MimeMessage(thisSession);
142 MessageCreator messageCreator = new MessageCreator();
143
144 messageCreator.updateMimeMessage(email, getDefaultFrom(), prefix, message);
145
146 log.debug("Getting transport for protocol [" + getMailProtocol().getProtocol() + "]");
147
148 final Transport transport = thisSession.getTransport(getMailProtocol().getProtocol());
149 try {
150 if (log.isDebugEnabled())
151 {
152 log.debug("Got transport: [" + transport + "]. Connecting");
153 }
154 transport.connect();
155 log.debug("Sending message");
156 transport.sendMessage(message, message.getAllRecipients());
157 }
158 finally
159 {
160 if (transport != null)
161 {
162 transport.close();
163 }
164 }
165
166
167 if (message.getHeader("Message-Id") != null && message.getHeader("Message-Id").length > 0)
168 {
169 final String messageId = message.getHeader("Message-Id")[0];
170 if (log.isDebugEnabled())
171 {
172 log.debug("Setting message id to [" + messageId + "]");
173 }
174 email.setMessageId(messageId);
175 }
176 }
177 catch (NamingException e)
178 {
179 throw new MailException(e);
180 }
181 catch (MessagingException e)
182 {
183 throw new MailException(e);
184 }
185 catch (UnsupportedEncodingException e)
186 {
187 log.error("Error setting the 'from' address with an email and the user's fullname", e);
188 }
189 }
190
191
192
193
194
195 public void quietSend(Email email) throws MailException
196 {
197 try
198 {
199 send(email);
200 }
201 catch (Exception e)
202 {
203 log.error("Error sending mail. to:" + email.getTo() + ", cc:" + email.getCc() + ", bcc:" + email.getBcc() + ", subject:" + email.getSubject() + ", body:" + email.getBody() + ", mimeType:" + email.getMimeType() + ", encoding:" + email.getEncoding() + ", multipart:" + email.getMultipart() + ", error:" + e, e);
204 }
205 }
206
207 public String getType()
208 {
209 return MailServerManager.SERVER_TYPES[1];
210 }
211
212 public String getDefaultFrom()
213 {
214 return defaultFrom;
215 }
216
217 public void setDefaultFrom(String defaultFrom)
218 {
219 this.defaultFrom = defaultFrom;
220 propertyChanged();
221 }
222
223 public String getPrefix()
224 {
225 return prefix;
226 }
227
228 public void setPrefix(String prefix)
229 {
230 this.prefix = prefix;
231 }
232
233 public boolean isRemovePrecedence()
234 {
235 return removePrecedence;
236 }
237
238 public void setRemovePrecedence(boolean precedence)
239 {
240 this.removePrecedence = precedence;
241 propertyChanged();
242 }
243
244 public boolean isSessionServer()
245 {
246 return isSessionServer;
247 }
248
249 public void setSessionServer(boolean sessionServer)
250 {
251 isSessionServer = sessionServer;
252 propertyChanged();
253 }
254
255 private class MyAuthenticator extends Authenticator
256 {
257 public PasswordAuthentication getPasswordAuthentication()
258 {
259 return new PasswordAuthentication(getUsername(), getPassword());
260 }
261 }
262
263
264 public boolean equals(Object o)
265 {
266 if (this == o)
267 {
268 return true;
269 }
270 if (!(o instanceof SMTPMailServerImpl))
271 {
272 return false;
273 }
274 if (!super.equals(o))
275 {
276 return false;
277 }
278
279 final SMTPMailServerImpl smtpMailServer = (SMTPMailServerImpl) o;
280
281 if (isSessionServer != smtpMailServer.isSessionServer)
282 {
283 return false;
284 }
285 if (defaultFrom != null ? !defaultFrom.equals(smtpMailServer.defaultFrom) : smtpMailServer.defaultFrom != null)
286 {
287 return false;
288 }
289 if (prefix != null ? !prefix.equals(smtpMailServer.prefix) : smtpMailServer.prefix != null)
290 {
291 return false;
292 }
293 if (removePrecedence != smtpMailServer.removePrecedence)
294 {
295 return false;
296 }
297
298 return true;
299 }
300
301 public int hashCode()
302 {
303 int result = super.hashCode();
304 result = 29 * result + (isSessionServer ? 1 : 0);
305 result = 29 * result + (defaultFrom != null ? defaultFrom.hashCode() : 0);
306 result = 29 * result + (prefix != null ? prefix.hashCode() : 0);
307 result = 29 * result + (removePrecedence ? 1 : 0);
308 return result;
309 }
310
311 public String toString()
312 {
313 return new ToStringBuilder(this).append("id", getId()).append("name", getName()).append("description", getDescription()).append("server name", getHostname()).append("username", getUsername()).append("password", getPassword()).append("isSessionServer", isSessionServer).append("defaultFrom", defaultFrom).append("prefix", prefix).append("smtpPort", getPort()).toString();
314 }
315
316
317
318
319 protected void propertyChanged()
320 {
321 super.propertyChanged();
322 session = null;
323 }
324 }