1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.util.mail;
16  
17  import com.liferay.mail.service.MailServiceUtil;
18  import com.liferay.portal.kernel.exception.SystemException;
19  import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayInputStream;
20  import com.liferay.portal.kernel.log.Log;
21  import com.liferay.portal.kernel.log.LogFactoryUtil;
22  import com.liferay.portal.kernel.mail.Account;
23  import com.liferay.portal.kernel.mail.MailMessage;
24  import com.liferay.portal.kernel.mail.SMTPAccount;
25  import com.liferay.portal.kernel.util.GetterUtil;
26  import com.liferay.portal.kernel.util.InfrastructureUtil;
27  import com.liferay.portal.kernel.util.Validator;
28  
29  import java.io.File;
30  
31  import java.net.SocketException;
32  
33  import java.util.Arrays;
34  import java.util.Date;
35  import java.util.Properties;
36  
37  import javax.activation.DataHandler;
38  import javax.activation.DataSource;
39  import javax.activation.FileDataSource;
40  
41  import javax.mail.Message;
42  import javax.mail.MessagingException;
43  import javax.mail.Part;
44  import javax.mail.SendFailedException;
45  import javax.mail.Session;
46  import javax.mail.Transport;
47  import javax.mail.internet.AddressException;
48  import javax.mail.internet.InternetAddress;
49  import javax.mail.internet.MimeBodyPart;
50  import javax.mail.internet.MimeMessage;
51  import javax.mail.internet.MimeMultipart;
52  
53  import org.apache.commons.lang.time.StopWatch;
54  
55  /**
56   * <a href="MailEngine.java.html"><b><i>View Source</i></b></a>
57   *
58   * @author Brian Wing Shun Chan
59   * @author Brian Myunghun Kim
60   * @author Jorge Ferrer
61   * @author Neil Griffin
62   * @author Thiago Moreira
63   * @author Brett Swaim
64   */
65  public class MailEngine {
66  
67      public static Session getSession() {
68          return getSession(false);
69      }
70  
71      public static Session getSession(boolean cache) {
72          Session session = null;
73  
74          try {
75              session = MailServiceUtil.getSession();
76          }
77          catch (SystemException se) {
78              if (_log.isWarnEnabled()) {
79                  _log.warn(se, se);
80              }
81  
82              session = InfrastructureUtil.getMailSession();
83          }
84  
85          if (_log.isDebugEnabled()) {
86              session.setDebug(true);
87  
88              session.getProperties().list(System.out);
89          }
90  
91          return session;
92      }
93  
94      public static Session getSession(Account account) {
95          Properties properties = _getProperties(account);
96  
97          Session session = Session.getInstance(properties);
98  
99          if (_log.isDebugEnabled()) {
100             session.setDebug(true);
101 
102             session.getProperties().list(System.out);
103         }
104 
105         return session;
106     }
107 
108     public static void send(MailMessage mailMessage)
109         throws MailEngineException {
110 
111         send(
112             mailMessage.getFrom(), mailMessage.getTo(), mailMessage.getCC(),
113             mailMessage.getBCC(), mailMessage.getBulkAddresses(),
114             mailMessage.getSubject(), mailMessage.getBody(),
115             mailMessage.isHTMLFormat(), mailMessage.getReplyTo(),
116             mailMessage.getMessageId(), mailMessage.getInReplyTo(),
117             mailMessage.getAttachments(), mailMessage.getSMTPAccount());
118     }
119 
120     public static void send(String from, String to, String subject, String body)
121         throws MailEngineException {
122 
123         try {
124             send(
125                 new InternetAddress(from), new InternetAddress(to), subject,
126                 body);
127         }
128         catch (AddressException ae) {
129             throw new MailEngineException(ae);
130         }
131     }
132 
133     public static void send(
134             InternetAddress from, InternetAddress to,
135             String subject, String body)
136         throws MailEngineException {
137 
138         send(
139             from, new InternetAddress[] {to}, null, null, subject, body, false,
140             null, null, null);
141     }
142 
143     public static void send(
144             InternetAddress from, InternetAddress to, String subject,
145             String body, boolean htmlFormat)
146         throws MailEngineException {
147 
148         send(
149             from, new InternetAddress[] {to}, null, null, subject, body,
150             htmlFormat, null, null, null);
151     }
152 
153     public static void send(
154             InternetAddress from, InternetAddress[] to, String subject,
155             String body)
156         throws MailEngineException {
157 
158         send(from, to, null, null, subject, body, false, null, null, null);
159     }
160 
161     public static void send(
162             InternetAddress from, InternetAddress[] to, String subject,
163             String body, boolean htmlFormat)
164         throws MailEngineException {
165 
166         send(from, to, null, null, subject, body, htmlFormat, null, null, null);
167     }
168 
169     public static void send(
170             InternetAddress from, InternetAddress[] to, InternetAddress[] cc,
171             String subject, String body)
172         throws MailEngineException {
173 
174         send(from, to, cc, null, subject, body, false, null, null, null);
175     }
176 
177     public static void send(
178             InternetAddress from, InternetAddress[] to, InternetAddress[] cc,
179             String subject, String body, boolean htmlFormat)
180         throws MailEngineException {
181 
182         send(from, to, cc, null, subject, body, htmlFormat, null, null, null);
183     }
184 
185     public static void send(
186             InternetAddress from, InternetAddress[] to, InternetAddress[] cc,
187             InternetAddress[] bcc, String subject, String body)
188         throws MailEngineException {
189 
190         send(from, to, cc, bcc, subject, body, false, null, null, null);
191     }
192 
193     public static void send(
194             InternetAddress from, InternetAddress[] to, InternetAddress[] cc,
195             InternetAddress[] bcc, String subject, String body,
196             boolean htmlFormat, InternetAddress[] replyTo, String messageId,
197             String inReplyTo)
198         throws MailEngineException {
199 
200         send(
201             from, to, cc, bcc, null, subject, body, htmlFormat, replyTo,
202             messageId, inReplyTo, null);
203     }
204 
205     public static void send(
206             InternetAddress from, InternetAddress[] to, InternetAddress[] cc,
207             InternetAddress[] bcc, InternetAddress[] bulkAddresses,
208             String subject, String body, boolean htmlFormat,
209             InternetAddress[] replyTo, String messageId, String inReplyTo)
210         throws MailEngineException {
211 
212         send(
213             from, to, cc, bcc, bulkAddresses, subject, body, htmlFormat,
214             replyTo, messageId, inReplyTo, null);
215     }
216 
217     public static void send(
218             InternetAddress from, InternetAddress[] to, InternetAddress[] cc,
219             InternetAddress[] bcc, InternetAddress[] bulkAddresses,
220             String subject, String body, boolean htmlFormat,
221             InternetAddress[] replyTo, String messageId, String inReplyTo,
222             File[] attachments)
223         throws MailEngineException {
224 
225         send(
226             from, to, cc, bcc, bulkAddresses, subject, body, htmlFormat,
227             replyTo, messageId, inReplyTo, attachments, null);
228     }
229 
230     public static void send(
231             InternetAddress from, InternetAddress[] to, InternetAddress[] cc,
232             InternetAddress[] bcc, InternetAddress[] bulkAddresses,
233             String subject, String body, boolean htmlFormat,
234             InternetAddress[] replyTo, String messageId, String inReplyTo,
235             File[] attachments, SMTPAccount smtpAccount)
236         throws MailEngineException {
237 
238         StopWatch stopWatch = null;
239 
240         if (_log.isDebugEnabled()) {
241             stopWatch = new StopWatch();
242 
243             stopWatch.start();
244 
245             _log.debug("From: " + from);
246             _log.debug("To: " + Arrays.toString(to));
247             _log.debug("CC: " + Arrays.toString(cc));
248             _log.debug("BCC: " + Arrays.toString(bcc));
249             _log.debug("List Addresses: " + Arrays.toString(bulkAddresses));
250             _log.debug("Subject: " + subject);
251             _log.debug("Body: " + body);
252             _log.debug("HTML Format: " + htmlFormat);
253             _log.debug("Reply to: " + Arrays.toString(replyTo));
254             _log.debug("Message ID: " + messageId);
255             _log.debug("In Reply To: " + inReplyTo);
256 
257             if (attachments != null) {
258                 for (int i = 0; i < attachments.length; i++) {
259                     File attachment = attachments[i];
260 
261                     if (attachment != null) {
262                         String path = attachment.getAbsolutePath();
263 
264                         _log.debug("Attachment #" + (i + 1) + ": " + path);
265                     }
266                 }
267             }
268         }
269 
270         try {
271             Session session = null;
272 
273             if (smtpAccount == null) {
274                 session = getSession();
275             }
276             else {
277                 session = getSession(smtpAccount);
278             }
279 
280             Message msg = new LiferayMimeMessage(session);
281 
282             msg.setFrom(from);
283             msg.setRecipients(Message.RecipientType.TO, to);
284 
285             if (cc != null) {
286                 msg.setRecipients(Message.RecipientType.CC, cc);
287             }
288 
289             if (bcc != null) {
290                 msg.setRecipients(Message.RecipientType.BCC, bcc);
291             }
292 
293             msg.setSubject(subject);
294 
295             if ((attachments != null) && (attachments.length > 0)) {
296                 MimeMultipart rootMultipart = new MimeMultipart(
297                     _MULTIPART_TYPE_MIXED);
298 
299                 MimeMultipart messageMultipart = new MimeMultipart(
300                     _MULTIPART_TYPE_ALTERNATIVE);
301 
302                 MimeBodyPart messageBodyPart = new MimeBodyPart();
303 
304                 messageBodyPart.setContent(messageMultipart);
305 
306                 rootMultipart.addBodyPart(messageBodyPart);
307 
308                 if (htmlFormat) {
309                     MimeBodyPart bodyPart = new MimeBodyPart();
310 
311                     bodyPart.setContent(body, _TEXT_HTML);
312 
313                     messageMultipart.addBodyPart(bodyPart);
314                 }
315                 else {
316                     MimeBodyPart bodyPart = new MimeBodyPart();
317 
318                     bodyPart.setText(body);
319 
320                     messageMultipart.addBodyPart(bodyPart);
321                 }
322 
323                 for (int i = 0; i < attachments.length; i++) {
324                     File attachment = attachments[i];
325 
326                     if (attachment != null) {
327                         MimeBodyPart bodyPart = new MimeBodyPart();
328 
329                         DataSource source = new FileDataSource(attachment);
330 
331                         bodyPart.setDisposition(Part.ATTACHMENT);
332                         bodyPart.setDataHandler(new DataHandler(source));
333                         bodyPart.setFileName(attachment.getName());
334 
335                         rootMultipart.addBodyPart(bodyPart);
336                     }
337                 }
338 
339                 msg.setContent(rootMultipart);
340 
341                 msg.saveChanges();
342             }
343             else {
344                 if (htmlFormat) {
345                     msg.setContent(body, _TEXT_HTML);
346                 }
347                 else {
348                     msg.setContent(body, _TEXT_PLAIN);
349                 }
350             }
351 
352             msg.setSentDate(new Date());
353 
354             if (replyTo != null) {
355                 msg.setReplyTo(replyTo);
356             }
357 
358             if (messageId != null) {
359                 msg.setHeader("Message-ID", messageId);
360             }
361 
362             if (inReplyTo != null) {
363                 msg.setHeader("In-Reply-To", inReplyTo);
364                 msg.setHeader("References", inReplyTo);
365             }
366 
367             _send(session, msg, bulkAddresses);
368         }
369         catch (SendFailedException sfe) {
370             _log.error(sfe);
371         }
372         catch (Exception e) {
373             throw new MailEngineException(e);
374         }
375 
376         if (_log.isDebugEnabled()) {
377             _log.debug("Sending mail takes " + stopWatch.getTime() + " ms");
378         }
379     }
380 
381     public static void send(byte[] msgByteArray) throws MailEngineException {
382         try {
383             Session session = getSession();
384 
385             Message msg = new MimeMessage(
386                 session, new UnsyncByteArrayInputStream(msgByteArray));
387 
388             _send(session, msg, null);
389         }
390         catch (Exception e) {
391             throw new MailEngineException(e);
392         }
393     }
394 
395     private static Properties _getProperties(Account account) {
396         Properties properties = new Properties();
397 
398         String protocol = account.getProtocol();
399 
400         properties.setProperty("mail.transport.protocol", protocol);
401         properties.setProperty("mail." + protocol + ".host", account.getHost());
402         properties.setProperty(
403             "mail." + protocol + ".port", String.valueOf(account.getPort()));
404 
405         if (account.isRequiresAuthentication()) {
406             properties.setProperty("mail." + protocol + ".auth", "true");
407             properties.setProperty(
408                 "mail." + protocol + ".user", account.getUser());
409             properties.setProperty(
410                 "mail." + protocol + ".password", account.getPassword());
411         }
412 
413         if (account.isSecure()) {
414             properties.setProperty(
415                 "mail." + protocol + ".socketFactory.class",
416                 "javax.net.ssl.SSLSocketFactory");
417             properties.setProperty(
418                 "mail." + protocol + ".socketFactory.fallback", "false");
419             properties.setProperty(
420                 "mail." + protocol + ".socketFactory.port",
421                 String.valueOf(account.getPort()));
422         }
423 
424         return properties;
425     }
426 
427     private static String _getSMTPProperty(Session session, String suffix) {
428         String protocol = GetterUtil.getString(
429             session.getProperty("mail.transport.protocol"));
430 
431         if (protocol.equals(Account.PROTOCOL_SMTPS)) {
432             return session.getProperty("mail.smtps." + suffix);
433         }
434         else {
435             return session.getProperty("mail.smtp." + suffix);
436         }
437     }
438 
439     private static void _send(
440         Session session, Message msg, InternetAddress[] bulkAddresses) {
441 
442         try {
443             boolean smtpAuth = GetterUtil.getBoolean(
444                 _getSMTPProperty(session, "auth"), false);
445             String smtpHost = _getSMTPProperty(session, "host");
446             int smtpPort = GetterUtil.getInteger(
447                 _getSMTPProperty(session, "port"), Account.PORT_SMTP);
448             String user = _getSMTPProperty(session, "user");
449             String password = _getSMTPProperty(session, "password");
450 
451             if (smtpAuth && Validator.isNotNull(user) &&
452                 Validator.isNotNull(password)) {
453 
454                 String protocol = GetterUtil.getString(
455                     session.getProperty("mail.transport.protocol"),
456                     Account.PROTOCOL_SMTP);
457 
458                 Transport transport = session.getTransport(protocol);
459 
460                 transport.connect(smtpHost, smtpPort, user, password);
461 
462                 if ((bulkAddresses != null) && (bulkAddresses.length > 0)) {
463                     transport.sendMessage(msg, bulkAddresses);
464                 }
465                 else {
466                     transport.sendMessage(msg, msg.getAllRecipients());
467                 }
468 
469                 transport.close();
470             }
471             else {
472                 if ((bulkAddresses != null) && (bulkAddresses.length > 0)) {
473                     Transport.send(msg, bulkAddresses);
474                 }
475                 else {
476                     Transport.send(msg);
477                 }
478             }
479         }
480         catch (MessagingException me) {
481             if (me.getNextException() instanceof SocketException) {
482                 if (_log.isWarnEnabled()) {
483                     _log.warn(
484                         "Failed to connect to a valid mail server. Please " +
485                             "make sure one is properly configured. " +
486                                 me.getMessage());
487                 }
488             }
489         }
490     }
491 
492     private static final String _MULTIPART_TYPE_ALTERNATIVE = "alternative";
493 
494     private static final String _MULTIPART_TYPE_MIXED = "mixed";
495 
496     private static final String _TEXT_HTML = "text/html;charset=\"UTF-8\"";
497 
498     private static final String _TEXT_PLAIN = "text/plain;charset=\"UTF-8\"";
499 
500     private static Log _log = LogFactoryUtil.getLog(MailEngine.class);
501 
502 }