1
2
3
4
5
6
7
8
9
10
11 package ch.qos.logback.core.net;
12
13 import java.util.ArrayList;
14 import java.util.Date;
15 import java.util.List;
16 import java.util.Properties;
17
18 import javax.mail.Message;
19 import javax.mail.MessagingException;
20 import javax.mail.Multipart;
21 import javax.mail.Session;
22 import javax.mail.Transport;
23 import javax.mail.internet.AddressException;
24 import javax.mail.internet.InternetAddress;
25 import javax.mail.internet.MimeBodyPart;
26 import javax.mail.internet.MimeMessage;
27 import javax.mail.internet.MimeMultipart;
28
29 import ch.qos.logback.core.AppenderBase;
30 import ch.qos.logback.core.Layout;
31 import ch.qos.logback.core.boolex.EvaluationException;
32 import ch.qos.logback.core.boolex.EventEvaluator;
33 import ch.qos.logback.core.util.ContentTypeUtil;
34 import ch.qos.logback.core.util.OptionHelper;
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 public abstract class SMTPAppenderBase<E> extends AppenderBase<E> {
50
51 protected Layout<E> subjectLayout;
52
53 private List<String> to = new ArrayList<String>();
54 private String from;
55 private String subjectStr = null;
56 private String smtpHost;
57 private int smtpPort = 25;
58 private boolean starttls = false;
59 private boolean ssl = false;
60
61 String username;
62 String password;
63
64 private String charsetEncoding = "UTF-8";
65
66 protected MimeMessage mimeMsg;
67
68 protected EventEvaluator<E> eventEvaluator;
69
70
71
72
73
74
75
76
77
78
79 abstract protected Layout<E> makeSubjectLayout(String subjectStr);
80
81
82
83
84 public void start() {
85 Properties props = new Properties(OptionHelper.getSystemProperties());
86 if (smtpHost != null) {
87 props.put("mail.smtp.host", smtpHost);
88 }
89 props.put("mail.smtp.port", Integer.toString(smtpPort));
90
91 LoginAuthenticator loginAuthenticator = null;
92
93 if (username != null) {
94 loginAuthenticator = new LoginAuthenticator(username, password);
95 props.put("mail.smtp.auth", "true");
96 }
97
98 if (isSTARTTLS() && isSSL()) {
99 addError("Both SSL and StartTLS cannot be enabled simultaneously");
100 } else {
101 if (isSTARTTLS()) {
102 props.setProperty("mail.smtp.auth", "true");
103 props.put("mail.smtp.starttls.enable", "true");
104 }
105 if (isSSL()) {
106 String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
107 props.put("mail.smtp.socketFactory.port", Integer.toString(smtpPort));
108 props.put("mail.smtp.socketFactory.class", SSL_FACTORY);
109 props.put("mail.smtp.socketFactory.fallback", "true");
110 }
111 }
112
113
114
115 Session session = Session.getInstance(props, loginAuthenticator);
116 mimeMsg = new MimeMessage(session);
117
118 try {
119 if (from != null) {
120 mimeMsg.setFrom(getAddress(from));
121 } else {
122 mimeMsg.setFrom();
123 }
124
125 mimeMsg.setRecipients(Message.RecipientType.TO, parseAddress(to));
126
127 subjectLayout = makeSubjectLayout(subjectStr);
128
129 started = true;
130
131 } catch (MessagingException e) {
132 addError("Could not activate SMTPAppender options.", e);
133 }
134 }
135
136
137
138
139
140 protected void append(E eventObject) {
141
142 if (!checkEntryConditions()) {
143 return;
144 }
145
146 subAppend(eventObject);
147
148 try {
149 if (eventEvaluator.evaluate(eventObject)) {
150 sendBuffer(eventObject);
151 }
152 } catch (EvaluationException ex) {
153 addError("SMTPAppender's EventEvaluator threw an Exception" + ex);
154 }
155 }
156
157 abstract protected void subAppend(E eventObject);
158
159
160
161
162
163
164
165
166 public boolean checkEntryConditions() {
167 if (!this.started) {
168 addError("Attempting to append to a non-started appender: "
169 + this.getName());
170 return false;
171 }
172
173 if (this.mimeMsg == null) {
174 addError("Message object not configured.");
175 return false;
176 }
177
178 if (this.eventEvaluator == null) {
179 addError("No EventEvaluator is set for appender [" + name + "].");
180 return false;
181 }
182
183 if (this.layout == null) {
184 addError("No layout set for appender named ["
185 + name
186 + "]. For more information, please visit http://logback.qos.ch/codes.html#smtp_no_layout");
187 return false;
188 }
189 return true;
190 }
191
192 synchronized public void stop() {
193 this.started = false;
194 }
195
196 InternetAddress getAddress(String addressStr) {
197 try {
198 return new InternetAddress(addressStr);
199 } catch (AddressException e) {
200 addError("Could not parse address [" + addressStr + "].", e);
201 return null;
202 }
203 }
204
205 InternetAddress[] parseAddress(List<String> addressList) {
206
207 InternetAddress[] iaArray = new InternetAddress[addressList.size()];
208
209 for (int i = 0; i < addressList.size(); i++) {
210 try {
211 InternetAddress[] tmp = InternetAddress.parse(addressList.get(i), true);
212
213 iaArray[i] = tmp[0];
214 } catch (AddressException e) {
215 addError("Could not parse address [" + addressList.get(i) + "].", e);
216 return null;
217 }
218 }
219
220 return iaArray;
221 }
222
223
224
225
226 public List<String> getTo() {
227 return to;
228 }
229
230
231
232
233 protected void sendBuffer(E lastEventObject) {
234
235
236
237 try {
238 MimeBodyPart part = new MimeBodyPart();
239
240 StringBuffer sbuf = new StringBuffer();
241
242 String header = layout.getFileHeader();
243 if (header != null) {
244 sbuf.append(header);
245 }
246 String presentationHeader = layout.getPresentationHeader();
247 if (presentationHeader != null) {
248 sbuf.append(presentationHeader);
249 }
250 fillBuffer(sbuf);
251 String presentationFooter = layout.getPresentationFooter();
252 if (presentationFooter != null) {
253 sbuf.append(presentationFooter);
254 }
255 String footer = layout.getFileFooter();
256 if (footer != null) {
257 sbuf.append(footer);
258 }
259
260 if (subjectLayout != null) {
261 mimeMsg.setSubject(subjectLayout.doLayout(lastEventObject),
262 charsetEncoding);
263 }
264
265 String contentType = layout.getContentType();
266
267 if (ContentTypeUtil.isTextual(contentType)) {
268 part.setText(sbuf.toString(), charsetEncoding, ContentTypeUtil
269 .getSubType(contentType));
270 } else {
271 part.setContent(sbuf.toString(), layout.getContentType());
272 }
273
274 Multipart mp = new MimeMultipart();
275 mp.addBodyPart(part);
276 mimeMsg.setContent(mp);
277
278 mimeMsg.setSentDate(new Date());
279 Transport.send(mimeMsg);
280 } catch (Exception e) {
281 addError("Error occured while sending e-mail notification.", e);
282 }
283 }
284
285 abstract protected void fillBuffer(StringBuffer sbuf);
286
287
288
289
290 public String getFrom() {
291 return from;
292 }
293
294
295
296
297 public String getSubject() {
298 return subjectStr;
299 }
300
301
302
303
304
305 public void setFrom(String from) {
306 this.from = from;
307 }
308
309
310
311
312
313 public void setSubject(String subject) {
314 this.subjectStr = subject;
315 }
316
317
318
319
320
321 public void setSMTPHost(String smtpHost) {
322 this.smtpHost = smtpHost;
323 }
324
325
326
327
328 public String getSMTPHost() {
329 return smtpHost;
330 }
331
332
333
334
335
336
337 public void setSMTPPort(int port) {
338 this.smtpPort = port;
339 }
340
341
342
343
344
345 public int getSMTPPort() {
346 return smtpPort;
347 }
348
349
350
351
352
353 public void addTo(String to) {
354 this.to.add(to);
355 }
356
357
358 public Message getMessage() {
359 return mimeMsg;
360 }
361
362
363 public void setMessage(MimeMessage msg) {
364 this.mimeMsg = msg;
365 }
366
367 public boolean isSTARTTLS() {
368 return starttls;
369 }
370
371 public void setSTARTTLS(boolean startTLS) {
372 this.starttls = startTLS;
373 }
374
375 public boolean isSSL() {
376 return ssl;
377 }
378
379 public void setSSL(boolean ssl) {
380 this.ssl = ssl;
381 }
382
383
384
385
386
387
388
389 public void setEvaluator(EventEvaluator<E> eventEvaluator) {
390 this.eventEvaluator = eventEvaluator;
391 }
392
393 public String getUsername() {
394 return username;
395 }
396
397 public void setUsername(String username) {
398 this.username = username;
399 }
400
401 public String getPassword() {
402 return password;
403 }
404
405 public void setPassword(String password) {
406 this.password = password;
407 }
408
409
410
411
412
413 String getCharsetEncoding() {
414 return charsetEncoding;
415 }
416
417
418
419
420
421
422
423 void setCharsetEncoding(String charsetEncoding) {
424 this.charsetEncoding = charsetEncoding;
425 }
426
427 }