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