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